https://habr.com/ru/post/438972/Введение
Статья предназначена для тех, кто когда-либо интересовался вопросом о том что же происходит внутри искусственной нейронной сети
(artificial neural network) —
ИНС. Сейчас разработать собственную ИНС может практически каждый используя уже готовые библиотеки, в большинстве языков программирования. В рассматриваемой статье я постараюсь показать как именно выглядит объект (
Паттерн) проходящий через слои ИНС, разработанной и скомпилированной при помощи библиотеки глубокого обучения
Tensorflow с надстройкой
Keras.
Используемое ПО
Необходимы следующие компоненты (версии я указал для своего случая):
- tensorflow 1.10.0
- keras 2.2.4
- matplotlib 2.2.0
- modul-os
- numpy1.14.3
Также есть возможность нарисовать архитектуру сети, но для этого необходимо установить средства визуализации keras и в методе
PLOT_PATTERN_PROCCESS(...)
установить
PLOT_MODEL=True
def PLOT_PATTERN_PROCCESS(model, pattern, FOLDER_TO_SAVE, grid_size=(3, 3), limit_size_layer=(15, 15), PLOT_MODEL=True):
Основная идея
Необходимо выбрать один паттерн (прохождение, которого мы будем наблюдать), затем скомпилированная сеть разбивается на слои
tensor'ов. В цикле от второго до последнего слоя, создается новая сеть где ее выход это номер слоя по циклу и пропуская паттерн, на её выходе получается результат в виде n-мерного массива.
Реализация
Подключение библиотек
from keras.models import *
from keras.layers import *
import matplotlib.pyplot as plt
import os
import numpy as np
Используемые методы:
-
def PLOT_PATTERN_PROCCESS(model, pattern, FOLDER_TO_SAVE, grid_size=(3, 3), limit_size_layer=(15, 15), PLOT_MODEL=True):def PLOT_PATTERN_PROCCESS(model, pattern, FOLDER_TO_SAVE, grid_size=(3, 3), limit_size_layer=(15, 15), PLOT_MODEL=True):
"""
:param model: Модель нейроархитектуры keras
:type model: Sequential
:param pattern: Входной паттерн, массив данных соответвующий размеру входных слоев
:type pattern: np.array
:param FOLDER_TO_SAVE: Папка в которую будет сохраняться результат
:type FOLDER_TO_SAVE: str
:param grid_size: Размер отображаемой сетки слоев
:type grid_size: tuple
:param limit_size_layer: Минимальный размер для отображения слоя
:type limit_size_layer: tuple
:param PLOT_MODEL: Выполнить построение модели
:type PLOT_MODEL: PLOT_MODEL
"""
SAVE_AR_LIST = []
for num_layer in range(1, len(model.layers)):
LO = model.layers[num_layer].output
_model = Model(inputs=model.input, outputs=LO)
if (
len(_model.output_shape) == 3 and
_model.output_shape[1] > limit_size_layer[0] and
_model.output_shape[2] > limit_size_layer[1]
):
_output = _model.predict(pattern)[0]
SAVE_AR_LIST.append(
[
num_layer,
model.layers[num_layer].name,
_output.tolist()
]
)
###
PIC_NUM = 0
while len(SAVE_AR_LIST) > 0:
fig, axs = plt.subplots(nrows=grid_size[0], ncols=grid_size[1], figsize=(10, 10), tight_layout=True)
xmin, xmax = plt.xlim()
ymin, ymax = plt.ylim()
for ax in axs.flat:
[num_layer, layer_name, ar] = SAVE_AR_LIST.pop(0)
ax.imshow(np.array(ar), cmap='viridis', extent=(xmin, xmax, ymin, ymax))
ax.set_title(layer_name + " " + str(np.array(ar).shape))
if len(SAVE_AR_LIST) == 0:
break
# plt.show()
plt.savefig(os.path.join(FOLDER_TO_SAVE, str(PIC_NUM) + '.png'), fmt='png')
plt.close(fig)
PIC_NUM += 1
###
if PLOT_MODEL:
from keras.utils.vis_utils import plot_model
plot_model(
model=model,
to_file=os.path.join(FOLDER_TO_SAVE, model.name + " neural network architecture.png"),
show_shapes=True,
show_layer_names=True
)
###
def build_model(IN_SHAPE=50,CLASSES=5) -> Sequential:def build_model(IN_SHAPE=50,CLASSES=5) -> Sequential:
inputs_LAYER0 = Input(shape=(IN_SHAPE,IN_SHAPE))
Dense_2_2 = Dense(75, activation='relu')(inputs_LAYER0)
Dense_2_3 = Dense(50, activation='relu', name="my_dense")(Dense_2_2)
Dense_2_4 = Dense(25, activation='relu')(Dense_2_3)
Dense_2_5 = Dense(10, activation='relu')(Dense_2_4)
flat_f_0 = Flatten()(Dense_2_5)
final_layer= Dense(CLASSES, activation='softmax')(flat_f_0)
#
model = Model(input=inputs_LAYER0, output=final_layer, name="simple model")
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
return model
Код программы
model_ = build_model()
pattern = np.random.sample((1,50,50))
os.makedirs("PLOT_PATTERN_PROCCESS")
PLOT_PATTERN_PROCCESS(
model = model_,
pattern = pattern,
FOLDER_TO_SAVE = "PLOT_PATTERN_PROCCESS",
PLOT_MODEL=False,
grid_size=(2, 2)
)
Описание работы программы
Метод
build_model()
возвращвет модель ИНС в формате
Sequential, предназначенную для классификации чего-либо в 5 классов.
model.summary()_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) (None, 50, 50) 0
_________________________________________________________________
dense_1 (Dense) (None, 50, 75) 3825
_________________________________________________________________
my_dense (Dense) (None, 50, 50) 3800
_________________________________________________________________
dense_2 (Dense) (None, 50, 25) 1275
_________________________________________________________________
dense_3 (Dense) (None, 50, 10) 260
_________________________________________________________________
flatten_1 (Flatten) (None, 500) 0
_________________________________________________________________
dense_4 (Dense) (None, 5) 2505
=================================================================
Total params: 11,665
Trainable params: 11,665
Non-trainable params: 0
_________________________________________________________________
Как видно из архитектуры паттерн, это массив размером 50х50. Переменная
pattern
и есть наблюдаемый объект.
Далее создается директория
os.makedirs("PLOT_PATTERN_PROCCESS")
куда будет сохранятья весть результат.
Описание метода PLOT_PATTERN_PROCCESS
Смысл метода я описывал выше, но важно сказать что нам не нужны все слои, поскольку выходы некоторых слоёв невозможно отобразить или это будет не информативно.
Получение выходного паттерна происходит тут
_output = _model.predict(pattern)[0]
В данной реализации можно отобразить, двумерный, выходной паттрен размеры которого не менее чем параметр
limit_size_layer
Поочередно перебирая слои модели ИНС переменная
SAVE_AR_LIST
постепенно заполняется данными:
- Номер слоя
num_layer
- Имя слоя
model.layers[num_layer].name
- Выходной двумерный массив
_output.tolist()
Исключая постепенно по одному результату из
SAVE_AR_LIST
и помещая его в ячейку холста
ax.imshow(np.array(ar), cmap='viridis', extent=(xmin, xmax, ymin, ymax))
На выходе создается файл
(0.png)
Рекомендации
Успехов!