转载自:https://zhuanlan.zhihu.com/p/51631163

目录

  • 论文来源
  • GAP(全局平均池化层)
  • CAM(类激活映射)
    • CAM的缺陷
    • CAM的应用
  • Grad-CAM
    • 两者区别
    • 输出加softmax的影响
    • 核心代码

论文来源

《Learning Deep Features for Discriminative Localization 》(2016CVPR)

简单来说,这篇文章主要介绍了两个核心技术:

GAP(Global Average Pooling Layer) 和 CAM(Class Activation Mapping)

GAP(全局平均池化层)

在说全局平均池化之前,我想先谈一谈池化层。我们都知道,池化层的作用是正则化。比如说,这是一个VGG-16的模型。


我们可以直观的看到,从卷积层到池化层,深度不变,尺寸变小了。我们使用更小尺寸的特征图来表示输入,虽然会丢失一些信息,但是池化层可以防止过拟合,降低维度,保留主要特征的同时减少计算量,减少了参数数量

全局平均池化也一样,可以用来正则化。让我们来看一个容易的例子,我想这个相信可以帮助我们理解全局平均池化。下图展示了三种池化的方式:

首先是Max pooling(最大池化)。如图所示,最大池化是选择每个子区域的最大值,然后使用子区域的最大值表示该子区域。

Average pooling(平均池化)是指计算出子区域的平均值,用一个平均值来分别表示子区域子区域。

与平均池化类似,Global Average Pooling(全局平均池化)是指计算整个区域的平均值,仅用一个值来表示整个区域。再上图中的计算方式是取整个所有16个像素点的平均。通过下面这个图,我想我们可以更直观的理解GAP。


左边是一个特征图。高度为6,宽度为6,深度(通道数)为3。当它经过GAP,我们把每一层的参数用一个值表示,这个特征图就变成一个113的特征向量。

第一个提出GAP这个想法的,是一篇叫做《Network in Network》的论文。这篇论文发现用GAP代替全连接层,不仅可以降低维度,防止过拟合,减少大量参数,网络的性能也很不错。

GAP怎么代替全连接层呢?让我们回到一开始的例子。


如果我们使用GAP,我们必须改变网络的结构。首先我们把最大池化层和全连接层扔掉,只需要将其换成一个尺寸为11512的GAP,即把512个14*14的方针取平均,之后和原网络一样接一个softmax层就可以了。当然这只是我从理论出发举的一个小小的例子,性能是否改变还没有做过实验。

如果我们使用GAP来代替FC,优点是最小化参数数量的同时保持高性能,结构变得简单,也避免了过拟合。但是缺点是和FC相比,GAP收敛速度较慢

虽然这个GAP不是新的技术,但是在论文《Learning Deep Features for Discriminative Localization 》中,他们发现了GAP的一个作用,能保留空间信息并且定位(localization)

尽管在图像级标签上进行了训练,它仍能够区分判别图像区域。 并且在许多任务中它都可以定位判别图像区域,尽管只是训练基于解决分类任务。

CAM(类激活映射)

那么什么是类激活映射呢?CAM是一个帮助我们可视化CNN的工具。使用CAM,我们可以清楚的观察到,网络关注图片的哪块区域。比如,我们的网络识别出这两幅图片,一个是在刷牙,一个是在砍树。通过CAM这个工具,我们可以清楚的看到网络关注图片的哪一部分,根据哪一部分得到的这个结果。

The class activation map is simply a weighted linear sum of the presence of these visual patterns at different spatial locations.
By simply upsamplingthe class activation map to the size of the input image, we can identify the image regions most relevant to the particular category.

使用论文中的话来说,类激活图仅仅是在不同空间位置处存在这些视觉图案的加权线性和。 通过简单地将类激活映射上采样到输入图像的大小,我们可以识别与特定类别最相关的图像区域。如果把这段话翻译成数学语言,就是如下的公式。 f k ( x , y ) f_{k}(x, y) fk​(x,y)表示最后一个卷积层经第 k k k 个卷积核输出上某一点 ( x , y ) (x, y) (x,y) 的值, C C C 表示类别。
而类激活映射 M c M_c Mc​ 则表示所有卷积核输出上单个点对类别C贡献的概率值。


