深度学习笔记:卷积神经网络的可视化——卷积核特征模式

内容

1. 前言

2. 代码实验

2.1 加载模型

2.2 构造返回中间层激活输出的模型

2.3 目标函数

2.4 通过随机梯度上升最大化损失

2.5 生成滤波器模式可视化图像

2.6 将多维数组变换回图像

2.7 将所有卷积核的特征图全部打印出来

1. 前言

人们常说,深度学习模型是“黑盒”,即模型学到的东西对于人类来说很难理解。对于很多深度学习模型来说的确是这样的,但是对于卷积神经网络(CNN)却并不尽然。CNN学习到的东西非常适合于可视化,因为它就是学习关于视觉概念的表示!自CNN诞生以来,人们已经开发了很多种技术来对卷积神经网络学习到的东西进行可视化和解释。其中最容易理解也最有用是以下三种:

  1. 特征图的可视化。特征图即中间激活层的输出。这个有助于理解CNN的各层如何对输入进行变换,也有助于初步了解CNN中每个滤波器的含义
  2. 滤波器的可视化。有助于精确理解CNN中每个过滤器对应的视觉模式或视觉概念
  3. 热图的可视化。可视化图像中类激活的热图有助于了解图像的哪个部分被识别为属于哪个类,从而允许对图像中的对象进行定位

在之前的深度学习笔记:卷积神经网络的可视化——特征图我们介绍了如何可视化卷积神经网络的特征图。

想要了解卷积神经网络到底学到了什么,另一种简单的方法时显示每个卷积滤波器核所相应的视觉模式。这个可以通过在输入空间中的梯度上升(gradient ascent in input space)来实现:从空白输入图像开始,对卷积神经网络的输入图像执行梯度下降(实际上在以下实验中用的是梯度上升)处理以最大化某个特定滤波器的响应,最终得到的输入图像就是使得该特定滤波器具有最大相应的图像。我们可以称这个图像为该卷积滤波器核的特征模式。

这里,“对卷积神经网络的输入图像执行梯度下降处理”意思是指通过梯度下降来不断调整输入图像值,其道理与正常训练中通过梯度下降更新参数是相同的。这个概念上应该是有点类似于生成对抗网络(GAN)中的生成器部分(?)。

2. 代码实验

2.1 加载模型

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras import utils
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline 
from PIL import Image
import os, shutil, pathlib

model = keras.models.load_model("convnet_from_scratch_with_augmentation.keras")
model.summary()

这个模型是在前面几篇中训练过的模型。当然也可以直接加载keras内置的预训练模型。

2.2 构造返回中间层激活输出的模型

列出模型中有哪些卷积层

for layer in model.layers:
    if isinstance(layer, (keras.layers.Conv2D)):
        print(layer.name)

创建指定层特征提取模型

与前文中的特征提取模型不同,这里我们只指定特定层的激活输出。

layer_name = "conv2d_1"
layer = model.get_layer(name=layer_name)
feature_extractor = keras.Model(inputs=model.input, outputs=layer.output)

2.3 目标函数

首先,我们必须构建一个目标函数,该函数表示卷积层的给定滤波器的输出值(以下实现中的平均值)。

def compute_obj(image, filter_index):
    activation = feature_extractor(image)
    filter_activation = activation[:, 2:-2, 2:-2, filter_index]
    return tf.reduce_mean(filter_activation)

2.4 通过随机梯度上升最大化损失

然后,我们使用随机梯度下降(stochastic gradient descent)算法来调节输入图像值以最大化该特定滤波器的激活值。

虽然说SGD,但是这里由于我们是需要最大化目标函数,因此实际上采用的是随机梯度上升。随机梯度下降会最小化目标函数,随机梯度上升则会最大化目标函数。当然,我们也可以定义损失函数为滤波器激活输出的负值,这样我们就可以基于随机梯度下降的目标函数最小化来达成相同的目的。

@tf.function
def gradient_ascent_step(image, filter_index, learning_rate):
    with tf.GradientTape() as tape:
        tape.watch(image)
        objfunc = compute_obj(image, filter_index)
    grads = tape.gradient(objfunc, image)
    grads = tf.math.l2_normalize(grads)
    image += learning_rate * grads
    return image

2.5 生成滤波器模式可视化图像

img_width = model.input.shape[1]
img_height = model.input.shape[2]

def generate_filter_pattern(filter_index):
    iterations = 30
    learning_rate = 10.
    image = tf.random.uniform(
        minval=0.4,
        maxval=0.6,
        shape=(1, img_width, img_height, 3))
    for i in range(iterations):
        image = gradient_ascent_step(image, filter_index, learning_rate)
    return image[0].numpy()

2.6 将多维数组变换回图像

def deprocess_image(image):
    image -= image.mean()
    image /= image.std()
    image *= 64
    image += 128
    image = np.clip(image, 0, 255).astype("uint8")
    image = image[25:-25, 25:-25, :]
    return image

例如,其中选定层”conv2d_1″的序号2的卷积核的特征图像如下所示:

# plt.axis("off")
plt.imshow(deprocess_image(generate_filter_pattern(filter_index=2)))

深度学习笔记:卷积神经网络的可视化——卷积核特征模式

2.7 将所有卷积核的特征图全部打印出来

from tensorflow.keras.preprocessing.image import load_img, img_to_array, save_img

all_images = []
for filter_index in range(64):
    print(f"Processing filter {filter_index}")
    image = deprocess_image(
        generate_filter_pattern(filter_index)
    )
    all_images.append(image)

margin = 5
n = 8
cropped_width = img_width - 25 * 2
cropped_height = img_height - 25 * 2
width = n * cropped_width + (n - 1) * margin
height = n * cropped_height + (n - 1) * margin
stitched_filters = np.zeros((width, height, 3))

for i in range(n):
    for j in range(n):
        image = all_images[i * n + j]
        stitched_filters[
            (cropped_width + margin) * i : (cropped_width + margin) * i + cropped_width,
            (cropped_height + margin) * j : (cropped_height + margin) * j
            + cropped_height,
            :,
        ] = image

save_img(
    f"filters_for_layer_{layer_name}.png", stitched_filters)

运行可以得到如下图(注意上面的代码并没有直接打印图像,而是将图像保存为文件),可以看出每个卷积核感受到的模式是不同的:

深度学习笔记:卷积神经网络的可视化——卷积核特征模式

版权声明:本文为博主笨牛慢耕原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/chenxy_bwave/article/details/123070657

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2022年2月23日
下一篇 2022年2月23日

相关推荐