Grad_CAM

文章:

1,Grad-CAM: Why did you say that?

2,Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization

 

目标:通过全图的热力图显示出图中重点部位,表示该部位是将图形判断为某类的依据。

 

代码:pytorch:

1,https://github.com/utkuozbulak/pytorch-cnn-visualizations;

2, https://github.com/jacobgil/pytorch-grad-cam

另有keras和tensorflow以及文章提供的源码。

 

阅读记录参考:

1,https://www.jianshu.com/p/1d7b5c4ecb93

2,http://spytensor.com/index.php/archives/20/

 

 

 

另对于理解上的记录:

由于CAM通过GAP(Global Average Pooling)需要最后一层卷积层)强制生成了和目标类别数量一致的特征图,这样就能通过GAP得到与后一层的fc层之间的权重,也就是gap前一层的每个特征图都有权重,这样就可以利用类似下图

Grad_CAM_第1张图片

这种方式得到某个类别的解释。但需要更改模型结构,因此,如何在不更改结构的情况下求得权重就是Grad-CAM做的事情。

 

Grad-CAM用梯度的全局平均来计算权重。针对某类C,需要获得判断为c的解释,则首先要获得最后一层输入softmax层之前的类别c的分数值,假设最后一层卷积层(语义信息最丰富)特征图为A,大小为20维,则通过类别的数值反向传播到对应的卷积层,得到对应的梯度,梯度尺寸与特征图A一致,再将任意单个维度的梯度求平均(也就是结果就等于通道维数的向量),即可得到对应通道的权重。最后类似CAM那样通过加权和的方式就可以得到热力图的原始特征图,再经过处理得到热力图。

 

 

注意点:

1,由于用的pytorch,故而模型创建或者Grad-CAM模型书写的时候,将模型分成 model.features和 model.classifier为最佳,方便使用,不这样操作也可以,就是算法模型部分针对不同的算法改的多。

2,在特征提取模块,利用model.features提取对应层特征的时候,需要像下面这样保存梯度:

class FeatureExtractor():
    """ Class for extracting activations and
    registering gradients from targetted intermediate layers """
    def __init__(self, model, target_layers):
        self.model = model
        self.target_layers = target_layers
        self.gradients = []

    def save_gradient(self, grad):
       self.gradients.append(grad)

    def __call__(self, x):
        outputs = []
        self.gradients = []
        for name, module in self.model._modules.items():
            x = module(x)
            if name in self.target_layers: # 保留固定层特征
                x.register_hook(self.save_gradient)  # 保存梯度
                outputs += [x]
        return outputs, x

 

3,softmax前一层的类别分数是在model.features链接 model.classifier后的结果,也就是模型从头到脚的输出,不是单纯特征图的输出。

 

4,对于不同模型,需要更改模型内部的模块,有时间可以改成自适应的。

 

你可能感兴趣的:(A)