但是,上式想要成立,就得满足一个条件——输入输出满足线性加法,即:
f k ( x 1 + x 2 , y 1 + y 2 ) = f k ( x 1 , y 1 ) + f k ( x 2 , y 2 ) f_{k}(x_1+x_2, y_1+y_2)=f_{k}(x_1,y_1) + f_{k}(x_2,y_2) fk​(x1​+x2​,y1​+y2​)=fk​(x1​,y1​)+fk​(x2​,y2​)
,这里的输出指的不是模型最终的输出,而是指最后一个卷积层的输出特征图。
用代码来说明就是这样:

但是我想这样理解起来是很困难的,所以我想通过图片来解释它。

这是一个基于分类训练的CNN网络,最左边是输入,中间是很多卷积层,在最后一层卷积层之后接的是全局平均池化层(GAP),最后接一层softmax,得到输出。我们刚刚说过,GAP就是把特征图(卷积层的输出是一幅幅图)转换成特征向量(一个特征图计算得到特征向量的一个元素),所以如果这个特征图的深度是512,那么这个特征向量的长度就是512。我们的输出是Australian terrier,澳大利亚猎犬。我们用Australian terrier这个类对应的权重乘上特征图对应的层,用热力图归一化,即下面一排热力图:W1蓝色层+W2红色层+…+Wn*绿色层=类激活映射(CAM),所以说CAM是一个加权线性和。通常来说,最后一层卷积层的大小是不会等于输入大小的,所以我们需要把这个类激活映射上采样到原图大小,再叠加在原图上,就可以观察到网络得到这个输出是关注图片的哪个区域了。这也就是说可以是任意输入图片的大小和卷积层的深度。

我还想说一点是,因为CAM基于分类,所以被激活的区域是根据分类决定的,即同一个特征图,只更新不同的权重。所以即使我们使用同一张input,就像下面这个例子。


示例图片的地面真值是圆顶。五张类激活映射分别是前五名预测类别和得分。我们可以看到如果输出是宫殿,网络关注的是整块区域的。如果输出是圆顶,网络只是关注宫殿顶部。

CAM的缺陷

这项技术非常有用但是存在一些缺陷的。首先我们必须改变网络结构,例如把全连接层改成全局平均池化层,这不利于训练。第二是这是基于分类问题的一种可视化技术,用于回归问题可能就没有这么好的效果。

为了解决第一个问题,2017年出现了一种改进的技术叫Grad-CAM,Grad-CAM可以不改变网络结构进行可视化,详见这篇论文《Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization》 (2017 ICCV)。

CAM的应用

CAM也可以应用到很多方面。比如,它可以发现场景中有用的物体:

弱监督文字检测,它可以关注文字部分即使网络没有训练过文字或者任何注释框:

利用CAM的可视化技术,我认为CAM也能帮助我们对比模型,选择一个更合适的结构,下图还比较了class-specific saliency map(另一种根据梯度定位类特征区域的方法):


在日常做实验的时候也可以利用CAM帮助我们发现问题,改进结构:

这是一个简单的二分类问题,识别图片是猫还是狗,通过CAM技术,我们可以看到网络关注哪里。在第二排第一第二个结果中,网络错误的将猫识别为狗,使用CAM我们可以很快发现错误原因是对于两张图片网络忽略了猫,而关注了其他区域。所以CAM可视化这可以帮助我们理解网络。

Grad-CAM

来源论文:Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization

CAM的局限性就是网络架构里必须有GAP层,但并不是所有模型都配GAP层的。而本文就是为克服该缺陷提出的,其基本思路是目标特征图的融合权重 w k c w_{k}^{c} wkc​可以表达为梯度。另外,因为热图关心的是对分类有正面影响的特征,所以加上了relu以移除负值。其实并不一定要是分类问题,只要是可求导的激活函数,在其他问题也一样使用Grad-CAM。特征融合权重计算公式如下:

其中 y c y^c yc 为目标类别的score。 A i j k A_{ij}^{k} Aijk​为需要可视化的目标特征图的坐标。论文里证明了grad-CAM是上文利用GAP一般形式。

两者区别

