【Day42】

article/2025/8/5 3:55:22

DAY 42 Grad-CAM与Hook函数

知识回顾

  1. 回调函数
  2. lambda函数
  3. hook函数模块钩子张量钩子
  4. Grad-CAM示例

作业:理解今天代码即可

"""
Day 42: Grad-CAM与Hook函数本节主要内容:
1. 回调函数(Callback)和lambda函数- 回调函数是作为参数传递给其他函数的函数- lambda函数是一种简单的匿名函数,用于创建一次性的简单函数2. hook函数(钩子函数)- 在深度学习中,hook函数用于"钩住"模型的某些层,获取或修改中间结果- 分为forward hook(前向钩子)和backward hook(后向钩子)- forward hook可以获取层的输入和输出- backward hook可以获取层的梯度信息3. Grad-CAM(Gradient-weighted Class Activation Mapping)- 一种可视化CNN模型决策的技术- 使用梯度信息来理解模型关注的图像区域- 通过生成热力图来展示模型的注意力焦点
"""import torch  # PyTorch深度学习框架
import torch.nn as nn  # 神经网络模块
import torch.nn.functional as F  # 函数式接口
import torchvision  # 计算机视觉工具包
from torchvision.models import ResNet18_Weights  # ResNet18预训练权重
import torchvision.transforms as transforms  # 图像变换工具
import matplotlib.pyplot as plt  # 绘图库
import numpy as np  # 数值计算库
from PIL import Image  # 图像处理库# 设置matplotlib中文字体,避免中文显示乱码
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 设置随机种子,确保结果可复现
torch.manual_seed(42)
# 检测是否可以使用GPU,如果可以就使用GPU,否则使用CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")class GradCAM:"""Grad-CAM(Gradient-weighted Class Activation Mapping)实现类工作原理:1. 获取CNN模型中指定层的特征图(通过forward hook)2. 获取特征图对于目标类别的梯度(通过backward hook)3. 计算每个通道的重要性权重4. 生成类激活图(CAM)来显示模型关注的区域使用方法:1. 创建GradCAM实例,指定模型和目标层2. 调用generate_cam方法生成类激活图3. 使用完毕后调用remove_hooks清理钩子"""def __init__(self, model, target_layer):"""初始化GradCAM参数:- model: 预训练的CNN模型- target_layer: 要可视化的目标层(通常是最后的卷积层)"""self.model = modelself.target_layer = target_layerself.gradients = None  # 存储梯度self.features = None   # 存储特征图# 注册钩子列表,用于后续移除self.hooks = []self._register_hooks()def _register_hooks(self):"""注册前向和后向钩子函数钩子函数的作用:1. forward_hook: 保存前向传播时的特征图2. backward_hook: 保存反向传播时的梯度信息"""def forward_hook(module, input, output):"""前向钩子函数,保存特征图"""self.features = output.detach()  # detach()创建不需要梯度的副本def backward_hook(module, grad_input, grad_output):"""后向钩子函数,保存梯度"""self.gradients = grad_output[0].detach()# 注册钩子# register_forward_hook在前向传播时触发self.hooks.append(self.target_layer.register_forward_hook(forward_hook))# register_full_backward_hook在反向传播时触发,支持多个自动求导节点self.hooks.append(self.target_layer.register_full_backward_hook(backward_hook))def remove_hooks(self):"""移除所有注册的钩子在使用完GradCAM后必须调用此方法,否则可能造成内存泄漏"""for hook in self.hooks:hook.remove()def generate_cam(self, input_image, target_class=None):"""生成类激活图(CAM)参数:- input_image: 输入图像张量,形状为[1, C, H, W]- target_class: 目标类别索引,如果为None则使用模型预测的类别返回:- cam: 类激活图(numpy数组)工作流程:1. 前向传播得到预测结果2. 计算目标类别的梯度3. 计算特征图的权重4. 生成并归一化类激活图"""# 前向传播model_output = self.model(input_image)# 如果没有指定目标类别,使用预测的类别if target_class is None:target_class = torch.argmax(model_output, 1).item()# 反向传播self.model.zero_grad()  # 清除现有梯度model_output[0, target_class].backward()  # 计算目标类别的梯度# 计算每个通道的权重(全局平均池化)weights = torch.mean(self.gradients, dim=(2, 3))[0, :]# 生成CAM# 创建与特征图大小相同的零张量cam = torch.zeros(self.features.shape[2:], dtype=torch.float32).to(device)# 将每个通道的特征图与其权重相乘并相加for i, w in enumerate(weights):cam += w * self.features[0, i, :, :]cam = F.relu(cam)  # 使用ReLU确保只关注正面贡献cam = cam - torch.min(cam)  # 减去最小值cam = cam / torch.max(cam)  # 归一化到[0,1]范围return cam.cpu().numpy()def denormalize(tensor, mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]):"""反归一化图像张量在训练深度学习模型时,我们通常会对输入图像进行标准化(减均值除以标准差)显示图像时需要将其转换回原始范围参数:- tensor: 输入张量- mean: ImageNet数据集的均值- std: ImageNet数据集的标准差返回:- 反归一化后的张量,像素值在[0,1]范围内"""tensor = tensor.clone()  # 创建副本避免修改原始数据for t, m, s in zip(tensor, mean, std):t.mul_(s).add_(m)  # 反归一化:x = x * std + meanreturn tensor.clamp_(0, 1)  # 将值限制在[0,1]范围内def visualize_cam(image, cam):"""可视化原始图像和CAM创建三个子图:1. 原始图像2. Grad-CAM热力图3. 热力图与原始图像的叠加结果参数:- image: 输入图像张量- cam: 类激活图(numpy数组)"""plt.figure(figsize=(12, 4))# 处理原始图像img = denormalize(image)  # 反归一化img_np = img.permute(1, 2, 0).cpu().numpy()  # 调整通道顺序并转换为numpy数组h, w = img_np.shape[:2]  # 获取图像尺寸# 调整CAM大小以匹配原始图像cam_resized = np.float32(cam)cam_resized = Image.fromarray(cam_resized)cam_resized = cam_resized.resize((w, h), Image.LANCZOS)  # LANCZOS提供高质量的重采样cam_resized = np.array(cam_resized)# 显示原始图像plt.subplot(1, 3, 1)plt.imshow(img_np)plt.title('原始图像')plt.axis('off')# 显示热力图plt.subplot(1, 3, 2)plt.imshow(cam_resized, cmap='jet')  # 使用jet颜色映射plt.title('Grad-CAM')plt.axis('off')# 显示叠加图plt.subplot(1, 3, 3)heatmap = plt.cm.jet(cam_resized)[:, :, :3]  # 转换为RGB热力图overlayed = 0.6 * img_np + 0.4 * heatmap  # 将热力图叠加到原始图像上overlayed = np.clip(overlayed, 0, 1)  # 确保值在[0,1]范围内plt.imshow(overlayed)plt.title('叠加结果')plt.axis('off')plt.tight_layout()plt.show()def main():"""主程序:演示Grad-CAM的使用步骤:1. 加载预训练的ResNet18模型2. 准备输入图像3. 创建GradCAM实例4. 生成并可视化类激活图"""# 加载预训练模型,使用新的weights参数(替代已弃用的pretrained参数)weights = ResNet18_Weights.DEFAULTmodel = torchvision.models.resnet18(weights=weights).to(device)model.eval()  # 设置为评估模式# 准备图像转换transform = transforms.Compose([transforms.Resize((224, 224)),  # 调整图像大小transforms.ToTensor(),          # 转换为张量transforms.Normalize(           # 标准化mean=[0.485, 0.456, 0.406],  # ImageNet数据集的均值std=[0.229, 0.224, 0.225]    # ImageNet数据集的标准差)])# 加载示例图像(使用CIFAR-10数据集的第一张图片)trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True)image, _ = trainset[0]image = transform(image).unsqueeze(0).to(device)  # 添加batch维度并移到设备# 创建Grad-CAM(使用最后一个残差块的输出)grad_cam = GradCAM(model, model.layer4[-1])try:# 生成CAMcam = grad_cam.generate_cam(image)# 可视化结果visualize_cam(image[0], cam)finally:# 确保钩子被清理(即使发生异常)grad_cam.remove_hooks()if __name__ == '__main__':"""回调函数和lambda函数示例回调函数:- 是一种将函数作为参数传递给另一个函数的编程模式- 允许在特定事件发生时执行自定义代码lambda函数:- 也称为匿名函数- 用于创建简单的一次性函数- 语法:lambda 参数: 表达式"""def process_data(data, callback):"""回调函数示例"""result = data * 2return callback(result)# 使用普通函数作为回调def square(x):return x ** 2# 使用lambda函数作为回调(等价于上面的square函数)result1 = process_data(5, square)  # 使用命名函数result2 = process_data(5, lambda x: x ** 2)  # 使用lambda函数print("回调函数示例:")print(f"使用普通函数: {result1}")print(f"使用lambda函数: {result2}")print()# 运行主程序main()
回调函数示例:
使用普通函数: 100
使用lambda函数: 100Files already downloaded and verified
arning-library/Day42.py
回调函数示例:
使用普通函数: 100
使用lambda函数: 100Files already downloaded and verified

