用keras来实现Grad-CAM

  • Grad-CAM是什么?
    英语的全称是Gradient-weighted Class Activation Mapping
    直接翻译是【梯度加权分类激活映射】
    简单说就是用CNN做图像分类的时候,到底是根据图像的哪里来判断属于这个分类的,给明确映射出来。
    如下图被分类为狗(拳师犬),CNN是根据哪里来判断是狗的呢?我们使用Grad-CAM可以看出是根据头部特征来判断的。 用keras来实现Grad-CAM_第1张图片

  • Grad-CAM的实现方法
    整体流程如下图,算法的主要的难点在于最后卷积层的梯度算出,也就是下图红框部分。
    梯度这个词数学基础不太扎实的同学可能已经忘记了。说说几个词
    【导数】指的是一元函数中,函数y=f(x)在某一点处沿x轴正方向的变化率;
    【偏导数】指的是多元函数中,函数y=f(x1,x2,…,xn)在某一点处沿某一坐标轴(x1,x2,…,xn)正方向的变化率。
    【方向导数】不止是坐标轴方向的变化率,坐标轴以外的其他方向的变化率
    【梯度】众多方向导数中最大的那个向量
    具体可以参考一下文章导数,偏导,方向倒数,梯度
    关于反向梯度的算出方法,可以参考我的另一篇文章 一步一步教你反向传播
    用keras来实现Grad-CAM_第2张图片

  • 代码实现

  • 代码和测试图像我上传到了git-hub上,请参考- git-hub-grad-cam
    核心函数实现如下.其中的梯度算出,利用了tensorflow的gradients函数。这个函数使用反向自动微分方法,可以自动算出梯度。有兴趣的同学可以研究一下。

def grad_cam(model, x, category_index, layer_name):
    """
    Args:
       model: model
       x: image input
       category_index: category index
       layer_name: last convolution layer name
    """
    # 取得目标分类的CNN输出值,也就是loss
    class_output = model.output[:, category_index]

    # 取得想要算出梯度的层的输出
    convolution_output = model.get_layer(layer_name).output
    # 利用gradients函数,算出梯度公式
    grads = K.gradients(class_output, convolution_output)[0]
    # 定义计算函数(tensorflow的常见做法,与一般开发语言不同,先定义计算逻辑图,之后一起计算。)
    gradient_function = K.function([model.input], [convolution_output, grads])
    # 根据实际的输入图像得出梯度张量(返回是一个tensor张量,VGG16 是一个7X7X512的三维张量)
    output, grads_val = gradient_function([x])
    output, grads_val = output[0], grads_val[0]

    # 取得所有梯度的平均值(维度降低:7X7X512 -> 512)
    weights = np.mean(grads_val, axis=(0, 1))
    # 把所有平面的平均梯度乘到最后卷积层(vgg16最后一层是池化层)上,得到一个影响输出的梯度权重图
    cam = np.dot(output, weights)

    # 把梯度权重图RGB化
    cam = cv2.resize(cam, (x.shape[1], x.shape[2]), cv2.INTER_LINEAR)
    cam = np.maximum(cam, 0)
    heatmap = cam / np.max(cam)

    # Return to BGR [0..255] from the preprocessed image
    image_rgb = x[0, :]
    image_rgb -= np.min(image_rgb)
    image_rgb = np.minimum(image_rgb, 255)

    cam = cv2.applyColorMap(np.uint8(255 * heatmap), cv2.COLORMAP_JET)
    cam = np.float32(cam) + np.float32(image_rgb)
    cam = 255 * cam / np.max(cam)
    return np.uint8(cam), heatmap
  • 参考
    grad-cam论文

你可能感兴趣的:(人工智能)