Grad-CAM 是一种改进后的方法,证明了特征图坐标对某一类的重要性可用梯度表现出来,和原始的CAM有以上区别:

  1. CAM 只能用于最后一层特征图和输出之间是GAP的操作,grad-CAM可适用非GAP连接的网络结构;
  2. CAM只能提取最后一层特征图的热力图,而gard-CAM可以提取任意一层;

输出加softmax的影响

论文原文中目标类别score是指网络未经过softmax的得分,但是某些代码实现当中也使用了通过softmax后的。二者有无区别?下面我们通过公式推导一下。因为这两种做法仅仅相差一个softmax,所以对softmax的求导。假设softmax层有C个输出,记为: [ a 1 , a 2 , . . . , a c , . . . , a C ] [a^1,a^2,...,a^c,...,a^C] [a1,a2,...,ac,...,aC] 。则softmax输出为:

则输出 a c a_c ac​ 对 y c y_c yc​ 的偏导为,由于这里计算的是目标类别,所以仅需计算对应输出的偏导:

所以特征融合的权重则变成:


可以看出,二者的梯度差异就是softmax输出的多一项 a c ( 1 − a c ) a^c(1-a^c) ac(1−ac) ,而对于已经训练好的网络,该项为定值。后面特征层进行加权求和,再归一化后,该项 a c ( 1 − a c ) a^c(1-a^c) ac(1−ac) 会被消掉。所以通过softmax和不通过softmax在理论上完全一致。但是在实际应用中我发现,加上softmax后,权重 s o f t m a x − a k c softmax-a^{c}_{k} softmax−akc​ 会变得非常小,就是因为训练的充分好的网络,预测输出 a c a^c ac 的值是非常接近1的,所以 a c ( 1 − a c ) a^c(1-a^c) ac(1−ac) 的值非常非常小,存在丢失精度的风险。所以目标类别score建议使用不经过softmax的值

核心代码

仅需要对目标类别的score进行求导, 然后追踪到目标特征图的梯度, 对该梯度进行element-wise求平均(GAP操作)即获得特征融合的权重。具体如下:

# 利用onehot的形式锁定目标类别
one_hot = np.zeros((1, output.size()[-1]), dtype=np.float32)
one_hot[0][index] = 1
one_hot = torch.from_numpy(one_hot).requires_grad_(True)
# 获取目标类别的输出,该值带有梯度链接关系,可进行求导操作
one_hot = torch.sum(one_hot * output)
self.model.zero_grad()
one_hot.backward(retain_graph=True) # backward 求导
# 获取对应特征层的梯度map
grads_val = self.extractor.get_gradients()[-1].cpu().data.numpy()
target = features[-1].cpu().data.numpy()[0, :] # 获取目标特征输出
weights = np.mean(grads_val, axis=(2, 3))[0, :] # 利用GAP操作, 获取特征权重
cam = weights.dot(target.reshape((nc, h * w)))
# relu操作,去除负值, 并缩放到原图尺寸
cam = np.maximum(cam, 0)
cam = cv2.resize(cam, input.shape[2:])
# 归一化操作
batch_cams = self._normalize(batch_cams)

继 Grad-CAM 之后有陆续延伸出了以下论文,感兴趣可以自己去研究一下:

Grad-CAM++: Improved Visual Explanations for Deep Convolutional Networks
Smooth Grad-CAM++: An Enhanced Inference Level Visualization Technique for Deep Convolutional Neural Network Models
Score-CAM: Score-Weighted Visual Explanations for Convolutional Neural Networks
Ablation-CAM: Visual Explanations for Deep Convolutional Network via Gradient-free Localization

CAM使得弱监督学习发展成为可能,可以慢慢减少对人工标注的依赖,能降低网络训练的成本。通过可视化,就像往黑箱子里打了一个手电筒,让人们可以尝试去理解网络。

