keras_猫狗分类案例(三)_卷积神经网络的可视化
参考:
https://blog.csdn.net/Einstellung/article/details/82832872
卷积神经网络的可视化
参考:
1、可视化卷积神经网络的中间输出(中间激活):有助于理解卷积神经网络连续的层如何
对输入进行变换,也有助于初步了解卷积神经网络每个过滤器的含义。
代码清单 5-25 预处理单张图像
代码清单 5-26 显示测试图像
代码清单 5-27 用一个输入张量和一个输出张量列表将模型实例化
代码清单 5-28 以预测模式运行模型
代码清单 5-29 将第 4 个通道可视化
代码清单 5-30 将第 7 个通道可视化
代码清单 5-31 将每个中间激活的所有通道可视化
我们刚刚揭示了深度神经网络学到的表示的一个重要普遍特征:随着层数的加深,层所提取的特征变得越来越抽象。更高的层激活包含关于特定输入的信息越来越少,而关于目标的信息越来越多(本例中即图像的类别:猫或狗)。深度神经网络可以有效地作为****信息蒸馏管道(**information distillation pipeline)**,输入原始数据(本例中是 RGB 图像),反复对其进行变换,将无关信息过滤掉(比如图像的具体外观),并放大和细化有用的信息(比如图像的类别)。
这与人类和动物感知世界的方式类似:人类观察一个场景几秒钟后,可以记住其中有哪些抽象物体(比如自行车、树),但记不住这些物体的具体外观。事实上,如果你试着凭记忆画一辆普通自行车,那么很可能完全画不出真实的样子,虽然你一生中见过上千辆自行车(见图 5-28)。你可以现在就试着画一下,这个说法绝对是真实的。你的大脑已经学会将视觉输入完全抽象化,即将其转换为更高层次的视觉概念,同时过滤掉不相关的视觉细节,这使得大脑很难记住周围事物的外观。
1、可视化卷积神经网络的中间输出(中间激活
)
对于第一种方法(即激活的可视化),我们将使用 5.2 节在猫狗分类问题上从头开始训练的
import keras
keras.__version__
# 可视化中间激活
# 可视化中间激活,是指对于给定输入,展示网络中各个卷积层和池化层输出的特征图(层
# 的输出通常被称为该层的激活,即激活函数的输出)。这让我们可以看到输入如何被分解为网络
# 学到的不同过滤器。我们希望在三个维度对特征图进行可视化:宽度、高度和深度(通道)。每
# 个通道都对应相对独立的特征,所以将这些特征图可视化的正确方法是将每个通道的内容分别
# 绘制成二维图像。我们首先来加载 5.2 节保存的模型。
from keras.models import load_model
model = load_model('cats_and_dogs_small_2.h5')
model.summary() # As a reminder.
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_5 (Conv2D) (None, 148, 148, 32) 896
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 (None, 74, 74, 32) 0
_________________________________________________________________
conv2d_6 (Conv2D) (None, 72, 72, 64) 18496
_________________________________________________________________
max_pooling2d_6 (MaxPooling2 (None, 36, 36, 64) 0
_________________________________________________________________
conv2d_7 (Conv2D) (None, 34, 34, 128) 73856
_________________________________________________________________
# 接下来,我们需要一张输入图像,即一张猫的图像,它不属于网络的训练图像。
# 代码清单 5-25 预处理单张图像
img_path = '/Users/fchollet/Downloads/cats_and_dogs_small/test/cats/cat.1700.jpg'
# We preprocess the image into a 4D tensor
from 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)
# Remember that the model was trained on inputs
# that were preprocessed in the following way:
# 请记住,训练模型的输入数据都用这种方法预处理
img_tensor /= 255.
# Its shape is (1, 150, 150, 3)
print(img_tensor.shape)
(1, 150, 150, 3)
Let's display our picture:
# 代码清单 5-26 显示测试图像
import matplotlib.pyplot as plt
plt.imshow(img_tensor[0])
plt.show()
# 为了提取想要查看的特征图,我们需要创建一个 Keras 模型,以图像批量作为输入,并输出
# 所有卷积层和池化层的激活。为此,我们需要使用 Keras 的 Model 类。模型实例化需要两个参
# 数:一个输入张量(或输入张量的列表)和一个输出张量(或输出张量的列表)。得到的类是一个
# Keras 模型,就像你熟悉的 Sequential 模型一样,将特定输入映射为特定输出。 Model 类允许
# 模型有多个输出,这一点与 Sequential 模型不同。想了解 Model 类的更多信息
# 代码清单 5-27 用一个输入张量和一个输出张量列表将模型实例化
from keras import models
# Extracts the outputs of the top 8 layers:
# 提取前 8 层的输出
# 创建一个模型,给定模型输入,可以返回这些输出
layer_outputs = [layer.output for layer in model.layers[:8]]
# Creates a model that will return these outputs, given the model input:
activation_model = models.Model(inputs=model.input, outputs=layer_outputs)
When fed an image input, this model returns the values of the layer activations in the original model. This is the first time you encounter a multi-output model in this book: until now the models you have seen only had exactly one input and one output. In the general case, a model could have any number of inputs and outputs. This one has one input and 8 outputs, one output per layer activation.
# 输入一张图像,这个模型将返回原始模型前 8 层的激活值。这是你在本书中第一次遇到的
# 多输出模型,之前的模型都是只有一个输入和一个输出。一般情况下,模型可以有任意个输入
# 和输出。这个模型有一个输入和 8 个输出,即每层激活对应一个输出。
# 代码清单 5-28 以预测模式运行模型
# This will return a list of 5 Numpy arrays:
# one array per layer activation
activations = activation_model.predict(img_tensor)
For instance, this is the activation of the first convolution layer for our cat image input:
# 例如,对于输入的猫图像,第一个卷积层的激活如下所示。
first_layer_activation = activations[0]
print(first_layer_activation.shape)
(1, 148, 148, 32)
It's a 148x148 feature map with 32 channels. Let's try visualizing the 3rd channel:
# 它是大小为 148×148 的特征图,有 32 个通道。我们来绘制原始模型第一层激活的第 4 个
# 通道(见图 5-25)。
# 代码清单 5-29 将第 3 个通道可视化
import matplotlib.pyplot as plt
plt.matshow(first_layer_activation[0, :, :, 3], cmap='viridis')
plt.show()
# 这个通道似乎是对角边缘检测器。我们再看一下第 7 个通道(见图 5-26)。但请注意,你的
# 通道可能与此不同,因为卷积层学到的过滤器并不是确定的。
# 提取前 8 层的输出
# 创建一个模型,给定模型输入,
# 可以返回这些输出
# 返回 8个 Numpy数组组成的列表,
# 每个层激活对应一个 Numpy 数组134 第 5 章 深度学习用于计算机视觉
# 代码清单 5-30 将第 30个通道可视化
plt.matshow(first_layer_activation[0, :, :, 30], cmap='viridis')
plt.show()
# 这个通道看起来像是“鲜绿色圆点”检测器,对寻找猫眼睛很有用。下面我们来绘制网络
# 中所有激活的完整可视化(见图 5-27)。我们需要在 8 个特征图中的每一个中提取并绘制每一个
# 通道,然后将结果叠加在一个大的图像张量中,按通道并排。
# 代码清单 5-31 将每个中间激活的所有通道可视化
# l
import keras
# These are the names of the layers, so can have them as part of our plot
# 层的名称,这样你可以将这些名称画到图中
layer_names = []
for layer in model.layers[:8]:
layer_names.append(layer.name)
images_per_row = 16
# Now let's display our feature maps
for layer_name, layer_activation in zip(layer_names, activations):
# This is the number of features in the feature map
n_features = layer_activation.shape[-1]
# The feature map has shape (1, size, size, n_features)
# 特征图的形状为 (1, size, size, n_features)
size = layer_activation.shape[1]
# We will tile the activation channels in this matrix
# 在这个矩阵中将激活通道平铺
n_cols = n_features // images_per_row
display_grid = np.zeros((size * n_cols, images_per_row * size))
# We'll tile each filter into this big horizontal grid
# 将每个过滤器平铺到一个大的水平网格中
for col in range(n_cols):
for row in range(images_per_row):
channel_image = layer_activation[0,
:, :,
col * images_per_row + row]
# Post-process the feature to make it visually palatable
# 对特征进行后处理,使其看起来更美观
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
# Display the grid
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')
plt.show()
# 这里需要注意以下几点。
# • 第一层是各种边缘探测器的集合。在这一阶段,激活几乎保留了原始图像中的所有信息。
# • 随着层数的加深,激活变得越来越抽象,并且越来越难以直观地理解。它们开始表示更
# 高层次的概念,比如“猫耳朵”和“猫眼睛”。层数越深,其表示中关于图像视觉内容
# 的信息就越少,而关于类别的信息就越多。
# • 激活的稀疏度(sparsity)随着层数的加深而增大。在第一层里,所有过滤器都被输入图
# 像激活,但在后面的层里,越来越多的过滤器是空白的。也就是说,输入图像中找不到
# 这些过滤器所编码的模式。
# 我们刚刚揭示了深度神经网络学到的表示的一个重要普遍特征:随着层数的加深,层所
# 提取的特征变得越来越抽象。更高的层激活包含关于特定输入的信息越来越少,而关于目标的
# 信息越来越多(本例中即图像的类别:猫或狗)。深度神经网络可以有效地作为信息蒸馏管道
# (information distillation pipeline),输入原始数据(本例中是 RGB 图像),反复对其进行变换,
# 将无关信息过滤掉(比如图像的具体外观),并放大和细化有用的信息(比如图像的类别)。