news 2026/4/10 13:06:26

Day 50 注意力热图可视化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day 50 注意力热图可视化

@浙大疏锦行

一、核心概念

注意力热图的本质是注意力权重矩阵的可视化映射

  • 权重值越高 → 热图颜色越深(如红色),代表模型越关注该部分输入
  • 权重值越低 → 热图颜色越浅(如蓝色),代表模型对该部分关注度低

在深度学习中,注意力热图主要分为两类:

  1. NLP 领域:基于 Transformer 的自注意力热图,展示 token 之间的关联权重
  2. CV 领域:基于 CAM/Grad-CAM 的特征注意力热图,展示图像区域对分类结果的贡献

二、CV - Grad-CAM 注意力热图可视化

在计算机视觉中,Grad-CAM 通过梯度加权激活图展示图像中对分类结果关键的区域,适用于 CNN 模型(如 ResNet、ViT)。

核心原理

  1. 计算目标类别对模型最后一个卷积层特征图的梯度
  2. 用梯度权重对特征图进行加权求和
  3. 将加权后的特征图上采样至原图尺寸,得到注意力热图

简化代码示例

import torch import torch.nn.functional as F import matplotlib.pyplot as plt from PIL import Image from torchvision import models, transforms # 1. 加载模型和图像预处理 model = models.resnet50(pretrained=True) model.eval() # 预处理:图像→张量 preprocess = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # 2. 加载并预处理图像 img = Image.open("cat.jpg").convert("RGB") img_tensor = preprocess(img).unsqueeze(0) # (1, 3, 224, 224) # 3. 注册钩子获取特征图和梯度 feature_maps = [] grads = [] def forward_hook(module, input, output): feature_maps.append(output) def backward_hook(module, grad_in, grad_out): grads.append(grad_out[0]) # 注册到最后一个卷积层 target_layer = model.layer4[-1] forward_handle = target_layer.register_forward_hook(forward_hook) backward_handle = target_layer.register_full_backward_hook(backward_hook) # 4. 前向传播+反向传播 preds = model(img_tensor) pred_class = preds.argmax(dim=1).item() model.zero_grad() preds[:, pred_class].backward() # 5. 计算Grad-CAM权重 fm = feature_maps[0].squeeze() # (2048, 7, 7) grad = grads[0].squeeze() # (2048, 7, 7) weights = F.adaptive_avg_pool2d(grad, (1, 1)).squeeze() # (2048,) cam = torch.sum(weights[:, None, None] * fm, dim=0) # (7, 7) cam = F.relu(cam) # 只保留正贡献 cam = F.interpolate( cam.unsqueeze(0).unsqueeze(0), size=img.size[::-1], mode="bilinear", align_corners=False ).squeeze() cam = cam / cam.max() # 归一化 # 6. 绘制热图叠加原图 plt.figure(figsize=(10, 10)) plt.imshow(img) plt.imshow(cam.numpy(), alpha=0.5, cmap="jet") plt.axis("off") plt.title(f"Grad-CAM Attention (Class: {pred_class})") plt.show() # 移除钩子 forward_handle.remove() backward_handle.remove()

三、步骤总结

步骤 1:准备工作(模型 + 图像预处理)

核心目的:搭建可提取梯度和特征图的模型环境,将原始图像转为模型可处理的张量

  1. 选择并加载 CNN 模型:优先选择包含卷积层 + 全连接层的模型(预训练 / 自定义均可),关键是保留最后一层卷积层(高层特征包含语义信息,可视化有意义;低层仅边缘纹理,无分类参考价值)。
  2. 图像预处理:严格遵循模型输入规范(尺寸、归一化参数),转为张量并增加批次维度(模型要求批量输入)。
  3. 模型设置:设为eval()模式(关闭 Dropout、BatchNorm 等训练层),但不使用torch.no_grad()(因为需要计算梯度,no_grad()会禁用梯度传播)。

步骤 2:捕获最后一层卷积层的「特征图」和「梯度」(核心:Hook 函数)

核心目的:通过 Hook 函数获取两个关键数据 —— 最后卷积层的输出(特征图)、目标类别对该特征图的梯度(反映通道重要性)。这是 Grad-CAM 的核心基础,因为后续所有计算都依赖这两个数据,具体操作:

  1. 定义两个 Hook 函数:前向 Hook 捕获特征图,反向 Hook 捕获梯度;
  2. 定位最后一层卷积层:以 ResNet18 为例,最后一层卷积层是model.layer4[-1].conv2
  3. 注册 Hook 并保存句柄:后续需移除 Hook,避免内存泄漏。

步骤 3:前向传播,获取目标类别

核心目的:通过前向传播得到模型的预测结果,确定要可视化的「目标类别」(可选择模型预测类别,也可自定义类别)

  1. 执行前向传播,得到模型对输入图像的预测输出;
  2. 提取预测类别(argmax获取概率最大的类别),作为后续反向传播的目标。

步骤 4:反向传播,计算目标类别的梯度

