神经网络的解释方法之CAM、Grad-CAM、Grad-CAM++、LayerCAM

news2024/11/20 6:19:02
原理优点缺点
GAP将多维特征映射降维为一个固定长度的特征向量①减少了模型的参数量;②保留更多的空间位置信息;③可并行计算,计算效率高;④具有一定程度的不变性①可能导致信息的损失;②忽略不同尺度的空间信息
CAM利用最后一个卷积层的特征图×权重(用GAP代替全连接层,重新训练,经过GAP分类后概率最大的神经元的权重效果已经很不错需要修改原模型的结构,导致需要重新训练该模型,大大限制了使用场景,如果模型已经上线了,或着训练的成本非常高,我们几乎是不可能为了它重新训练的。
Grad-CAM最后一个卷积层的特征图×权重(通过对特征图梯度的全局平均来计算权重①解决了CAM的缺点,适用于任何卷积神经网络;②利用特征图的梯度,可视化结果更准确和精细
Grad-CAM++1. 定位更准确
2. 更适合同类多目标的情况

GAP全局平均池化

论文:Network In Network

GAP (Global Average Pooling,全局平均池化),在上述论文中提出,用于避免全连接层的过拟合问题。全局平均池化就是对整个特征映射应用平均池化。

图1:将原本h × w × d的三维特征图,具体大小为6 × 6 × 3,经过GAP池化为1 × 1 × 3 输出值。也就是每一个channel的h × w 平均池化为一个值。特征图经过 GAP 处理后每一个特征图包含了不同类别的信息。 

GAP平均池化的操作步骤如下:

  1. 经过卷积操作和激活函数后,得到最后一个卷积层的特征图。
  2. 对每个通道的特征图进行平均池化,即计算每个通道上所有元素的平均值。这将每个通道的特征图转化为一个标量值。
  3. 将每个通道的标量值组合成一个特征向量。这些标量值的顺序与通道的顺序相同。
  4. 最终得到的特征向量可以作为分类器的输入,用于进行图像分类。

CAM

论文:Learning Deep Features for Discriminative Localization

原理:利用最后一个卷积层的特征图与经过GAP分类后概率最大的神经元权重进行叠加。

图2:解释了在CNN中使用全局平均池化(GAP)生成类激活映射(CAM)的过程:

经过最后一层卷积操作之后,得到的特征图包含多个channel,如图1中的不同颜色的3个channel,也就是在GAP之前所对应的不同的channel特征图,f_{k}就表示第k个channel的特征图。然后经过GAP处理后每个channel的特征图包含了不同类别的信息,w_{k}就表示分类概率最大的神经元(图2黑色神经元)所对应连接的第k个神经元的权重。

Grad-CAM 

Grad-CAM的前身是 CAM,CAM 的基本的思想是求分类网络某一类别得分对高维特征图 (卷积层的输出) 的偏导数,从而可以得到该高维特征图每个通道对该类别得分的权值;而高维特征图的激活信息 (正值) 又代表了卷积神经网络的所感兴趣的信息,加权后使用热力图呈现得到 CAM。

原理:Grad-CAM的关键思想是将输出类别的梯度(相对于特定卷积层的输出)与该层的输出相乘,然后取平均,得到一个“粗糙”的热力图。这个热力图可以被放大并叠加到原始图像上,以显示模型在分类时最关注的区域。

具体步骤如下:

  1. 选择网络的最后一个卷积层,因为它既包含了高级特征,也保留了空间信息。
  2. 前向传播图像到网络,得到你想解释的类别的得分。
  3. 计算此得分相对于我们选择的卷积层输出的梯度。
  4. 对于该卷积层的每个通道,使用上述梯度的全局平均值对该通道进行加权。
  5. 结果是一个与卷积层的空间维度相同的加权热力图。

因为热力图关心的是对分类有正面影响的特征,所以在线性组合的技术上加上了ReLU,以移除负值 。

w_{k}^{c}第 k 个特征图对应于类别 c 的权重,
A^{k}表示:第 k 个特征图,
Z表示特征图的像素个数,
y^{c}表示: 第c类得分的梯度,
A_{ij}^{k}表示: 第 k个特征图中坐标( i , j )位置处的像素值;

Grad-CAM代码:

import torch
import cv2
import torch.nn.functional as F
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from PIL import Image
 
class GradCAM:
    def __init__(self, model, target_layer):
        self.model = model  # 要进行Grad-CAM处理的模型
        self.target_layer = target_layer  # 要进行特征可视化的目标层
        self.feature_maps = None  # 存储特征图
        self.gradients = None  # 存储梯度
        
        # 为目标层添加钩子,以保存输出和梯度
        target_layer.register_forward_hook(self.save_feature_maps)
        target_layer.register_backward_hook(self.save_gradients)
 
    def save_feature_maps(self, module, input, output):
        """保存特征图"""
        self.feature_maps = output.detach()
 
    def save_gradients(self, module, grad_input, grad_output):
        """保存梯度"""
        self.gradients = grad_output[0].detach()
 
    def generate_cam(self, image, class_idx=None):
        """生成CAM热力图"""
        # 将模型设置为评估模式
        self.model.eval()
        
        # 正向传播
        output = self.model(image)
        if class_idx is None:
            class_idx = torch.argmax(output).item()
 
        # 清空所有梯度
        self.model.zero_grad()
 
        # 对目标类进行反向传播
        one_hot = torch.zeros((1, output.size()[-1]), dtype=torch.float32)
        one_hot[0][class_idx] = 1
        output.backward(gradient=one_hot.cuda(), retain_graph=True)
 
        # 获取平均梯度和特征图
        pooled_gradients = torch.mean(self.gradients, dim=[0, 2, 3])
        activation = self.feature_maps.squeeze(0)
        for i in range(activation.size(0)):
            activation[i, :, :] *= pooled_gradients[i]
        
        # 创建热力图
        heatmap = torch.mean(activation, dim=0).squeeze().cpu().numpy()
        heatmap = np.maximum(heatmap, 0)
        heatmap /= torch.max(heatmap)
        heatmap = cv2.resize(heatmap, (image.size(3), image.size(2)))
        heatmap = np.uint8(255 * heatmap)
        heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
        
        # 将热力图叠加到原始图像上
        original_image = self.unprocess_image(image.squeeze().cpu().numpy())
        superimposed_img = heatmap * 0.4 + original_image
        superimposed_img = np.clip(superimposed_img, 0, 255).astype(np.uint8)
        
        return heatmap, superimposed_img
 
    def unprocess_image(self, image):
        """反预处理图像,将其转回原始图像"""
        mean = np.array([0.485, 0.456, 0.406])
        std = np.array([0.229, 0.224, 0.225])
        image = (((image.transpose(1, 2, 0) * std) + mean) * 255).astype(np.uint8)
        return image
 
def visualize_gradcam(model, input_image_path, target_layer):
    """可视化Grad-CAM热力图"""
    # 加载图像
    img = Image.open(input_image_path)
    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])
    ])
    input_tensor = preprocess(img).unsqueeze(0).cuda()
 
    # 创建GradCAM
    gradcam = GradCAM(model, target_layer)
    heatmap, result = gradcam.generate_cam(input_tensor)
 
    # 显示图像和热力图
    plt.figure(figsize=(10,10))
    plt.subplot(1,2,1)
    plt.imshow(heatmap)
    plt.title('热力图')
    plt.axis('off')
    plt.subplot(1,2,2)
    plt.imshow(result)
    plt.title('叠加后的图像')
    plt.axis('off')
    plt.show()
 
