《Python深度学习》第五章-6(可视化类激活图)读书笔记

《Python深度学习》第五章-6(可视化类激活图)读书笔记

卷积神经网络学到的表示非常适合可视化,很大程度上是因为它们是 视 觉 概 念 的 表 示 \color{red}视觉概念的表示 。接下来介绍3种可视化方法。

  • 事 中 \color{blue}事中 可 视 化 卷 积 神 经 网 络 的 中 间 输 出 ( 中 间 激 活 ) \color{red}可视化卷积神经网络的中间输出(中间激活) 有助于理解卷积神经网络连续的层如何对输入进行变换,也有助于初步了解卷积神经网络每个过滤器的含义。
  • 事 前 \color{blue}事前 可 视 化 卷 积 神 经 网 络 的 过 滤 器 \color{red}可视化卷积神经网络的过滤器 有助于精确理解卷积神经网络中每个过滤器容易接受的视觉模式或视觉概念。
  • 事 后 \color{blue}事后 可 视 化 图 像 中 类 激 活 的 热 力 图 \color{red}可视化图像中类激活的热力图 有助于理解图像的哪个部分被识别为属于某个类别,从而可以定位图像中的物体。

5.4.3 可视化类激活的热力图

《Python深度学习》第五章-6(可视化类激活图)读书笔记_第1张图片

5.4.3.1 类激活热力图的相关定义

  1. What ?——什么是类激活热力图的可视化?
    • 类激活图(Class activation map,简称CAM),指 对 输 入 图 像 \color{red}对输入图像 生成类激活的热力图。它是 与 特 定 输 出 类 别 \color{red}与特定输出类别 相关的 二 维 特 征 分 数 网 格 \color{red}二维特征分数网格 网 格 每 个 位 置 表 示 对 该 类 别 的 重 要 程 度 \color{red}网格每个位置表示对该类别的重要程度
    • 对于一张输入到CNN模型且被分类成 " 狗 " \color{blue}"狗" ""的图片,该技术 可 以 以 热 力 图 形 式 告 诉 我 们 图 片 中 的 每 个 位 置 \color{red}可以以热力图形式告诉我们图片中的每个位置 " 狗 " \color{blue}"狗" ""类的 相 似 程 度 \color{red}相似程度
  2. Why ?——为什么使用类激活热力图的可视化?
    有助于了解一张原始图像的哪一个局部 位 置 \color{red}位置 让CNN模型做出了最终的 分 类 决 策 \color{red}分类决策
  3. How ?——如何实现类激活热力图的可视化?
    • 来自佐治亚理工、脸书AI研究团队的Ramprasaath R.Selvaraju等人于2017年ICCV发表的《 G r a d − C A M \color{red}Grad-CAM GradCAM: visual explanations from deep networks via grtadient based localization》,提出了一种可视化类激活热力图的解决方案。
    • 论文地址:http://openaccess.thecvf.com/contentICCV_20l7/papers/SelvarajuGrad-CAM_Visual_ExplanationsICCV_20l7-paper.pdf
  4. 举例说明
    • 促使模型对左图做出自行车分类预测的主要特征区域集中在车把手。
    • 促使模型对左图做出棒球棒分类预测的主要特征区域集中在棒腹部。
      《Python深度学习》第五章-6(可视化类激活图)读书笔记_第2张图片