核心目的:针对目标类别执行反向传播,触发反向 Hook 函数,捕获该类别对最后卷积层特征图的梯度。关键细节:

  1. 清零现有梯度:用model.zero_grad()避免梯度累积;
  2. 仅对目标类别的输出值反向传播:不是对整个损失函数反向传播,而是直接对pred_output[0, target_class]反向传播,这样得到的梯度仅反映该类别对特征图的贡献;
  3. 反向传播后,gradient变量会被 Hook 函数填充,得到目标类别对应的梯度。

步骤 5:计算梯度权重(全局平均池化 GAP)

核心目的:将每个通道的梯度压缩为一个标量权重,反映该通道对目标类别的「重要性」。为什么用全局平均池化(GAP)?因为最后卷积层的梯度形状是(1, C, H, W)(C = 通道数,H/W = 特征图尺寸),每个通道对应一个特征图,我们需要用一个标量来代表该通道的重要性,GAP 可以将每个通道的(H, W)梯度值平均为一个标量,具体操作:

  1. 对梯度在「空间维度」(H、W)上执行平均池化,保留通道维度;
  2. 得到的权重形状为(1, C, 1, 1),每个值对应一个通道的重要性。

步骤 6:加权求和生成原始 CAM 图,ReLU 激活过滤负贡献

核心目的:用通道权重对特征图进行加权求和,生成原始 CAM 图,并过滤负贡献(仅保留对分类有帮助的区域)。具体操作:

  1. 加权求和:将通道权重与对应的特征图通道相乘,然后沿通道维度求和,消除通道维度,得到原始 CAM 图;
  2. ReLU 激活:Grad-CAM 的核心创新之一,只保留正贡献(值 > 0),负贡献对目标类别分类无帮助,直接过滤,避免干扰可视化结果;
  3. 原始 CAM 图的形状与最后卷积层特征图一致(如(7, 7)),尺寸较小,需后续上采样。

步骤 7:上采样至原图尺寸,归一化处理

核心目的:将小尺寸的原始 CAM 图放大至与输入图像一致的尺寸,方便叠加可视化,并归一化到 0-1 区间,避免颜色失真。具体操作:

  1. 上采样:使用双线性插值(bilinear),效果优于最近邻插值,能保持热图的平滑性;
  2. 归一化:将 CAM 图的值压缩到 0-1 区间,消除数值范围差异对可视化的影响。

步骤 8:热图可视化,叠加原图展示结果

核心目的:将 CAM 图转换为彩色热图,并与原始图像叠加,直观展示模型的注意力区域。具体操作:

  1. 将 CAM 图转换为彩色热图:使用 OpenCV 的applyColorMap,常用COLORMAP_JET(红 = 高权重,蓝 = 低权重);
  2. 格式转换与归一化:将 OpenCV 的 BGR 格式转为 RGB 格式,与原始图像格式对齐;
  3. 叠加原图:设置透明度(如原图 0.7,热图 0.3),平衡原图和热图的可见性;
  4. 移除 Hook 句柄:释放内存,避免后续干扰。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/8 16:11:30

【开题答辩全过程】以 高校社团管理系统设计与实现为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/4/10 2:05:22

HBase在物联网(IoT)中的应用:海量设备数据处理方案

HBase在物联网(IoT)中的应用:海量设备数据处理方案 关键词:HBase、物联网(IoT)、海量数据、时间序列、分布式存储、高并发写入、RowKey设计 摘要:物联网(IoT)时代,全球每天产生万亿条设备数据(如传感器、智能硬件、工业设备),这些数据具有"海量、高频、多源、实…

作者头像 李华
网站建设 2026/4/4 8:20:16

使用TensorRT加速LangChain应用响应速度

使用TensorRT加速LangChain应用响应速度 在构建生成式AI应用的今天,用户早已不再满足于“能用”,而是追求“快、稳、多”——更低的延迟、更高的并发能力、更流畅的交互体验。尤其是在基于 LangChain 构建的智能对话系统中,每一次提示词&…

作者头像 李华
网站建设 2026/3/27 18:52:56

Myvatis 动态查询及关联查询

1.查询和修改1.1 MyBatis中的<where>, <set>和<trim>标签详解1.1.1 <where>标签<where>标签用于动态生成SQL语句中的WHERE子句&#xff0c;它会智能处理以下情况&#xff1a;自动去除开头多余的AND或OR当所有条件都不满足时&#xff0c;不会生成…

作者头像 李华
网站建设 2026/4/2 21:24:01

Docker 网络

Dcoker中的网络类型网络类型备注bridge为每一个容器分配、设置IP等&#xff0c;并将容器连结到一个docker0网络虚拟网桥&#xff0c;默认为该模式host 容器将不会虚拟出自己的网卡&#xff0c;配置自己的IP等&#xff0c;而是使用宿主机的IP和端口none容器拥有独立的Net…

作者头像 李华
网站建设 2026/4/2 0:35:53

TensorRT极致优化:让您的GPU算力发挥最大效能

TensorRT极致优化&#xff1a;让您的GPU算力发挥最大效能 在现代AI系统中&#xff0c;模型一旦训练完成&#xff0c;真正的挑战才刚刚开始——如何在生产环境中以最低延迟、最高吞吐的方式运行推理&#xff1f;尤其是在视频分析、语音助手、推荐引擎等对实时性要求极高的场景下…

作者头像 李华