0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

CAM与Grad-CAM++可视化CNN方式的代码实现和对比

冬至子 来源:Tanishq Sardana 作者:Tanishq Sardana 2023-06-09 16:53 次阅读

当使用神经网络时,我们可以通过它的准确性来评估模型的性能,但是当涉及到计算机视觉问题时,不仅要有最好的准确性,还要有可解释性和对哪些特征/数据点有助于做出决策的理解。模型专注于正确的特征比模型的准确性更重要。

理解CNN的方法主要有类激活图(Class Activation Maps, CAM)、梯度加权类激活图(Gradient Weighted Class Activation Mapping, Grad-CAM)和优化的 Grad-CAM( Grad-CAM++)。它们的思想都是一样的:如果我们取最后一个卷积层的输出特征映射并对它们施加权重,就可以得到一个热图,可以表明输入图像中哪些部分的权重高(代表了整个图的特征)。

Class Activation Maps

CAM是一种将CNN所看到或关注的内容可视化并为我们生成类输出的方法。

通过将图像传递给CNN,我们获得了相同图像的低分辨率特征图。

CAM的思想是,删除那些完全连接的神经网络,并用全局平均池化层代替它们,特征图中所有像素的平均值就是它的全局平均值。通过将GAP应用于所有特征映射将获得它们的标量值。

对于这些标量值,我们应用表明每个特征映射对特定类重要性的权重,权重是通过训练一个线性模型来学习的。

激活图将是所有这些特征图的加权组合。

defgenerate_cam(input_model, image, layer_name='block5_conv3', H=224, W=224):
     
     cls=np.argmax(input_model.predict(image)) # Obtain the predicted class
     conv_output=input_model.get_layer(layer_name).output#Get the weights of the last output layer
     
     last_conv_layer_model=keras.Model(input_model.inputs, conv_output) #Create a model with the last output layer    
     class_weights=input_model.get_layer(layer_name).get_weights()[0] # Get the weights of the output layer\\
     class_weights=class_weights[0,:,:,:]
     class_weights=np.mean(class_weights, axis=(0, 1))
     
     
     last_conv_output=last_conv_layer_model.predict(image) #The feature map output from last output layer
     last_conv_output=last_conv_output[0, :]
     cam=np.dot(last_conv_output, class_weights)
     
     
     cam=zoom(cam, H/cam.shape[0]) #Spatial Interpolation/zooming to image size
     cam=cam/np.max(cam) #Normalizing the gradcam
     
     returncam

但是CAM有一个最大的缺点就是必须重新训练模型才能得到全局平均池化后得到的权重。对于每一类必须学习一个线性模型。也就是说将有n个权重(等于最后一层的过滤器)* n个线性模型(等于类)。并且还必须修改网络架构来创建CAM这对于现有的模型来说改动太大,所以Grad-CAM解决了这些缺点。

Grad-CAM( Gradient Weighted Class Activation Mapping)

Grad-CAM背后的思想是,依赖于最后一个卷积层的特征映射中使用的梯度,而不是使用网络权重。这些梯度是通过反向传播得到的。

这不仅解决了再训练问题,还解决了网络架构修改问题,因为只使用梯度而不使用GAP层。

我们只要在最后一个卷积层中计算用于顶部预测类的特征映射的梯度。然后我们对这些权重应用全局平均。权重与最后一层得到的特征映射的点积就是Grad-CAM输出。然后通过在其上应用ReLU,识别图像中仅对我们的图像有积极贡献的部分。

最后就是将Grad-CAM调整为图像大小并规范化,以便它可以叠加在图像上。