浙大疏锦行 


http://www.hkcw.cn/article/hnpRDvkbfY.shtml

相关文章

各种乱码问题解决措施

1.乱码问题原因 1.数据的编码和解码使用的不是同一个字符集 编码就是我们能看懂的数据转换为计算机能够识别的二进制编码 解码就是将存在计算机里面的二进制编码的文件转化为我们能够识别的字符等内容。 2.使用了不支持某个语言文字的字符集。 1,1html文件乱码 在<meta c…

c++ 异常处理

测试代码&#xff1a; #include <exception>void testException() { // test exceptionclass MyException : public exception {public:using std::exception::exception; // 关键&#xff1a;继承父类所有构造函数};struct Divide {int operator() (int a, int b) cons…

yolo个人深入理解

卷积层的理解,通过云端服务器训练模型,模型构建的重要性,针对极低像素的处理,模型训练召回率提高技巧,卷积层2,4,8,16,32的小模型与大模型的理解 一.关于backbone,neck,head深入理解 1,backbone的主要组成部分是sppf和conv,这是backbone的核心,其中yolov5和yolov8…

Git基本操作

目录 1. 创建Git本地仓库 2. 配置Git 3. 认识工作区、暂存区、版本库 4. 添加文件 -- 场景一 5. 查看.git文件 6. 添加文件 -- 场景二 7. 修改文件 8. 版本回退 9. 撤销修改 9.1 情况一&#xff1a;对于工作区的代码&#xff0c;还没有add 9.2 情况二&#xff1a;已…

