Продолжаем говорить о сверточных нейронных сетях (CNN) с использованием Python-фреймворка TensorFlow в рамках задач Computer Vision. Для понимания работы глубоких сверточных сетей может пригодиться визуализация. В этой статье мы расскажем, как посмотреть результаты промежуточных активаций TensorFlow модели с помощью визуализации данных; и узнаем, как сверточные сети фильтруют изображения.
Инициализация модели TensorFlow
Воспользуемся моделью Machine Learning, которая была обучена в Python-фреймворке TensorFlow для распознавании кошек и собак из прошлой статьи. Вот так она выглядит:
>>> model.summary() _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 148, 148, 32) 896 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 74, 74, 32) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 72, 72, 64) 18496 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 36, 36, 64) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 34, 34, 128) 73856 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 17, 17, 128) 0 _________________________________________________________________ conv2d_3 (Conv2D) (None, 15, 15, 128) 147584 _________________________________________________________________ max_pooling2d_3 (MaxPooling2 (None, 7, 7, 128) 0 _________________________________________________________________ dropout (Dropout) (None, 7, 7, 128) 0 _________________________________________________________________ flatten (Flatten) (None, 6272) 0 _________________________________________________________________ dense (Dense) (None, 512) 3211776 _________________________________________________________________ dense_1 (Dense) (None, 1) 513 ================================================================= Total params: 3,453,121 Trainable params: 3,453,121 Non-trainable params: 0
На валидационной выборке эта модель машинного обучения показывала точность около 90%. На основе этой модели покажем результаты функций активации всех фильтров в ответ на входное изображение. Так, для первого сверточного слоя (conv2d) будет 32 результата функции активации, а для второго (conv2d_1) — 64.
Преобразование входного изображения
Изображение нужно получить в виде тензора, а форма тензора должна совпадать с формой входного сигнала.
Первый сверточный слой принимает на вход цветное изображение (150,150). Причём 1-е измерение соответствует размеру пакета, но поскольку мы хотим посмотреть только на одной, то оно должно быть равно 1. Для обработки изображения в Keras есть специальный модуль image
. Так подготовка изображения в Python выглядит следующим образом:
from keras.preprocessing import image import numpy as np img_path = test_cats_dir / 'cat.1016.jpg' img = image.load_img(img_path, target_size=(150, 150)) img_tensor = image.img_to_array(img) img_tensor = np.expand_dims(img_tensor, axis=0) # Изображение нужно приводить к диапазону [0,1] img_tensor /= 255. print(img_tensor.shape) # (1, 150, 150, 3)
Можем взглянуть на это изображение с помощью Python-библиотеки Matplotlib. Именно на этой картинке будем проводить визуализацию промежуточных активаций TensorFlow.
import matplotlib.pyplot as plt plt.imshow(img_tensor[0]) plt.show()
Извлечение карт признаков
Теперь нужно получить результаты активаций от фильтров в каждом сверточном слое. Для этого нам понадобится класс Model, который принимает входной тензор и тензоры слоев. Нам нужны только сверточные слои, т.е. первые 8 слоев. Вот так выглядит получение результатов активации TensorFlow-модели в Python:
from tensorflow.keras import models layer_outputs = [layer.output for layer in model.layers[:8]] activation_model = models.Model(inputs=model.input, outputs=layer_outputs) acts = activation_model.predict(img_tensor)
Мы можем посмотреть на результаты активации в первом сверточном слое нашей нейронной сети. Этот слой содержит 32 фильтра (conv2d). Например, вот так это выглядит для 1-го фильтра:
first_layer_activation = acts[0] plt.matshow(first_layer_activation[0, :, :, 1], cmap='viridis')
Ниже пример Python для визуализация результата функции активации для 30-фильтра. Скорее всего, первый сверточный слой ответственен за контур животных.
plt.matshow(first_layer_activation[0, :, :, 30], cmap='viridis')
Визуализация активаций для всех фильтров
Перебирать по одному фильтру и слою дело затруднительное, поэтому лучшего всего автоматизировать этот процесс. Ниже функция на Python для визуализации результатов активации модели TensorFlow. Мы создаём сетку, содержащую 16 колонок. В каждой ячейке результат активации
images_per_row = 16 for layer_output, layer_activation in zip(layer_outputs, acts): if not layer_output.name.startswith('max'): # Количество фильтров в карте признаков n_features = layer_activation.shape[-1] # Признак имеет форму: (1, высота, ширина, n_features) size = layer_activation.shape[1] # Разместим результаты активации в виде сетки. # На каждой строке будет по images_per_row (16) n_cols = n_features // images_per_row display_grid = np.zeros((size * n_cols, images_per_row * size)) for col in range(n_cols): for row in range(images_per_row): # Фильтр: channel_image = layer_activation[0, :, :, col * images_per_row + row] # Постобработка, чтобы получить приемлимую визуализацию channel_image -= channel_image.mean() channel_image /= channel_image.std() channel_image *= 64 channel_image += 128 channel_image = np.clip(channel_image, 0, 255).astype('uint8') display_grid[col * size : (col + 1) * size, row * size : (row + 1) * size] = channel_image # Визуализация результатов активации модели TensorFlow scale = 1. / size plt.figure(figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])) plt.title(layer_output.name) plt.grid(False) plt.imshow(display_grid, aspect='auto', cmap='viridis') plt.show()
Нажмите, чтобы посмотреть результаты визуалзиации всех слоев.
Итоги визуализации
Можем увидеть, что с переходом к новому слою результат активаций становится более специфичным и абстрактным. Например, последний слой (conv2d_3) для человека уже становится непонятен. Но для нейронной сети это может значить «ухо», «ус», «родинка». Именно так и работают глубокие нейронные сети (Deep Learning) — углубляются и специализируются с увеличением уровня слоя.
К тому же от слоя к слою увеличивается количество пустых фильтров. Это значит, что слой не видит специфичных признаков, которые принадлежат этому изображению. Таким образом, с увеличением глубины ещё и фильтруется входящая информация. Похожим образом работает мозг человека. Например, если его попросить нарисовать кошку, то он отфильтрует все детали, изобразив только специфичные для кошки признаки.
Ещё больше подробностей о работе сверточных нейронных сетей на реальных примерах Data Science с использованием Python-фреймворка TensorFlow, вы узнаете на нашем специализированном курсе «VISI: Computer Vision» в лицензированном учебном центре обучения и повышения квалификации Data Scientist’ов и IT-специалистов в Москве.