defgrad_cam(input_model, image, layer_name='block5_conv3',H=224,W=224):
     
     cls=np.argmax(input_model.predict(image)) #Get the predicted class
     y_c=input_model.output[0, cls] #Probability Score
     conv_output=input_model.get_layer(layer_name).output#Tensor of the last layer of cnn
     grads=K.gradients(y_c, conv_output)[0] #Gradients of the predicted class wrt conv_output layer
     
     get_output=K.function([input_model.input], [conv_output, grads]) 
     output, grads_val=get_output([image]) #Gives output of image till conv_output layer and the gradient values at that level
     output, grads_val=output[0, :], grads_val[0, :, :, :]
     
     
     weights=np.mean(grads_val, axis=(0, 1)) #Mean of gradients which acts as our weights
     cam=np.dot(output, weights) #Grad-CAM output
     
     cam=np.maximum(cam, 0) #Applying Relu
     cam=zoom(cam,H/cam.shape[0]) #Spatial Interpolation/zooming to image size
     cam=cam/cam.max() #Normalizing the gradcam
     
     returncam

Grad-CAM++

Grad-CAM++不仅包括gradcam技术,它增加了引导反向传播,只通过类别预测的正梯度进行反向传播。

Grad-CAM++这种优化的原因是因为Grad-CAM在识别和关注多次出现的对象或具有低空间占用的对象方面存在问题。

所以Grad-CAM++给予与预测类相关的梯度像素更多的重要性(正梯度),通过使用更大的因子而不是像Grad-CAM那样使用常数因子来缩放它们。这个比例因子在代码中用alpha表示。

defgrad_cam_plus(input_model, image, layer_name='block5_conv3',H=224,W=224):
     
     cls=np.argmax(input_model.predict(image))
     y_c=input_model.output[0, cls]
     conv_output=input_model.get_layer(layer_name).output
     grads=K.gradients(y_c, conv_output)[0]
     
     first=K.exp(y_c)*grads#Variables used to calculate first second and third gradients
     second=K.exp(y_c)*grads*grads
     third=K.exp(y_c)*grads*grads*grads
 
     #Gradient calculation
     get_output=K.function([input_model.input], [y_c,first,second,third, conv_output, grads])
     y_c, conv_first_grad, conv_second_grad,conv_third_grad, conv_output, grads_val=get_output([img])
     global_sum=np.sum(conv_output[0].reshape((-1,conv_first_grad[0].shape[2])), axis=0)
 
     #Used to calculate the alpha values for each spatial location
     alpha_num=conv_second_grad[0]
     alpha_denom=conv_second_grad[0]*2.0+conv_third_grad[0]*global_sum.reshape((1,1,conv_first_grad[0].shape[2]))
     alpha_denom=np.where(alpha_denom!=0.0, alpha_denom, np.ones(alpha_denom.shape))
     alphas=alpha_num/alpha_denom
     
     #Calculating the weights and alpha's which is the scale at which we multiply the weights with more importance
     weights=np.maximum(conv_first_grad[0], 0.0)
     alpha_normalization_constant=np.sum(np.sum(alphas, axis=0),axis=0)
     alphas/=alpha_normalization_constant.reshape((1,1,conv_first_grad[0].shape[2])) #Normalizing alpha
     
     #Weights with alpha multiplied to get spatial importance
     deep_linearization_weights=np.sum((weights*alphas).reshape((-1,conv_first_grad[0].shape[2])),axis=0)
     
     grad_CAM_map=np.sum(deep_linearization_weights*conv_output[0], axis=2) #Grad-CAM++ map
     cam=np.maximum(grad_CAM_map, 0)
     cam=zoom(cam,H/cam.shape[0])
     cam=cam/np.max(cam) 
     
     returncam

结果对比

这里我们使用VGG16,对一些图像进行了比较,下图中可以看到CAM、Grad-CAM和Grad-CAM++的看法有多么不同。虽然它们都主要集中在它的上半身,但Grad-CAM++能够将其整体视为重要部分,而CAM则将其某些部分视为非常重要的特征,而将一些部分视为其预测的辅助。而Grad-CAM只关注它的冠和翅膀作为决策的重要特征。

对于这张风筝的图像,CAM显示它关注的是除了风筝之外的所有东西(也就是天空),但是使用gradcam则看到到模型关注的是风筝,而gradcam ++通过增加重要的突出空间进一步加强了这一点。这里需要注意的是,模型错误地将其分类为降落伞,但风筝类紧随其后。也就是说,其实CAM更好的捕捉到了错误的原因。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 神经网络
    +关注

    关注

    42

    文章

    4575

    浏览量

    98792
  • 过滤器
    +关注

    关注

    1

    文章

    407

    浏览量

    19003
  • 计算机视觉
    +关注

    关注

    8

    文章

    1601

    浏览量

    45634
  • GAP
    GAP
    +关注

    关注

    0

    文章

    15

    浏览量

    8243
