可解释性(一)之CAM和Grad_CAM

可视化

最近在学习可解释性方面的内容,主要是用cam做可解释性,因此想要系统地学习一下。
参考:
keras CAM和Grad-cam原理简介与实现
GAP CAM Grad-CAM Grad-CAM++的解释
pytorch实现所有cam衍生
ECG-Grad-CAM

CAM

  1. 将原模型的结构修改:利用GAP(Global Average Pooling)替换掉了全连接层

  2. 重新进行训练

  3. 经过GAP之后,得到了最后一个卷积层每个特征图的均值,均值经过加权和得到输出某个类别的权重

  4. 对于一个特定的类c,最终的分类分数 Y c Y^c Yc可以写成它经过全局平均池化的最后一个卷积层特征映射 A k A^k Ak的线性组合
    在这里插入图片描述

  5. 因此,CAM需要做的就是:在这里插入图片描述
    找出某个类别每个特征图对应的权重,将特征图与权重进行加权和后叠加到原图就可以得到重点信息

CAM通过使用为给定图像生成的最后一个卷积层的激活映射,为每个c类训练一个线性分类器来估计这些权重 w c k w^k_c wck。但这将其解释能力限制在具有GAP倒数层的CNN上,并且需要在初始模型训练后再训练多个线性分类器(每个类一个)。
在这里插入图片描述

求解heatmap流程图:

  1. 求出图像经过特征提取后得到的最后一层卷积的特征图
  2. 所有特征图在全连接分类的权重不一样,利用反向传播求出每张特征图的权重,CAM 方法要求模型必须使用GAP层,因为利用GAP层可以有更强的可解释性,GAP后每张特征图对应一个权重,选择softmax层值最大得到节点反向传播,将梯度作为权重
  3. 用每张特征图乘以权重得到带权重的特征图,在第三维求均值,relu激活,归一化处理(避免有些值不在0-255范围内)。其中最重要的是relu激活(relu只保留大于0的值),relu后只保留该类别有用的特征。正数认为是该类别有用的特征,负数是其他类别的特征(或无用特征)。如果没有relu,定位图谱显示的不仅仅是某一类的特征。而是所有类别的特征

缺点:

CAM要求修改原模型的结构,导致需要重新训练该模型,这大大限制了它的使用场景。

Grad_CAM

Grad-cam实现了不改变模型结构的求heatmap的方法。具体流程还是上述的流程,只是巧妙的求出来每张特征图的权重。
求解heatmap流程图:

  1. 求出图像经过特征提取后得到的最后一层卷积的特征图
  2. 所有特征图在全连接分类的权重不一样,利用反向传播求出每张特征图的权重,Grad-cam的思想是选择softmax值最大的节点(对应置信度最高的类别)反向传播,对最后一层卷积层求梯度,每张特征图的梯度的均值作为该张特征图的权重。
  3. 用每张特征图乘以权重得到带权重的特征图,在第三维求均值,relu激活,归一化处理(避免有些值不在0-255范围内)。
    在这里插入图片描述

为了获得细粒度的像素尺度表示,Grad-CAM显著maps被上采样,并通过点乘与Guided Backpropagation生成的可视化结果融合。这种可视化被称为 Guided Grad-CAM

def explain(input, model, layer):
    #input为模型输入,model为原始模型以及参数,layer为最后一层卷积层
    grad_model = tf.keras.models.Model([model.inputs],[model.get_layer(layer).output,model.output])
    inputs = input
    class_idx = np.argmax(pred)#找出softmax值最大的节点
    with tf.GradientTape() as tape:
        conv_outputs, predictions = grad_model(inputs)#得到卷积层输出和最终输出
        loss = predictions[:, class_idx]
    grads = tape.gradient(loss, conv_outputs)#对最后一层卷积层求梯度
    guided_grads = (tf.cast(conv_outputs > 0, "float32") * tf.cast(grads > 0, "float32") * grads)#guided描边操作
    output = conv_outputs[0]
    guided_grad = guided_grads[0]
    weights = tf.reduce_mean(guided_grad, axis=(0, 1))#每张特征图的梯度的均值作为该张特征图的权重
    heatmap = tf.reduce_sum(tf.multiply(weights, output), axis=-1)#得到带权重的特征图,在第三维求均值

    image = np.uint8(inputs)
    image = np.squeeze(image)
    heatmap = cv2.resize(heatmap.numpy(), tuple([image.shape[1], image.shape[0]]))
    heatmap = np.maximum(heatmap, 0)#relu激活
    max_heat = np.max(heatmap)
    if max_heat == 0:
        max_heat = 1e-10
    heatmap /= max_heat
    heatmap = (heatmap - np.min(heatmap)) / (heatmap.max() - heatmap.min())#归一化
    
    return heatmap

缺点:
如果图像包含多个相同的类,Grad-CAM就不能正确地定位图像中的对象。这是一个严重的问题,因为在现实世界中,同一对象在图像中多次出现是非常常见的,但这个时候Grad_CAM无法很好定位

后面可以继续学习一下Grad_CAM++和Score_CAM

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值