5.4.3.2 类激活热力图的基本解决思路

  1. Grad-CAM基本原理(可以概括为 3 个 变 量 \color{red}3个变量 3+ 2 种 运 算 \color{red}2种运算 2
    • 给定一张输入图像,对于一个 卷 积 层 的 输 出 特 征 图 \color{red}卷积层的输出特征图 ,用 类 别 \color{red}类别 相对于 通 道 \color{red}通道 梯 度 \color{blue}梯度 对这个特征图中的每个通道进行 加 权 \color{blue}加权
    • 以VGG16模型为例
      《Python深度学习》第五章-6(可视化类激活图)读书笔记_第3张图片
  2. 简要概括 3 个 变 量 \color{red}3个变量 3+ 2 种 运 算 \color{red}2种运算 2
    • 3 个 变 量 \color{red}3个变量 3
      • 卷积层输出特征,conv-layer.output
      • 卷积层输出特征中的每个通道,conv-layer.output[i]
      • 特定输出类别,model.output[i]
    • 2 种 运 算 \color{red}2种运算 2
      • 求梯度,K.gradients(y,x), K.mean(gradients)
      • 乘梯度,conv-layer.outputL[i]* gradients

5.4.3.3 类激活热力图的任务流

《Python深度学习》第五章-6(可视化类激活图)读书笔记_第4张图片

  1. 基本步骤

    • s t e p    1    指 定 入 \color{red}step\;1 \;指定入 step1指定一张待分类图片输入到模型并预处理
    • s t e p    2    求 梯 度 \color{red}step\;2\;求梯度 step2获取模型输出相对于最后一卷积层激活输出的梯度
      k.gradients(模型输出,最后一个卷积层激活输出)
      k.function(模型输入,(梯度均值,最后一个卷积层激活输出))
      
    • s t e p    3    乘 梯 度 \color{red}step\;3\;乘梯度 step3表征出最后卷积层激活输出各点位对模型决策分类的重要程度,并进行预处理,记得到类激活图
      最后一个卷积层输出 *= 梯度均值
      再求均值
      
    • s t e p    4    染 画 布 \color{red}step\;4\;染画布 step4将调节后的卷积激活输出渲染为热力效果
      cv2.applyColorMap
      
    • s t e p    5 可 视 化 \color{red}step\;5可视化 step5将原始图像与渲染后的热力图叠加后再可视化
  2. 步骤图形化

    《Python深度学习》第五章-6(可视化类激活图)读书笔记_第5张图片

5.4.3.4 类激活热力图的代码

步骤 指 定 入 − − > 定 损 数 − − > 求 梯 度 − − > 乘 梯 度 − − > 染 画 布 − − > 可 视 化 \color{red}指定入-->定损数-->求梯度-->乘梯度-->染画布-->可视化 >>>>>

  1. 指 定 入 \color{red}指定入

    from tensorflow.keras.applications.vgg16 import VGG16
    from tensorflow.keras import backend as K
    K.clear_session()
    # 特别注意,在之前的实验中,我们都把顶层的分类器丢弃掉了,include_top = False
    ## 加载预训练模型
    model = VGG16(weights='imagenet')
    
    ## 加载指定分类图片
    from tensorflow.keras.preprocessing import image
    from tensorflow.keras.applications.vgg16 import preprocess_input, decode_predictions
    import numpy as np
    
    # The local path to our target image
    img_path = 'C:\\Users\\Administrator\\HQR_Python_learning\\creative_commons_elephant.jpg'
    
    ## 图片预处理
    # `img` is a PIL image of size 224x224
    img = image.load_img(img_path, target_size=(224, 224))
    
    # 一转,`x` is a float32 Numpy array of shape (224, 224, 3)
    x0 = image.img_to_array(img)
    
    # 二扩,We add a dimension to transform our array into a "batch"
    # of size (1, 224, 224, 3)
    x1 = np.expand_dims(x0, axis=0)
    
    # 三标,Finally we preprocess the batch
    # (this does channel-wise color normalization)
    x = preprocess_input(x1)
    
    • 预测图片分类
      >>>preds = model.predict(x)
      >>>print('Predicted:', decode_predictions(preds, top=3)[0])
      Predicted: [('n02504458', 'African_elephant', 0.909421), ('n01871265', 'tusker', 0.086182885), ('n02504013', 'Indian_elephant', 0.0043545826)]
      
  2. 求 梯 度 \color{red}求梯度

    import tensorflow as tf
    tf.compat.v1.disable_eager_execution()
    
    #获取非洲象预测输出
    african_elephant_output = model.output[:,386]
    
    #获取最后一个卷积层激活输出
    last_conv_layer = model.get_layer('block5_conv3')
    #求模型输出针对最后一个卷积层激活输出的梯度
    #非洲象类别相对于 block5_conv3输出特征图的梯度
    # grad is (None,14,14,512)
    grads= K.gradients(african_elephant_output,
    					last_conv_layer.output)[0]
    # 均值化处理梯度
    # 形状为 (512,) 的向量,每个元素是特定特征图通道的梯度平均大小
    pooled_grads = K.mean(grads, axis=(0,1, 2))
    
    #建立模型输出、最后一个卷积层激活输出、梯度均值三者之间的函数关系
    #访问刚刚定义的量:对于给定的样本图像,pooled_grads 和 block5_conv3 层的输出特征图
    # model.input:(None, 224, 224, 3);last_conv_layer.output[0]:(14, 14, 512)
    iterate =K.function([model.input], [pooled_grads,last_conv_layer.output[0]])
    # pooled_grads:(512,);conv_layer_output_value:(14, 14, 512)
    pooled_grads_value,conv_layer_output_value =iterate([x])
    
  3. 乘 梯 度 \color{red}乘梯度

    import matplotlib.pyplot as plt
    for i in range(512):
        # conv_layer_output_value[:, :, i]:(14*14);pooled_grads_value[i]:()
        conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
    
    # 得到的特征图的逐通道平均值即为类激活的热力图
    # heatmap:(14*14)
    heatmap = np.mean(conv_layer_output_value, axis=-1)
    # 为了将热力图可视化,去除所有负数
    heatmap = np.maximum(heatmap, 0)
    # 归一化处理
    heatmap /= np.max(heatmap)
    # 展现
    plt.matshow(heatmap)
    

    《Python深度学习》第五章-6(可视化类激活图)读书笔记_第6张图片

  4. 染 画 布 、 可 视 化 \color{red}染画布、可视化
    安装cv2:

    • pip install opencv-python (如果只用主模块,使用这个命令安装)
    • pip install opencv-contrib-python (如果需要用主模块和contrib模块,使用这个命令安装)
    import cv2
    # 用 cv2 加载原始图像
    # img:(600, 899, 3)
    img = cv2.imread(img_path)
    # 将热力图的大小调整为与原始图像相同
    #heatmap为[0,1]之间的浮点数,特别注意:cv2.resize(img, (x轴向长度,y轴向长度))
    # heatmap:(600, 899, 3)
    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
    # 将热力图应用于原始图像
    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
    # 将热力图转换为 RGB 格式
    heatmap = np.uint8(255 * heatmap)
    # 将热力图与原始图像叠加,0.5表示渲染强度,
    # 有超出(0,255)范围的,如果需要可视化,则需要clip裁剪
    superimposed_img = heatmap * 0.5 + img
    cv2.imwrite('C:\\Users\\Administrator\\HQR_Python_learning\\elephant_cam.jpg', superimposed_img)
    

    《Python深度学习》第五章-6(可视化类激活图)读书笔记_第7张图片

    通过梯度类激活热力图可以看到“非洲象”分类决策依据主要来自于图片中象的鼻部、嘴部、眼部、耳部等面部区域。

总结

  1. 各个丈量的含义
  2. 这种可视化方法回答了两个重要问题:
    • 网 络 为 什 么 会 认 为 这 张 图 像 中 包 含 一 头 非 洲 象 \color{red}网络为什么会认为这张图像中包含一头非洲象 ?
    • 非 洲 象 在 图 像 中 的 什 么 位 置 \color{red}非洲象在图像中的什么位置 ?

整体代码

## 指定入
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras import backend as K
K.clear_session()
# 特别注意,在之前的实验中,我们都把顶层的分类器丢弃掉了,include_top = False
## 加载预训练模型
model = VGG16(weights='imagenet')

## 加载指定分类图片
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np

# The local path to our target image
img_path = 'C:\\Users\\Administrator\\HQR_Python_learning\\creative_commons_elephant.jpg'

## 图片预处理
# `img` is a PIL image of size 224x224
img = image.load_img(img_path, target_size=(224, 224))

# 一转,`x` is a float32 Numpy array of shape (224, 224, 3)
x0 = image.img_to_array(img)

# 二扩,We add a dimension to transform our array into a "batch"
# of size (1, 224, 224, 3)
x1 = np.expand_dims(x0, axis=0)

# 三标,Finally we preprocess the batch
# (this does channel-wise color normalization)
x = preprocess_input(x1)

## 求梯度
import tensorflow as tf
tf.compat.v1.disable_eager_execution()

#获取非洲象预测输出
african_elephant_output = model.output[:,386]

#获取最后一个卷积层激活输出
last_conv_layer = model.get_layer('block5_conv3')
#求模型输出针对最后一个卷积层激活输出的梯度
#非洲象类别相对于 block5_conv3输出特征图的梯度
# grad is (None,14,14,512)
grads= K.gradients(african_elephant_output,
					last_conv_layer.output)[0]
# 均值化处理梯度
# 形状为 (512,) 的向量,每个元素是特定特征图通道的梯度平均大小
pooled_grads = K.mean(grads, axis=(0,1, 2))

#建立模型输出、最后一个卷积层激活输出、梯度均值三者之间的函数关系
#访问刚刚定义的量:对于给定的样本图像,pooled_grads 和 block5_conv3 层的输出特征图
# model.input:(None, 224, 224, 3);last_conv_layer.output[0]:(14, 14, 512)
iterate =K.function([model.input], [pooled_grads,last_conv_layer.output[0]])
# pooled_grads:(512,);conv_layer_output_value:(14, 14, 512)
pooled_grads_value,conv_layer_output_value =iterate([x])

## 乘梯度
import matplotlib.pyplot as plt
for i in range(512):
    # conv_layer_output_value[:, :, i]:(14*14);pooled_grads_value[i]:()
    conv_layer_output_value[:, :, i] *= pooled_grads_value[i]

# 得到的特征图的逐通道平均值即为类激活的热力图
# heatmap:(14*14)
heatmap = np.mean(conv_layer_output_value, axis=-1)
# 为了将热力图可视化,去除所有负数
heatmap = np.maximum(heatmap, 0)
# 归一化处理
heatmap /= np.max(heatmap)
# 展现
plt.matshow(heatmap)

## 渲染画布,可视化
import cv2
# 用 cv2 加载原始图像
# img:(600, 899, 3)
img = cv2.imread(img_path)
# 将热力图的大小调整为与原始图像相同
#heatmap为[0,1]之间的浮点数,特别注意:cv2.resize(img, (x轴向长度,y轴向长度))
# heatmap:(600, 899, 3)
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
# 将热力图应用于原始图像
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
# 将热力图转换为 RGB 格式
heatmap = np.uint8(255 * heatmap)
# 将热力图与原始图像叠加,0.5表示渲染强度,
# 有超出(0,255)范围的,如果需要可视化,则需要clip裁剪
superimposed_img = heatmap * 0.5 + img
cv2.imwrite('C:\\Users\\Administrator\\HQR_Python_learning\\elephant_cam.jpg', superimposed_img)

你可能感兴趣的:(Python学习,python,人工智能,计算机视觉,神经网络,深度学习)