赞
踩
可视化卷积神经网络的过滤器
想要观察卷积神经网络学到的过滤器,另一种简单的方法是显示每个过滤器所响应的视觉模式。这可以通过在输入空间中进行梯度上升来实现:从空白输入图像开始,将梯度下降应用于卷积神经网络输入图像的值,其目的是让某个过滤器的响应最大化。得到的输入图像是选定过滤器具有最大响应的图像。
我们需要构建一个损失函数,其目的是让某个卷积层的某个过滤器的值最大化;然后,我们要使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化。例如,对于在ImageNet上预训练的VGG16网络,其block3_conv1层第0个过滤器激活的损失如下所示
为过滤器的可视化定义损失张量
from keras.applications import VGG16
from keras import backend as K
model = VGG16(weights='imagenet',
include_top=False)
layer_name = 'block3_conv1'
filter_index = 0
layer_output = model.get_layer(layer_name).output
loss = K.mean(layer_output[:, :, :, filter_index])
获取损失相对于输入的梯度
grads = K.gradients(loss, model.input)[0]
调用 gradients 返回的是一个张量列表(本例中列表长度为1)。因此,只保留第一个元素,它是一个张量
为了让梯度下降过程顺利进行,一个非显而易见的技巧是将梯度张量除以其 L2 范数(张量中所有值的平方的平均值的平方根)来标准化。这就确保了输入图像的更新大小始终位于相同的范围。
梯度标准化技巧
grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
做除法前加上 1e–5,以防不小心除以 0
现在你需要一种方法:给定输入图像,它能够计算损失张量和梯度张量的值。你可以定义一个 Keras 后端函数来实现此方法:iterate 是一个函数,它将一个 Numpy 张量(表示为长度为 1 的张量列表)转换为两个 Numpy 张量组成的列表,这两个张量分别是损失值和梯度值。
给定 Numpy 输入值,得到 Numpy 输出值
iterate = K.function([model.input], [loss, grads])
import numpy as np
loss_value, grads_value = iterate([np.zeros((1, 150, 150, 3))])
现在你可以定义一个 Python 循环来进行随机梯度下降。
input_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128.
step = 1. # this is the magnitude of each gradient update
for i in range(40):
loss_value, grads_value = iterate([input_img_data])
input_img_data += grads_value * step
得到的图像张量是形状为 (1, 150, 150, 3) 的浮点数张量,其取值可能不是 [0, 255] 区间内的整数。因此,你需要对这个张量进行后处理,将其转换为可显示的图像。下面这个简单的实用函数可以做到这一点。
将张量转换为有效图像的实用函数
def deprocess_image(x):
# normalize tensor: center on 0., ensure std is 0.1
x -= x.mean()
x /= (x.std() + 1e-5)
x *= 0.1
# clip to [0, 1]
x += 0.5
x = np.clip(x, 0, 1)
# convert to RGB array
x *= 255
x = np.clip(x, 0, 255).astype('uint8')
return x
生成过滤器可视化的函数
def generate_pattern(layer_name, filter_index, size=150): # Build a loss function that maximizes the activation # of the nth filter of the layer considered. layer_output = model.get_layer(layer_name).output loss = K.mean(layer_output[:, :, :, filter_index]) # Compute the gradient of the input picture wrt this loss grads = K.gradients(loss, model.input)[0] # Normalization trick: we normalize the gradient grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5) # This function returns the loss and grads given the input picture iterate = K.function([model.input], [loss, grads]) # We start from a gray image with some noise input_img_data = np.random.random((1, size, size, 3)) * 20 + 128. # Run gradient ascent for 40 steps step = 1. for i in range(40): loss_value, grads_value = iterate([input_img_data]) input_img_data += grads_value * step img = input_img_data[0] return deprocess_image(img)
plt.imshow(generate_pattern('block3_conv1', 0))
生成某一层中所有过滤器响应模式组成的网格
for layer_name in ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1']: size = 64 margin = 5 # This a empty (black) image where we will store our results. results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3)) for i in range(8): # iterate over the rows of our results grid for j in range(8): # iterate over the columns of our results grid # Generate the pattern for filter `i + (j * 8)` in `layer_name` filter_img = generate_pattern(layer_name, i + (j * 8), size=size) # Put the result in the square `(i, j)` of the results grid horizontal_start = i * size + i * margin horizontal_end = horizontal_start + size vertical_start = j * size + j * margin vertical_end = vertical_start + size results[horizontal_start: horizontal_end, vertical_start: vertical_end, :] = filter_img # Display the results grid plt.figure(figsize=(20, 20)) plt.imshow(results) plt.show()
这些过滤器可视化包含卷积神经网络的层如何观察世界的很多信息:卷积神经网络中每一层都学习一组过滤器,以便将其输入表示为过滤器的组合。这类似于傅里叶变换将信号分解为一组余弦函数的过程。随着层数的加深,卷积神经网络中的过滤器变得越来越复杂,越来越精细。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。