《中国棒垒球》注册青少年运动员需要什么条件·棒球1号位

青少年注册棒球/垒球运动员&#xff1a; 基础条件 | Basic Requirements 年龄范围 通常6-18岁&#xff08;按U8/U10/U12/U15/U18分组&#xff09; Typically 6-18 years old (grouped as U8/U10/U12/U15/U18) 健康证明 需提交体检报告&#xff0c;重点关注心肺功能与运动损…

华为深度学习面试手撕题:手写nn.Conv2d()函数

题目 只允许利用numpy包&#xff0c;实现Pytorch二维卷积函数nn.Conv2d() 解答 此代码考察二维卷积的概念&#xff0c;详见&#xff1a; 6.2. 图像卷积 — 动手学深度学习 2.0.0 documentation 6.3. 填充和步幅 — 动手学深度学习 2.0.0 documentation 6.4. 多输入多输出通…

MMR 最大边际相关性详解

最大边际相关性&#xff08;MMR&#xff0c;max_marginal_relevance_search&#xff09;的基本思想是同时考量查询与文档的 相关度&#xff0c;以及文档之间的 相似度。相关度 确保返回结果对查询高度相关&#xff0c;相似度 则鼓励不同语义的文档被包含进结果集。具体来说&…

美业+智能体,解锁行业转化新密码(2/6)

摘要&#xff1a;中国美业市场近年蓬勃发展&#xff0c;规模持续扩大&#xff0c;预计不久将突破万亿级别&#xff0c;但同时也面临着诸多挑战&#xff0c;如获客成本攀升、服务质量不稳定、难以满足消费者多元化个性化需求等。智能体技术的出现为美业带来了新的发展机遇&#…

Mybatis-Plus 学习

Mybatis-Plus 简介 官网&#xff1a;https://baomidou.com/ github 地址&#xff1a;https://github.com/baomidou/mybatis-plus 什么是 Mybatis-Plus MyBatis-Plus&#xff08;简称 MP&#xff09;是 MyBatis 的增强工具库&#xff0c;旨在简化开发流程&#xff0c;减少样…

