介绍

深入学习中最具争议的话题之一是如何解释和理解一个经过训练的模型——特别是在医疗等高风险行业的背景下。“黑匣子”一词经常与深度学习算法联系在一起,如果我们不能解释模型是如何工作的,我们怎么能相信模型的结果呢?这是个合理的问题。

以一个为检测癌症而训练的深度学习模型为例,这个模型告诉你,它99%确定它已经检测到癌症,但它并没有告诉你为什么或者如何做出这个决定。

是在核磁共振扫描中找到了重要线索的呢?还是只是扫描上的污点被错误地检测为肿瘤?这是病人生死攸关的问题,医生犯了错后果是很严重。

在本文中,我们将探讨如何可视化卷积神经网络(CNN),这是一种深入学习的体系结构,被用于最先进的基于图像的应用程序;我们将了解可视化CNN模型的重要性,以及可视化它们的方法;我们还将看一个用例,它将帮助你更好地理解这个概念。

目录

  • CNN模型可视化的重要性

  • 可视化方法

    • 显著图

    • 基于梯度的类激活图

    • 最大激活

    • 图像遮挡

    • 绘制模型架构

    • 可视化滤波器

  1. 基本方法

  2. 基于激活的方法

  3. 基于梯度的方法

CNN模型可视化的重要性

正如我们在上面的癌症肿瘤例子中所看到的,我们知道我们的模型在做什么,以及它如何对预测做出决定,这是绝对重要的。通常,下面列出的原因是一个深度学习实践者要记住的最重要的知识点:

  1. 了解模型的工作原理

  2. 超参数调整

  3. 找出模型的失败之处并能够解决失败

  4. 向消费者/最终用户或业务主管解释决策

