VGG16能让某个指定的feature map激活值最大化图片的可视化
在前面的文章中,我用jupyter notebook分别实现了,预训练好的VGG16模型各层filter权重的可视化和给VGG16输入了一张图像,可视化VGG16各层的feature map。深度学习 --- VGG16卷积核的可视化(JupyterNotebook实战)-优快云博客文章浏览阅读653次,点赞11次,收藏8次。本文是基于JupyterNotebook的VGG16卷积核的可视化实战,有代码也有详细说明
https://blog.youkuaiyun.com/daduzimama/article/details/141460156
在这篇文章中需要可视化的是看看究竟什么的图像会令众多feature map/activation map中的某个activation map的激活值最大化。例如,看看什么样的图像会让block2_conv2中的第123个feature map的激活值最大化。
这个算法的整体思路如下:
1,利用已有的不包含顶层的VGG16模型创建一个输出为指定层指定feature map的新模型
2,创建一个图像尺寸和模型输入层维度相同的随机噪声图,并假设他就是那个能够令指定feature map激活最大化的输入图像作为初值。
3,定义损失函数,这个损失函数的输入是刚才创建随机噪声图像,输出为指定feature map的激活值总和。
4,创建优化器使用梯度上升的反向传播方式,使得损失函数的函数值最大化。逐步迭代,最终把原始的随机噪声图像变成我们想要的能够最大化feature map的输入图像。
1,导入需要用到的库函数
import tensorflow as tf
print(tf.__version__)
print(tf.keras.__version__)
from tensorflow.keras.applications import VGG16
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input
import numpy as np
import matplotlib.pyplot as plt
2,加载不包括顶层VGG16的模型
model=VGG16(weights='imagenet',include_top=False)
model.summary()
# 获取该模型的总层数
total_layers = len(model.layers)
# 输出总层数
print(f"模型的总层数为: {total_layers}")
# 输出每一层所对应的名字便于后续选择feature map时使用
for i in range(total_layers):
print(f"第{i}层是{model.layers[i].name}")

3,定义损失函数
定义损失函数也就是定义feature map关于输入图像的函数。因此,损失函数的输入是我们后面自定义的模型model,输入图像和指定feature map的index。输出是整张指定feature map值的均值。
# 损失函数的输入为你所使用的model,输入图像和指定feature map的index,输出是指定层的某个卷积核的激活值的均值
def loss_function(model,input_image,feature_map_num):
activations = model(input_image)#获得input_image在新模型中产生的所有特征图
'''
activations 是一个四维张量,其维度如下:
第一个维度 (batch size): 代表输入批次的大小。通常情况下,如果只输入了一张图像,这个维度的值为 1。
第二个维度 (height): 代表特征图的高度。随着网络层数的增加,通常由于池化层(Pooling Layer)的作用,这个维度会逐渐减小。
第三个维度 (width): 代表特征图的宽度。和高度一样,宽度通常也会随着网络的加深而减小。
第四个维度 (channels/filters): 代表特征图的通道数,或者说在当前层中使用的滤波器的数量。这个维度表示在每一层中所提取的不同特征的数量。
'''
loss = tf.reduce_mean(activations[:, :, :, feature_map_num])
return loss
”activations = model(input_image)“这句话的意思是:把随机生成的输入图像喂给新建的模型计算,输出相应层所有的output,output即feature map。并且把指定层所有的feature map保存在activations中。
“loss = tf.reduce_mean(activations[:, :, :, feature_map_num])”这句话的意思是:根据函数输入的feature_map_num,在activations选择当前层指定的feature map,也就是我们需要最大化的那个feature map,并计算这个张量的均值。
最终把整张feature map的均值通过loss函数传出去。
上述过程如果用数学模型来表示的话大致可写成(这里不一定严谨,仅供参考):
这样看来,损失函数L是input image的复合函数,feature map是input image的函数。
4,定义计算梯度的函数
梯度是用于反向传播的,这里所计算的梯度是损失函数相对于输入图像的梯度。
def gradient_function(model,image,feature_map_num):
#创建 tf.GradientTape 对象:
#TensorFlow 的 tf.GradientTape 是一个自动微分工具,它可以记录运算过程中涉及的所有变量,并计算这些变量相对于某个损失函数的梯度。
with tf.GradientTape() as tape:
#监视输入图像:这里明确告诉 GradientTape 需要监视 image 这个张量,确保后续可以计算相对于 image 的梯度。
tape.watch(image)
#计算损失函数
loss = loss_function(model,image,feature_map_num)
#通过 tape.gradient() 计算损失 loss 相对于输入图像 image 的梯度。
#这会返回一个张量 gradient,表示如何调整输入图像以最大化或最小化损失。
gradient = tape.gradient(loss, image)
return loss,gradient
计算损失函数相对于输入图像的梯度的目的是为了通过反向传播,也就是梯度上升,不断地优化输入图像。这一过程也可以用数学公式简单的表示如下:
因此,第一步是调用先前定义的损失函数计算loss。

第二步就调用tensorflow自带的计算梯度的函数tf.GradientTape去计算梯度。其中,tape.gradient的第一个输入是损失函数的值loss,第二个要输入的变量是损失函数相对于谁的梯度,比如说在本例中要计算损失函数相对于输入图像input image的梯度,所以这里输入的就是随机初始化的input image。

5,定义用于优化图像显示效果的函数
通过梯度上升反向传播得到的能够令某个feature map最大化的input image无法直接通过imshow函数显示,因此,这里定义了一个专门

最低0.47元/天 解锁文章
434