Linux开发追踪(IMX6ULL篇_第一部分)

前言 参数&#xff1a;cortex-A7 698Mhz flash 8GB RAM 512M DDR3 2个100M网口 单核 初期&#xff1a; 一、安装完虚拟机之后&#xff0c;第一步先设置文件之间可以相互拷贝复制&#xff0c;以及通过CRT连接到虚拟机等 折磨死人了啊啊啊啊啊啊 1、关于SSH怎么安装…

中国观鸟数据集(CSV)

数据简介 今天我们分享的数据是观鸟数据集&#xff0c;该数据整理中国观鸟记录中心的鸟类报告数据&#xff0c;在2024年获取了该网站种鸟类的报告信息&#xff0c;详情信息以及鸟种信息&#xff0c;分别整理为各省的数据&#xff0c;方便大家研究使用&#xff0c;方便大家研究使…

【AI论文】SWE-rebench:一个用于软件工程代理的任务收集和净化评估的自动化管道

摘要&#xff1a;基于LLM的代理在越来越多的软件工程&#xff08;SWE&#xff09;任务中显示出有前景的能力。 然而&#xff0c;推进这一领域面临着两个关键挑战。 首先&#xff0c;高质量的训练数据稀缺&#xff0c;尤其是反映现实世界软件工程场景的数据&#xff0c;在这些场…

【计算机系统结构】习题2

目录 1.有一条静态多功能流水线由5段组成&#xff0c;加法用1、2、4、5段&#xff0c;乘法用1、3、5段&#xff0c;第3段时间为&#xff0c;其余各段为&#xff0c;且流水线的输出可直接返回输入端或暂存器&#xff0c;若计算&#xff0c;试计算吞吐量、加速比、效率 2.有一动…

多模态大语言模型arxiv论文略读(103)

Are Bigger Encoders Always Better in Vision Large Models? ➡️ 论文标题&#xff1a;Are Bigger Encoders Always Better in Vision Large Models? ➡️ 论文作者&#xff1a;Bozhou Li, Hao Liang, Zimo Meng, Wentao Zhang ➡️ 研究机构: 北京大学 ➡️ 问题背景&…

[ElasticSearch] RestAPI

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

【irregular swap】An Examination of Fairness of AI Models for Deepfake Detection

文章目录 An Examination of Fairness of AI Models for Deepfake Detection背景points贡献深伪检测深伪检测审计评估检测器主要发现评估方法审计结果训练分布和方法偏差An Examination of Fairness of AI Models for Deepfake Detection 会议/期刊:IJCAI 2021 作者: 背景…

初学大模型部署以及案例应用(windows+wsl+dify+mysql+Ollama+Xinference)

大模型部署以及案例应用&#xff08;windowswsldifymysqlOllamaXinference&#xff09; 1.wsl 安装①安装wsl②测试以及更新③安装Ubuntu系统查看系统以及版本安装Ubuntu系统进入Ubuntu系统 2、docker安装①下载安装包②安装③docker配置 3、安装dify①下载dify②安装③生成.en…

【Linux系统编程】Ext系列文件系统

目录 磁盘文件系统的必要性 认识磁盘结构 理解硬件 磁盘的物理结构 磁盘的存储结构 磁盘的逻辑结构 引入磁盘文件系统 引入"块"概念 引入"分区"概念 引入"分组"概念 ext*系列文件系统 inode、inode Bitmap、inode Table Block Bitm…

基于ZYNQ ARM+FPGA异构平台的声呐数据采集系统设计

0 引 言 近年来&#xff0c;随着海洋工程技术的发展&#xff0c;水下无人 航行器 (underwater unmanned vehicle, UUV)) 因其 灵活性、低风险性以及多功能性的优点&#xff0c;在维护国 家海洋权益以及海洋安全发挥着日益重要的作用 [1-3] 。 UUV 在完成目标搜索、…

前端基础学习html+css+js

HTML 区块 div标签&#xff0c;块级标签 span包装小部分文本&#xff0c;行内元素 表单 CSS css选择器 css属性 特性blockinlineinline-block是否换行✅ 换行❌ 不换行❌ 不换行可设置宽高✅ 支持❌ 不支持✅ 支持常见元素div容器 p段落 h标题span文本容器 a超链接img图片…