深度学习:卷积神经网络-类激活图可视化

摘要:本文介绍一种卷积网络的可视化方法,类激活图可视化。使用预训练的VGG16模型,对一张网上随便找的动物图片进行分析,并将生成的热力图与原图像结合观察网络模型的分类依据。使用Keras框架。

目录

  1. 类激活图原理简介
  2. Keras实现

主要参考文献

【1】“Deep learning with python”

【2】“Grad-CAM: visual explanations from deep networks via gradientbased localization”

1. 类激活图原理简介

类激活图可视化,可以针对指定的输入图像生成类激活的热力图。类激活热力图表示图像的每个位置对该类别的重要程度。

Grad-CAM不同于CAM,理论上各种卷积网络都可以直接用该方法进行可视化,不需要对网络结构进行修改。

【2】中给出的方法如下:给定一张输入图像,对于一个卷积层的输出特征图,用类别相对于通道的梯度对这个特征图中的每个通道进行加权。直观理解,就是用每个通道对特定类别的重要程度不同通道的激活强度进行加权,从而得到输入图像对该类别的激活强度

落实到操作中,描述如下:取最后一层的卷积,算每个通道的梯度,然后对每个通道的梯度求全局平均,然后用这个全局平均加权原来的通道。下面使用Keras对上述步骤逐步实现。

2. Keras实现

使用预训练的VGG16对可视化的具体操作进行介绍。参照【1】。

首先直接载入Keras中的VGG16。记得使用model.summary()方法查看最后一个卷积层的名字,这里是block5_conv3。

from keras.applications.vgg16 import VGG16

model = VGG16(weights='imagenet')
model.summary()

同时准备输入数据,读取图像并转化为numpy数组的格式。读取的方法可以选择scipy.misc(已经过时),cv2,或者keras.preprocessing自带的image。最终得到的输入数据维数为[1, 224, 224, 3]。

import numpy as np
import scipy

from keras.applications.vgg16 import preprocess_input, decode_predictions

img_path = 'image.jfif'
img = scipy.misc.imread(img_path)
img = scipy.misc.imresize(img, (224, 224))
x = np.expand_dims(img, axis=0)
x = preprocess_input(x)

然后对该输入数据进行预测,得到模型输出。可以看到,对该输入,VGG16认为它有96.7%的概率是老虎。。最大概率的索引为292。

preds = model.predict(x)
print('Predicted:', decode_predictions(preds, top=3)[0])
print(np.argmax(preds[0])) # 用该索引分析输入和该类别之间的类激活图。
>>> Predicted: [('n02129604', 'tiger', 0.96711606), ('n02123159', 'tiger_cat', 0.026872123), ('n02391049', 'zebra', 0.0046514785)]
292

下面开始说明网络是通过哪一部分将其判断为老虎的,如果误分类,则可以说明网络看到了输入图像的什么位置导致的误分类。

import keras.backend as K

tiger_output = model.output[:, np.argmax(preds[0])]# 输出中老虎对应的元素。
last_conv_layer = model.get_layer('block5_conv3')# 最后一个卷积层
grads = K.gradients(tiger_output, last_conv_layer.output)[0]# 老虎类对于最后一个卷积层输出特征图的梯度
pooled_grads = K.mean(grads, axis=(0, 1, 2))# 对每个通道的梯度求全局平均
# 对于给定的输入图像,获取梯度的全局平均以及最后一个卷积层的输出
iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([x])
# 给定一张输入图像,对于一个卷积层的输出特征图,用类别相对于通道的梯度对这个特征图中的每个通道进行加权
for i in range(512):
    conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
heatmap = np.mean(conv_layer_output_value, axis=-1)

对该热力图进行可视化。
在这里插入图片描述

import matplotlib.pyplot as plt

heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)
plt.matshow(heatmap)

热力图的可视化结果如下图所示:

最后将热力图和原始图像合并,得到最终想要的可视化结果。

import cv2

img = cv2.imread(img_path)
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
heatmap = np.uint8(255 * heatmap)
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
superimposed_img = heatmap * 0.5 + img
cv2.imwrite('cam.jpg', superimposed_img)

结果如图所示:原始的老虎图片来自网络。

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章