【计算机视觉】Class Activation Mapping(CAM、GradCAM) 特征定位、激活图相关推荐

  1. Class Activation Mapping(CAM)介绍

    CAM是什么? CAM全称Class Activation Mapping,即类别激活映射图,也称为类热力图.显著性图等.我们可以理解为图像中的信息对预测结果的贡献排名,分数越高(颜色越"热 ...

  2. 可解释性神经网络(可视化):CAM/Grad-CAM pytorch相关代码

    目录 为什么神经网络要具有可解释性 前言 类激活图(CAM,class activation map),可视化 1.1 CAM的工作原理 2. 基于梯度的CAM(Grad-CAM) pytorch 实 ...

  3. Class Activation Mapping(CAM)

    论文<Learning Deep Features for Discriminative Localization >(2016CVPR)主要介绍了两个核心技术: GAP(Global A ...

  4. Class Activation Mapping(CAM)类激活映射

    目录 本文总结: GAP(全局平均池化层) CAM(类激活映射) CAM的缺陷 CAM的应用 CVRP 2015,原文链接:http://arxiv.org/abs/1512.04150 官方开源代码 ...

  5. 简明代码介绍类激活图CAM, GradCAM, GradCAM++

      类激活图(class activation map, CAM)能够显示输入图像各区域对于分类神经网络指定类别提供信息的多少,可以帮助我们更好的理解神经网络的工作过程.关于CAM网上讲的有不少,我这 ...

  6. CNN可视化技术 -- CAM Grad-CAM详解及pytorch简洁实现

    文章目录 前言 1. CAM(Class Activation Map) 2. Grad-CAM 3. PyTorch中的hook机制 4. Grad-CAM的PyTorch简洁实现 参考资料 前言 ...

  7. Class Activation Mapping (CNN可视化) Python示例

    Class Activation Mapping 论文:CVPR2016<Learning Deep Features for Discriminative Localization> 代 ...

  8. 北京地标-自动驾驶高精度地图特征定位数据技术规范

    1 范围 本文件规范了自动驾驶高精度地图特征定位数据的建立. 本文件适用于自动驾驶高精度地图特征定位数据的生产和测试. 2 规范性引用文件 下列文件对于本文件的应用是必不可少的.凡是注日期的引用文件, ...

  9. python二维码特征定位与识别

    python二维码特征定位与识别 1. 项目背景 2.引入相关库 3. 图像预处理 4. 识别位置探测图像 1. 项目背景 在使用手机等移动设备对发票中的二维码进行扫描识别的时候,经常会出现这样的情况 ...

最新文章

  1. Tomcat内存溢出解决方法
  2. RabbitMQ核心概念
  3. Linux系统日志分析与管理(14)
  4. 关于html5和css3的新特性
  5. 【趣说】IT人的职场艰难,全藏在气氛组里!
  6. hdu-5063 Operation the Sequence
  7. 编译服务器home文件夹,离线安装FastDFS-过程填坑
  8. linux上点时间延时,Linux上时间和定时器
  9. ROS开发时的服务器启动命令
  10. 经典:比尔·盖茨的创业智慧
  11. 传统软件测试的互联网化改造
  12. lex yacc 入门教程(3)正则表达式和lex变量及函数
  13. java jxta_JXTA——JAVA P2P网络编程技术(入门篇) | 学步园
  14. 白群晖图文版阿里云域名解析IPV6远程访问方法
  15. python新年快乐代码_新年快乐! python实现绚烂的烟花绽放效果
  16. 089【RTKLIB源码之postpos-5】pppos
  17. pairing-friendly曲线家族
  18. YOLOv4论文解读
  19. ios项目编译错误:error: Multiple commands produce 'Faun.app/Assets.car'
  20. 自动驾驶的分级,感知与规划基本意义

热门文章

  1. ExtJS 学习专题-如何应用ExtJS
  2. 可选操作(UnsupportedOperationException)
  3. 高中音乐教学计算机,浅析多媒体计算机技术在高中音乐课的应用
  4. HCNA——Telnet,Ftp,Switch
  5. Floats_Flexbox_Grid_The_Progression_of_CSS_layouts by Kevin Powell
  6. 简单BroadcastRecevier
  7. 【PyTorch】语言模型/Language model
  8. mixamo和ue小白人映射关系以及让mixamo绑定的人物在场景中运动的多种方法实践...
  9. (个人学习)资金托管与资金存管的区别
  10. xib报错“nib must contain exactly one top level object which must be a UITableViewCell instance”