类激活图(CAM, class activation map)可视化, 是指对输入图像生成类激活的热力图, 表示每个位置对该类别的重要程度. 有助于了解一张图片的那个部分使得卷积神经网络做出最终的决策. 还可以定位图像中特定的目标
使用keras的完整实现方法(从<
使用keras的预训练VGG16模型对图片进行分类预测, 然后使用Grad-CAM算法生成热力图, 再将热力图扩展(映射)到原图上, 形成对每个位置有不同权重分配的新图像.
下面是完整过程
import cv2
import numpy as np
import matplotlib.pyplot as plt
from keras import backend as K
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input, decode_predictions
# 使用的图片 !wget https://pixabay.com/get/54e1d24b4f55a414f1dc8460825668204022dfe05554764e75297cd3/animals-2178578_640.jpg
# 待处理图像的路径, 自定义
img_path_orig = 'smartphone-1957740_640'
img_path = './{}.jpg'.format(img_path_orig)
# 将图片数据处理成预训练模型可以处理的格式
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
model = VGG16(weights='imagenet') # 加载VGG16模型, 用imagenet的权重
# 获取预测结果
preds = model.predict(x)
print(decode_predictions(preds, top=3)[0]) # 查看前三种预测类别的概率
# 利用 Grad-CAM算法 生成热力图. 然而看不懂为什么是这么实现的.
african_elephant_output = model.output[:, 386]
last_conv_layer = model.get_layer('block5_conv3') # 最后一个卷积层
grads = K.gradients(african_elephant_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)
heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)
# 读取原图
img = cv2.imread(img_path)
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
# 转化为RGB
heatmap = np.uint8(255 * heatmap)
# 应用热力图到原图上
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
superimposed_img = heatmap * 0.4 + img
cv2.imwrite('./{}_result.jpg'.format(img_path_orig), superimposed_img)
书中给的样例图片是非洲大象, 热力图的显示效果较好. 如下面这张图, 也是非洲大象图, 效果也尚可(非书中的示例).
但是在对其他图片进行处理的过程中, 发现效果并不是非常好, 比如下面这个手机的图片, VGG16预测成了ipad, 且热力图的关键点并未在手机上, 反而在左下角平坦位置比较多权重.
这张猫的图片, 对猫耳和猫舌有较大的权重