收藏 人收藏

    评论

    相关推荐

    何谓单片机编程的可视化?

    何谓单片机编程的可视化?可视化编程就是提供给用户可视化的器件模块配置界面使用户在不用关心具体器件工作原理和设置的情况下直接生成所要配置的器件初始
    发表于 07-08 16:53

    单片机可视化编程

    单片机的可视化编程是不是指在环境下避开复杂的指令编写而通过图形的方式产生指令代码?-在可视化的条件下是否可以观察到仿真的结果?是的。不过仿真的结果不能够直接观察到,而要通过将生成的
    发表于 07-08 16:56

    可视化MES系统软件

    和客户都会造成损失,为了更好的满足客户需求、实现企业信息,目前企业制造过程中主要还存在以下需求:(1)数据可视化方面。MES系统软件之所以能有效的监控整个车间的生产过程,主要是通过对制造过程中
    发表于 11-30 19:55

    利用Keras实现四种卷积神经网络(CNN)可视化

    Keras实现卷积神经网络(CNN)可视化
    发表于 07-12 11:01

    CAM350进行IPC网表对比

    CAM350进行IPC网表对比,可以检查短路,开路等问题。
    发表于 09-04 09:54

    如何把AD中非可视化区域物件移到可视化区域?

    AD中非可视化区域物件怎么移到可视化区域???
    发表于 09-10 05:36

    python数据可视化的方法和代码

    Python数据可视化汇总
    发表于 10-14 14:59

    三维可视化的应用和优势

    的整体态势。  比如设备在偏僻区域(海下、深山、沙漠、分布全国各地等),可以实现无人检测,无需消耗人力物力进行检测,通过三维数据的分析可以直观的探测出设备状态和产能。  设备运行可视化:根据图像
    发表于 12-02 11:52

    如何用Verilog HDL设计CAM

    CAM具有什么功能?基于移位寄存器的CAM的设计基于移位寄存器的CAM的Verilog HDL实现
    发表于 04-13 06:28

    代码可视化开发理念在物联网APP开发 精选资料分享

    代码可视化开发理念在物联网APP开发,云编排式物联APP开发平台可通过云端可视化编排开发,边端远程自动部署,云边协同管理运维的方式
    发表于 07-19 06:14

    基于VSCode的嵌入式开发的可视化代码调试方法分享

    ,经常会遇到问题不是那么明显,不方便通过加打印的方式进行排查的问题,并且加打印排查的方式较为低效,使得调试过程极为痛苦。可视化调试效率一直比命令行调试要方便和快捷很多,而嵌入式开发由于目标程序在开发板上,而不在编写
    发表于 12-14 07:54

    如何在Ubuntu下实现可视化代码跟踪调试

    目录一、在Ubuntu下实现可视化代码跟踪调试1.1 安装VSCode1.2 配置调试和编译文件一、在Ubuntu下实现可视化
    发表于 12-14 07:02

    Keras可视化神经网络架构的4种方法

    pip install graphviz然后我们创建一个模型,并用这4个包来进行可视化:在实际使用时我们希望的是通过可视化对比模型架构,所以这里定义三个具有不同超参数 CNN 模型
    发表于 11-02 14:55

    CNN的三种可视化方法介绍

    导读 对神经网络进行可视化分析不管是在学习上还是实际应用上都有很重要的意义,基于此,本文介绍了3种CNN可视化方法:可视化中间特征图,可视化
    的头像 发表于 12-29 11:49 2169次阅读

    基于Grad-CAM与KL损失的SSD目标检测算法

    基于Grad-CAM与KL损失的SSD目标检测算法 来源:《电子学报》,作者侯庆山等 摘 要: 鉴于Single Shot Multibox Detector (SSD)算法对中小目标检测
    发表于 01-21 08:40 798次阅读