# 以下是示例代码,显示如何使用上述代码。
# 首先,你需要加载你的模型和权重。
# model = resnet20()
# model.load_state_dict(torch.load("path_to_your_weights.pth"))
# model.to('cuda')
 
# 然后,调用`visualize_gradcam`函数来查看结果。
# visualize_gradcam(model, "path_to_your_input_image.jpg", model.layer3[-1])

 Grad-CAM++

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1154924.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Allegro如何恢复器件的丝印,位号

在用Allegro Layout的过程中,有时候会无意间删除掉器件的丝印,位号等,那怎么恢复呢? 被无意删除的电容丝印框,如下图。 首先点击菜单Place 点击Update Symbols...(更新器件) 跳出下面的对话框,找到对应的封装类型打勾。 然后下面四项打勾,然后点击恢复按钮即可。 恢复…

国标GB28181安防视频平台EasyGBS显示设备无法注册是什么原因?该如何解决?

国标GB28181协议视频平台EasyGBS,是基于国标GB28181协议的视频云服务平台,支持多路设备同时接入,并对多平台、多终端分发出RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。平台可提供视频监控直播、云端录像、云存储、检索回放、智能告警、语音…

三维场景视图加载cgcs2000坐标系数据

需求: 高程服务:2000坐标系 底图:天地图2000坐标系 三维模型:2000坐标系 效果图: 测试数据: 链接:https://pan.baidu.com/s/1cJbMfzkMalY06wOrmXStSQ 提取码:uz2a 高程服务…

Xcode中如何操作Git

👨🏻‍💻 热爱摄影的程序员 👨🏻‍🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻‍🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…

Tips:关于自己电脑重装python的流程

新换电脑,记录下安装python环境的流程。 1.先安装python 网上随便找教程 2.再安装pycharm https://blog.csdn.net/thefg/article/details/128881507?loginfrom_csdnhttps://blog.csdn.net/thefg/article/details/128881507?loginfrom_csdn3.再修改默认的pip为…

BI零售数据分析,告别拖延症,及时掌握一线信息

在日常的零售数据分析中,经常会因为数据量太大,分析指标太多且计算组合多变而导致数据分析报表难产,零售运营决策被迫拖延症。随着BI数据可视化分析技术的发展,智能化、可视化、自助分析的BI数据分析逐渐成熟,形成一套…

