一、说明
这个想法是,我们从最后的密集层中得到权重,然后乘以最终的CNN层。这需要全局平均池化(GAP)才能发挥作用。
二、选择型号
在本教程中,我们将 Keras 与 Tensorflow 和 ResNet50 结合使用。
因为 ResNet50 有一个全局平均池化 (GAP) 层(稍后会解释),所以它适合我们的演示。这很完美。
三、热图如何工作
来自CNN的热图,又名类激活映射(CAM)。这个想法是我们收集卷积层的每个输出(作为图像),并将其组合在一个镜头中。(我们稍后会逐步展示代码)
因此,以下是全局平均池化 (GAP) 或全局最大池化的工作方式(取决于您使用哪个,但它们是相同的想法)。
在一些特征提取后的模型中,我们使用与神经网络的扁平层(完全连接)来预测结果。但这一步就像丢弃图像维度和一些信息。
相比之下,使用全局平均池 (GAP) 或全局最大池 (GMP) 在这里起作用。它保留图像维度信息,并使神经网络决定哪个CNN通道(特征图像)对于预测结果更为关键。
四、示例和代码
让我们从Keras中的ResNet50开始。
from tensorflow.keras.applications import ResNet50
res_model = ResNet50()
res_model.summary()
如您所见(上图):
- 红色:我们将使用此层作为“转移倾斜”。
- 绿色:全球平均池化(GAP)。这项工作至关重要。
并导入库和图像供以后使用。
import cv2
import matplotlib.pyplot as plt
from scipy.ndimage import zoom
from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions
img = cv2.imread('./test_cat.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
X = np.expand_dims(img, axis=0).astype(np.float32)
X = preprocess_input(X)
我们使用“from scipy.ndimage import zoom”。为了调整由于CNN而调整热图的大小,特征提取图像的形状小于原始图像。
4.1 迁移学习
现在提取我们将使用的图层。
P.S:你可以从头开始训练你的模型,但需要很长时间,特征提取可能也需要大量的调优。
from tensorflow.keras.models import Model
conv_output = res_model.get_layer("conv5_block3_out").output
pred_ouptut = res_model.get_layer("predictions").output
model = Model(res_model.input, outputs=[conv_ouptut, pred_layer])
这里我们有两个输出(如上所述,图中的红色部分)。
- 首先是卷积网络输出
- 二是预测结果
并做预测
conv, pred = model.predict(X)
decode_predictions(pred)
结果如下所示。还不错
[[('n02123159', 'tiger_cat', 0.7185241),('n02123045', 'tabby', 0.1784818),('n02124075', 'Egyptian_cat', 0.034279127),('n03958227', 'plastic_bag', 0.006443105),('n03793489', 'mouse', 0.004671723)]]
4.2 输出
现在,让我们看看一些CNN输出。
scale = 224 / 7
plt.figure(figsize=(16, 16))
for i in range(36):plt.subplot(6, 6, i + 1)plt.imshow(img)plt.imshow(zoom(conv[0, :,:,i], zoom=(scale, scale)), cmap='jet', alpha=0.3)
CNN 输出
我们首先显示地面图像( plt.imshow(img) ),因此我们可以将其与地面图像进行比较。
(如果你不这样做,会得到这样的结果)
4.3 输出的一次性组合
这是关键的。我们使用预测结果指数(目标)来获取权重。并乘以每个特征图与权重(点积)
target = np.argmax(pred, axis=1).squeeze()
w, b = model.get_layer("predictions").weights
weights = w[:, target].numpy()
heatmap = conv.squeeze() @ weights
然后显示带有地面图像的热图。
scale = 224 / 7
plt.figure(figsize=(12, 12))
plt.imshow(img)
plt.imshow(zoom(heatmap, zoom=(scale, scale)), cmap='jet', alpha=0.5)
这就是我们想要的结果。
五、参考资源
海沌
- 用于图像识别的深度残差学习 — https://arxiv.org/abs/1512.03385
- Grad-CAM:通过基于梯度的定位从深度网络进行视觉解释 — https://arxiv.org/abs/1610.02391
- 网中网 — https://arxiv.org/abs/1312.4400
- 学习区分性本地化的深层特征 — https://arxiv.org/abs/1512.04150