让我们看一个例子,在这个例子中,可视化一个神经网络模型有助于理解模型一些不好的行为和提高性能(下面的例子来自:http://intelligence.org/files/AIPosNegFactor.pdf)。

曾几何时,美国陆军想使用神经网络来自动检测伪装的敌方坦克。研究人员用50张树木伪装的坦克照片和50张没有坦克的树木照片训练了神经网络,使用标准技术来进行监督学习,研究人员对神经网络进行了训练,使其权重能够正确加载训练集:对50张伪装坦克的照片输出“是”,对50张树木照片的输出“否”。

这并不能确保新的例子也可以被正确分类。神经网络可能已经“学习”了100个不会泛化到任何新问题的特殊情况,聪明的是,研究人员最初拍摄了200张照片,100张坦克照片和100张树木照片,他们在训练场只使用了50个。研究人员在剩下的100张照片上运行了神经网络,在没有进一步训练的情况下,神经网络对剩下的所有照片进行了正确的分类。不错!研究人员把完成的工作结果交给五角大楼,五角大楼很快就把工作交还给了他们,他们抱怨说,在他们自己的测试中,神经网络在辨别照片方面跟随机差不多。

结果发现,在研究人员的数据集中,伪装坦克的照片是在阴天拍摄的,而没有伪装的照片是在晴天拍摄的。神经网络学会了区分阴天和晴天,而不是区分伪装坦克和空旷的森林。

CNN模型的可视化方法

大体上,CNN模型的可视化方法可以根据其内部工作方式分为三个部分

  • 基本方法-向我们展示训练模型总体架构的简单方法

  • 基于激活的方法-在这些方法中,我们破译单个神经元或一组神经元的激活函数,以理解它们正在做什么

  • 基于梯度的方法-这些方法倾向于在训练模型时操纵由向前和反向传播形成的梯度

我们将在下面的章节中详细介绍它们。在这里,我们将使用keras作为我们的库来构建深度学习模型,并使用keras-vis来可视化它们。在继续之前,请确保你已经在系统中安装了这些程序。

注:本文使用“Identify the Digits”竞赛中给出的数据集,要运行下面提到的代码,你必须在系统中下载它。另外,在开始下面的实现之前,请执行要求的步骤。

数据集:https://datahack.analyticsvidhya.com/contest/practice-problem-identify-the-digits/

准备步骤:https://www.analyticsvidhya.com/keras_script-py/

1.基本方法

1.1 绘制模型架构

最简单的方法就是打印模型。在这里,你还可以打印神经网络中各个层的形状和每个层的参数。

在keras中,可以按如下方式实现:

model.summary()
_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================conv2d_1 (Conv2D)            (None, 26, 26, 32)        320       _________________________________________________________________conv2d_2 (Conv2D)            (None, 24, 24, 64)        18496     _________________________________________________________________max_pooling2d_1 (MaxPooling2 (None, 12, 12, 64)        0         _________________________________________________________________dropout_1 (Dropout)          (None, 12, 12, 64)        0         _________________________________________________________________flatten_1 (Flatten)          (None, 9216)              0         _________________________________________________________________dense_1 (Dense)              (None, 128)               1179776   _________________________________________________________________dropout_2 (Dropout)          (None, 128)               0         _________________________________________________________________preds (Dense)                (None, 10)                1290      =================================================================Total params: 1,199,882Trainable params: 1,199,882Non-trainable params: 0

为了更具创造性和表现力,你可以绘制一个架构图(keras.utils.vis_utils函数)。

1.2 可视化滤波器

另一种方法是绘制训练模型的滤波器,以便我们可以了解这些滤波器的行为。例如,上述模型第一层的第一个滤波器如下所示:

top_layer = model.layers[0]plt.imshow(top_layer.get_weights()[0][:, :, :, 0].squeeze(), cmap='gray')

一般来说,我们看到低层的滤波器起到边缘探测器的作用,当我们走得更高时,它们倾向于捕捉像物体和人脸这样的高层概念。

2. 基于激活的方法

2.1 最大激活

为了了解我们的神经网络在做什么,我们可以对输入图像应用滤波器,然后绘制输出,这使我们能够理解什么样的输入模式激活了一个特定的滤波器,例如,可能有一个人脸滤波器,当它在图像中出现一个人脸时会激活它。

from vis.visualization import visualize_activationfrom vis.utils import utilsfrom keras import activations
from matplotlib import pyplot as plt%matplotlib inlineplt.rcParams['figure.figsize'] = (18, 6)
# 按名称搜索图层索引。# 或者,我们可以将其指定为-1,因为它对应于最后一层。layer_idx = utils.find_layer_idx(model, 'preds')
#用线性层替换softmaxmodel.layers[layer_idx].activation = activations.linearmodel = utils.apply_modifications(model)
# 这是我们要最大化的输出节点。filter_idx = 0img = visualize_activation(model, layer_idx, filter_indices=filter_idx)plt.imshow(img[..., 0])

我们可以把这个想法转移到所有的类中,并检查每个类。

PS:运行下面的脚本来检查它。

for output_idx in np.arange(10):   # 让我们这次关闭详细输出以避免混乱   img = visualize_activation(model, layer_idx, filter_indices=output_idx, input_range=(0., 1.))   plt.figure()   plt.title('Networks perception of {}'.format(output_idx))   plt.imshow(img[..., 0])
2.2 图像遮挡

在一个图像分类问题中,一个简单问题是模型是否真正识别了图像中对象的位置,或者仅仅使用了周围的上下文。我们在上面基于梯度的方法中对此做了简要的介绍。基于遮挡的方法试图通过系统地用一个灰色正方形遮挡输入图像的不同部分来回答这个问题,并监视分类器的输出。示例清楚地表明,模型正在场景中定位对象,因为当对象被遮挡时,正确类的概率显著降低。

为了理解这个概念,让我们从数据集中随机抽取一张图像,并尝试绘制图像的热图。这将给我们一个直觉,图片的哪些部分是重要的,可以明确区分类别。

def iter_occlusion(image, size=8):occlusion = np.full((size * 5, size * 5, 1), [0.5], np.float32)   occlusion_center = np.full((size, size, 1), [0.5], np.float32)   occlusion_padding = size * 2# print('padding...')   image_padded = np.pad(image, ( \   (occlusion_padding, occlusion_padding), (occlusion_padding, occlusion_padding), (0, 0) \   ), 'constant', constant_values = 0.0)for y in range(occlusion_padding, image.shape[0] + occlusion_padding, size):for x in range(occlusion_padding, image.shape[1] + occlusion_padding, size):           tmp = image_padded.copy()tmp[y - occlusion_padding:y + occlusion_center.shape[0] + occlusion_padding, \             x - occlusion_padding:x + occlusion_center.shape[1] + occlusion_padding] \             = occlusiontmp[y:y + occlusion_center.shape[0], x:x + occlusion_center.shape[1]] = occlusion_centeryield x - occlusion_padding, y - occlusion_padding, \             tmp[occlusion_padding:tmp.shape[0] - occlusion_padding, occlusion_padding:tmp.shape[1] - occlusion_padding]
i = 23 # 例如data = val_x[i]correct_class = np.argmax(val_y[i])
# model.predict的输入向量inp = data.reshape(1, 28, 28, 1)
# matplotlib imshow函数的图片img = data.reshape(28, 28)
# 遮盖img_size = img.shape[0]occlusion_size = 4
print('occluding...')
heatmap = np.zeros((img_size, img_size), np.float32)class_pixels = np.zeros((img_size, img_size), np.int16)
from collections import defaultdictcounters = defaultdict(int)
for n, (x, y, img_float) in enumerate(iter_occlusion(data, size=occlusion_size)):X = img_float.reshape(1, 28, 28, 1)    out = model.predict(X)    #print('#{}: {} @ {} (correct class: {})'.format(n, np.argmax(out), np.amax(out), out[0][correct_class]))    #print('x {} - {} | y {} - {}'.format(x, x + occlusion_size, y, y + occlusion_size))heatmap[y:y + occlusion_size, x:x + occlusion_size] = out[0][correct_class]    class_pixels[y:y + occlusion_size, x:x + occlusion_size] = np.argmax(out)    counters[np.argmax(out)] += 1

3. 基于梯度的方法

3.1 显著性图

正如我们在坦克的例子中所看到的,我们如何才能知道我们的模型关注哪个部分来获得预测?为此,我们可以使用显著性图。

使用显著性图的概念是非常直接的——我们计算输出类别相对于输入图像的梯度,这可以告诉我们输出类别值相对于输入图像像素的微小变化是如何变化的。梯度中的所有正值都告诉我们,对该像素的微小更改将增加输出值,因此,将这些与图像形状相同的梯度可视化,应该能提供一些直觉。

直观地,该方法突出了对输出贡献最大的显著图像区域。

class_idx = 0indices = np.where(val_y[:, class_idx] == 1.)[0]
# 从这里选取一些随机输入。idx = indices[0]
# 让sanity检查选中的图像。from matplotlib import pyplot as plt%matplotlib inlineplt.rcParams['figure.figsize'] = (18, 6)
plt.imshow(val_x[idx][..., 0])from vis.visualization import visualize_saliencyfrom vis.utils import utilsfrom keras import activations
# 按名称搜索图层索引# 或者,我们可以将其指定为-1,因为它对应于最后一层。layer_idx = utils.find_layer_idx(model, 'preds')
# 用线性层替换softmaxmodel.layers[layer_idx].activation = activations.linearmodel = utils.apply_modifications(model)
grads = visualize_saliency(model, layer_idx, filter_indices=class_idx, seed_input=val_x[idx])# 可视化为热图。plt.imshow(grads, cmap='jet')# 线性层。for class_idx in np.arange(10):     indices = np.where(val_y[:, class_idx] == 1.)[0]    idx = indices[0]f, ax = plt.subplots(1, 4)    ax[0].imshow(val_x[idx][..., 0])for i, modifier in enumerate([None, 'guided', 'relu']):        grads = visualize_saliency(model, layer_idx, filter_indices=class_idx,         seed_input=val_x[idx], backprop_modifier=modifier)        if modifier is None:            modifier = 'vanilla'        ax[i+1].set_title(modifier)         ax[i+1].imshow(grads, cmap='jet')

3.2 基于梯度的类激活图

类激活图是另一种在进行预测时可视化模型所看到内容的方法,使用倒数第二卷积层输出,而不是使用相对于输出的梯度,这样做是为了利用存储在倒数第二层的空间信息。

from vis.visualization import visualize_cam
# 线性层。for class_idx in np.arange(10):  indices = np.where(val_y[:, class_idx] == 1.)[0] idx = indices[0]
f, ax = plt.subplots(1, 4) ax[0].imshow(val_x[idx][..., 0])
for i, modifier in enumerate([None, 'guided', 'relu']):    grads = visualize_cam(model, layer_idx, filter_indices=class_idx,     seed_input=val_x[idx], backprop_modifier=modifier)     if modifier is None:        modifier = 'vanilla'    ax[i+1].set_title(modifier)     ax[i+1].imshow(grads, cmap='jet')

结尾

在本文中,我们介绍了如何可视化CNN模型,以及为什么要可视化,我们结合一个例子来实现它。

参考链接:https://www.analyticsvidhya.com/blog/2018/03/essentials-of-deep-learning-visualizing-convolutional-neural-networks/

☆ END ☆

使用Python可视化卷积神经网络方法汇总相关推荐

  1. 基于Python的卷积神经网络和特征提取

     基于Python的卷积神经网络和特征提取 发表于2015-08-27 21:39| 4577次阅读| 来源blog.christianperone.com/| 13 条评论| 作者Christi ...

  2. 卷积神经网络的可视化(二)(可视化卷积神经网络的过滤器)

    总结自<Python 深度学习>(François Chollet)第5章. 可视化卷积神经网络的过滤器 想要观察卷积神经网络学到的过滤器,另一种简单的方法是显示每个过滤器所响应的视觉模 ...

  3. P6:可视化卷积神经网络

    子豪兄YYDS https://www.bilibili.com/video/BV1K7411W7So?p=6 一.什么是卷积神经网络的可视化 卷积神经网络可以看作一个黑箱子,打破黑箱子就需要处理中间 ...

  4. 可视化卷积神经网络的过滤器

    可视化卷积神经网络的过滤器 #想要观察卷积神经网络学到的过滤器,另一种简单的方法是显示每个过滤器所响应的视觉模式. #通过在输入空间中进行梯度上升来实现:空白图像开始,将梯度下降应用于卷积神经网络输入 ...

  5. 二、ZFNet可视化卷积神经网络——可解释性机器学习(DataWhale组队学习)

    目录 引言 ZFNet的网络结构 可视化反卷积 反池化 反激活 反卷积 训练细节 特征可视化 特征演化 特征不变性 局部遮挡测试 敏感性分析 相关性分析 消融实验 宽度影响 深度影响 迁移学习能力 有 ...

  6. 12、理解与可视化卷积神经网络

    目录 12.1 可视化卷积神经网络学习到的东西 12.1.1可视化激活和第一层权重 12.1.2 找到对神经元有最大激活的图像 12.1.3 用 t-SNE 嵌入代码 12.1.4 遮挡部分图像 12 ...

  7. keras_猫狗分类案例(三)_卷机神经网络的可视化(可视化卷积神经网络的中间输出)

    keras_猫狗分类案例(三)_卷积神经网络的可视化 参考: https://blog.csdn.net/Einstellung/article/details/82832872 卷积神经网络的可视化 ...

  8. 【深度学习】越来越卷,教你使用Python实现卷积神经网络(CNN)

    @Author:Runsen https://blog.csdn.net/weixin_44510615/article/details/117409037 卷积神经网络 Yann LeCun 和Yo ...

  9. 一维卷积神经网络_序列特征的处理方法之二:基于卷积神经网络方法

    前言 上一篇文章介绍了基本的基于注意力机制方法对序列特征的处理,这篇主要介绍一下基本的基于卷积神经网络方法对序列特征的处理,也就是TextCNN方法.序列特征的介绍,背景以及应用可以参考上一篇的详细介 ...

最新文章

  1. 投资提升亦令云安全引发高度关注
  2. Oracle根据日期计算某月的天数
  3. python基础代码-python基础代码
  4. java中的内部接口
  5. MongoDB 权限
  6. 从零开始学习C# 2
  7. 没有光驱怎样从硬盘上安装Windows XP系统
  8. KICAD | 分享一个必须安装的插件Interactive HTML BOM plugin for KiCad
  9. 公务员计算机软件及相关专业,公务员计算机专业考试大纲和真题3
  10. 为什么说比特币隐私是一门艺术?
  11. Caused by: java.lang.StringIndexOutOfBoundsException: length=5; regionStart=0; regionLength=-1
  12. Vue packages version mismatch: 版本冲突;Error: EPERM: operation not permitted
  13. 微软打造Unity开发工具包 为视力低落的用户增加辅助功能
  14. [入门阅读]怎样在android中解析JSON
  15. c语言编程秒表multisim,用定时器计数器设计一个简单的秒表.docx
  16. 欧氏空间距离和内积_希尔伯特空间(Hilbert Space)
  17. laravel文档——文件夹结构
  18. 亲测有效win10系统QQ音乐无法安装
  19. Spring——事物操作
  20. 前一段时间比较火的刷网课平台源码,带数据库和教程

热门文章

  1. 【青少年编程】【四级】绘图程序优化
  2. tensorflow 2
  3. Mat 类常用函数用法示例
  4. Python 批量处理 Excel 数据后,导入 SQL Server
  5. 新年快到了,让我们一起用 Python 编织中国结吧
  6. 有的放矢,远程操控中实时音视频的优化之道
  7. 英特尔公布新技术路线图,将为 AWS、高通代工芯片
  8. 从Python到AI,这条路好走吗?
  9. 想学新的编程语言?考虑下Go吧
  10. 算力觉醒后,智慧距离勃发就只差一个想法