UG\NX二次开发 获取图层所在的图层类别

文章作者:里海 来源网站:《里海NX二次开发3000例专栏》 感谢粉丝订阅 感谢 大熊猫小竹子 订阅本专栏,非常感谢。 简介 获取图层所在的图层类别,比如获取20层所在的图层类别。已经封装好函数。 效果 代码 #include "me.hpp"using namespace std;//获取图层所在的…

JAVA毕业设计107—基于Java+Springboot+Vue的民宿酒店预订管理系统(源码+数据库)

基于JavaSpringbootVue的民宿酒店预订管理系统(源码数据库)107 一、系统介绍 本系统前后端分离 本系统分为用户、前台、管理员三种角色(角色菜单可以自行分配) 前台: 登录、注册、民宿浏览、民宿评价、民宿酒店下单预订、密码修改、个人信息修改。 管理后台&…

云计算助力史上首届“云上亚运”圆满成功!

201金,魔幻的BGM,以及崛起的中国科技,让杭州亚运会成功出圈。 很多网友表示太震撼了!开幕式很漂亮,杭州为了奥运造新城真豪横,看完一整个文化自信住! 赛场内外除了无数个令人感动的瞬间&#…

ReuseAndDiffuse笔记

https://arxiv.org/pdf/2309.03549.pdf https://mp.weixin.qq.com/s/pbSK4KOO2hqQU1-uwQzjBA 数据集: BLIP-2、MiniGPT4 等多模态大语言模型,对Moments-In-Time、Kinetics-700 和 VideoLT等数据集进行自动标注; Image-text datasets:平移缩…

多亏了iOS 17.2!现在自定义Action按钮,让iPhone 15秒变翻译器

iPhone 15 Pro和iPhone 15 Pro Max在发布时的头条功能之一是“Action”按钮,它取代了iPhone从一开始就存在的熟悉的静音切换按钮。 Action按钮是一个多用途的自定义按钮,可以分配给各种功能(包括静音!)。事实上,由于它可以被指定为快捷方式,所以可能性是无限的。 苹果…

同步盘简介及功能解析:了解同步盘是什么及其实用性

数字化时代,办公中用户对于文件协同的需求越来越高。同步盘无疑是近几年最热门的文件协同工具。什么是同步盘?同步盘有什么用? 什么是同步盘? 同步盘是一种可以将文件存储至云端,然后同步至用户的各个设备的文件存储协…

Pod资源限制与探针

目录 资源限制 资源限制概述 资源单位 示例 示例1 示例2 探针 探针的三种规则 Probe支持三种检查方法 示例 示例1:exec方式 示例2:httpGet方式 示例3:tcpSocket方式 示例4:就绪检测 示例5:就绪检测2 …

vue-resource发送数据请求

vue-resource是Vue用于发送数据请求的一个插件库,在Vue1.0版本时使用比较频繁,现在Vue作者更支持使用axios进行数据发送。 一、安装vue-resource库 npm i vue-resource 二、使用vue-resource插件 使用插件之前需要先对插件进行引入 三、使用$http发送…

C++设计模式_22_Chain of Resposibility 职责链(理解,已过时)

Chain of Resposibility 职责链也是属于“数据结构”模式。 职责链在今天整个软件框架中应用确实不多,甚至你已经在运用链表的逻辑处理程序,但是可能并不意识到它是职责链的模式,这不重要。 文章目录 1. 动机( Motivation )2. 模式定义3. Cha…

2. PPT提高效率的快捷键

2. PPT提高效率的快捷键 1、SHIFT家族 水平垂直移动 用鼠标单击拖动形状总会有位置的误差,要后续调整,怎样保持在水平上移动呢? 按住Shift,鼠标拖动形状 等比例放大和缩小 在放大矩形时,如果原先是个有比例的形状…

python:计算遥感时间序列数据的最大值所对应索引的影像(最大值所对用年份/day of year-DOY)

作者:CSDN @ _养乐多_ 本文将介绍使用python编程语言,进行遥感数据时间序列最大值所对应的影像索引的代码。代码中使用了numpy和gdal,通过numpy广播机制实现时间序列最大值所对应的影像索引的计算,并以NDVI时间序列数据为例。代码方便易运行,逻辑简单,速度快。只需要输入…

第46天:CSS选择器、css属性、盒子模型及浮动

CSS选择器 分组和嵌套 分组 分组选择器使用逗号隔开,所有的选择器都是并列的。 当多个元素的样式相同的时候,我们没有必要重复地为每个元素都设置样式,我们可以通过在多个选择器之间使用逗号分隔的分组选择器来统一设置元素样式。 div, p {c…

企业计算机电脑中了locked勒索病毒怎么办,勒索病毒解密,数据恢复

网络技术的不断发展,为我们的企业带来了很大的便利,大部分企业都会选择合适的办公软件系统,方便自身的生产与运营。近期,网络上的locked勒索病毒又开始攻击企业的计算机服务器了,经过10月份云天数据恢复中心对企业数据…