当前位置:   article > 正文

十一、卷积神经网络的可视化2_卷积神经网络梯度可视化

卷积神经网络梯度可视化

可视化卷积神经网络的过滤器
想要观察卷积神经网络学到的过滤器,另一种简单的方法是显示每个过滤器所响应的视觉模式。这可以通过在输入空间中进行梯度上升来实现:从空白输入图像开始,将梯度下降应用于卷积神经网络输入图像的值,其目的是让某个过滤器的响应最大化。得到的输入图像是选定过滤器具有最大响应的图像。

我们需要构建一个损失函数,其目的是让某个卷积层的某个过滤器的值最大化;然后,我们要使用随机梯度下降来调节输入图像的值,以便让这个激活值最大化。例如,对于在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])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

获取损失相对于输入的梯度

grads = K.gradients(loss, model.input)[0]
调用 gradients 返回的是一个张量列表(本例中列表长度为1)。因此,只保留第一个元素,它是一个张量
  • 1
  • 2

为了让梯度下降过程顺利进行,一个非显而易见的技巧是将梯度张量除以其 L2 范数(张量中所有值的平方的平均值的平方根)来标准化。这就确保了输入图像的更新大小始终位于相同的范围。
梯度标准化技巧

grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
做除法前加上 1e–5,以防不小心除以 0
  • 1
  • 2

现在你需要一种方法:给定输入图像,它能够计算损失张量和梯度张量的值。你可以定义一个 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))])
  • 1
  • 2
  • 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
  • 2
  • 3
  • 4
  • 5

得到的图像张量是形状为 (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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

生成过滤器可视化的函数

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
 plt.imshow(generate_pattern('block3_conv1', 0))
  • 1

在这里插入图片描述
生成某一层中所有过滤器响应模式组成的网格

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述
在这里插入图片描述
这些过滤器可视化包含卷积神经网络的层如何观察世界的很多信息:卷积神经网络中每一层都学习一组过滤器,以便将其输入表示为过滤器的组合。这类似于傅里叶变换将信号分解为一组余弦函数的过程。随着层数的加深,卷积神经网络中的过滤器变得越来越复杂,越来越精细。

  • 模型第一层(block1_conv1)的过滤器对应简单的方向边缘和颜色(还有一些是彩色边缘)。
  • block2_conv1 层的过滤器对应边缘和颜色组合而成的简单纹理。
  • 更高层的过滤器类似于自然图像中的纹理:羽毛、眼睛、树叶等。
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
  

闽ICP备14008679号