如何画Grad-CAM图
时间: 2025-02-18 12:30:33 浏览: 55
### 实现和绘制Grad-CAM热力图
#### Grad-CAM概述
Grad-CAM是一种基于梯度的定位方法,可以提供来自深层网络的视觉解释[^3]。这种方法允许观察者理解模型在做出特定预测时关注的是输入图像中的哪个部分。
#### 准备工作
为了生成并绘制Grad-CAM热力图,在准备阶段需要确保安装必要的库,并加载预训练好的模型以及待分析的数据集。通常情况下会涉及到`torch`, `torchvision`等PyTorch相关包来构建或导入神经网络模型;另外还需要像`matplotlib.pyplot`这样的绘图工具来进行最终结果展示。
#### 获取最后一层卷积特征映射及其对应的类别得分向量
要应用Grad-CAM算法,首先要获取到目标网络的最后一层卷积层输出(即特征映射),同时也要获得该样本所属类别的得分向量\(y_c\)相对于这些特征映射的反向传播得到的梯度\(\frac{\partial y_c}{\partial A}\)[^5]。
```python
from pytorch_grad_cam import GradCAM
import torch.nn.functional as F
def get_last_conv_layer_and_gradients(model, input_tensor, target_category=None):
# 设置模型为评估模式
model.eval()
# 注册钩子函数以捕获指定层的激活值与梯度
activations = []
gradients = []
def forward_hook(module, inp, output):
activations.append(output)
def backward_hook(module, grad_input, grad_output):
gradients.append(grad_output[0])
handle_forward = model._modules.get('layer_name').register_forward_hook(forward_hook)
handle_backward = model._modules.get('layer_name').register_backward_hook(backward_hook)
outputs = model(input_tensor.unsqueeze(0))
if not isinstance(target_category, int):
_, predicted_class = torch.max(outputs.data, 1)
target_category = predicted_class.item()
one_hot_vector = F.one_hot(torch.tensor([target_category]), num_classes=outputs.size()[-1]).float().cuda()
model.zero_grad()
outputs.backward(one_hot_vector)
activation_maps = activations[-1].squeeze().cpu().data.numpy()
gradient_values = gradients[-1].squeeze().cpu().data.numpy()
handle_forward.remove()
handle_backward.remove()
return activation_maps, gradient_values
```
请注意上述代码片段中`'layer_name'`应替换为你实际使用的模型架构里最后一个卷基层的名字。
#### 计算全局平均池化后的梯度权重并与原始特征相乘求得重要性分数矩阵
接着利用前面收集到的信息——每张图片上各个位置处关于选定类别的敏感程度(由正向传递过程产生的激活值)同它们各自贡献了多少于最终分类结果之间关系(通过反传计算得出的局部梯度)相结合形成一个新的三维数组作为后续处理的基础材料[^4]。
```python
def compute_heatmap(activation_map, gradient_value):
weights = np.mean(gradient_value, axis=(1, 2)) # 对每个通道上的梯度取均值得到权重w_k
cam = np.zeros_like(activation_map[0], dtype=np.float32)
for k in range(len(weights)):
cam += weights[k]*activation_map[k]
cam = cv2.resize(cam, (input_image_size, input_image_size))
cam = np.maximum(cam, 0) # 只保留正值
heatmap = cam / cam.max() # 归一化至区间[0,1]
return heatmap
```
这里假设已经定义好了变量`input_image_size`代表原图尺寸大小以便调整热力图分辨率匹配源文件规格。
#### 将热力图叠加显示在原始图像之上完成可视化呈现
最后一步则是把之前制作出来的热度分布情况按照一定比例混合进最初提供的测试样例之中从而直观反映出哪些区域被赋予更高关注度:
```python
import matplotlib.pyplot as plt
import numpy as np
import cv2
def overlay_heatmap_on_original(image_path, heatmap, alpha=.7):
img = cv2.imread(image_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
heatmap = cv2.applyColorMap(np.uint8(255*heatmap), cv2.COLORMAP_JET)
superimposed_img = heatmap * alpha + img*(1-alpha)
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(superimposed_img.astype('uint8'))
plt.axis('off')
plt.show()
```
此段脚本接受三个参数:一是路径字符串指示哪一张照片参与运算;二是前述环节产出的结果对象;三是透明度系数控制融合效果深浅,默认设置为0.7较为合适。
阅读全文
相关推荐


















