卷积神经网络学到的表示非常适合可视化,很大程度上是因为它们是 视 觉 概 念 的 表 示 \color{red}视觉概念的表示 视觉概念的表示。接下来介绍3种可视化方法。
from tensorflow.keras.models import load_model model = load_model('cats_and_dogs_small_1.h5') model.summary() # 作为提醒
img_path = 'C:\\Users\\Administrator\\deep-learning-with-python-notebooks-master\\cats_and_dogs_small\\test\\cats\\cat.3700.jpg' from tensorflow.keras.preprocessing import image import numpy as np 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) img_tensor /= 255. # 其形状为 (1, 150, 150, 3) print(img_tensor.shape)显示测试图像
import matplotlib.pyplot as plt plt.imshow(img_tensor[0]) plt.show()
Keras
的Model
类。
- 使用
Keras
的Model
类。为了提取想要查看的特征图,我们需要创建一个Keras
模型并使用Model
类,以图像批量作为输入,并输出所有卷积层和池化层的激活。Model
类允许模型有多个输出,这一点与Sequential
模型不同。模型实例化需要两个参数:一个输入张量(或输入张量的列表)和一个输出张量(或输出张量的列表)。
from tensorflow.keras import models layer_outputs = [layer.output for layer in model.layers[:8]] # 提取前 8 层的输出 # 创建一个模型,给定模型输入,可以返回这些输出 activation_model = models.Model(inputs=model.input, outputs=layer_outputs)
# 返回8个Numpy数组组成的列表,每个层激活对应一个 Numpy 数组 activations = activation_model.predict(img_tensor)
>>>first_layer_activation = activations[0] >>>print(first_layer_activation.shape) (1, 148, 148, 32)可知其大小为 148×148 的特征图,有 32 个通道。
import matplotlib.pyplot as plt plt.matshow(first_layer_activation[0, :, :, 4], cmap='viridis')
# 层的名称,这样你可以将这些名称画到图中 layer_names = [] for layer in model.layers[:8]: layer_names.append(layer.name) images_per_row = 16 # 显示特征图 for layer_name, layer_activation in zip(layer_names, activations): n_features = layer_activation.shape[-1] # 特征图中的特征个数 size = layer_activation.shape[1] # 特征图的形状为 (1, size, size, n_features) 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 scale = 1. / size plt.figure(figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])) plt.title(layer_name) plt.grid(False) plt.imshow(display_grid, aspect='auto', cmap='viridis')
随着层数的加深,层所提取的特征变得越来越抽象。更高的层激活包含关于特定输入的信息越来越少,而关于目标的信息越来越多(本例中即图像的类别:猫或狗)。这个跟人类的认知场景很相似,我们认识一个东西也是这样开始的。
深度神经网络可以有效地作为 信 息 蒸 馏 管 道 \color{red}信息蒸馏管道 信息蒸馏管道(information distillation pipeline),输入原始数据(本例中是 RGB 图像),反复对其进行变换,将无关信息过滤掉(比如图像的具体外观), 并 放 大 和 细 化 有 用 的 信 息 \color{red}并放大和细化有用的信息 并放大和细化有用的信息(比如图像的类别)。