对于大多数深度学习模型,模型学到的表示都难以用人类可以理解的方式提取和呈现。但对于卷积神经网络来说,我们可以很容易第提取模型学习到的表示形式,并以此加深对卷积神经网络模型运作原理的理解。

这篇文章的内容参考了《python深度学习》的《卷积神经网络可视化》的内容,可以说是对其中内容的提炼,代码书中都有,其他博客有很多都提供了,因此我尽可能不把代码放进来,而是把内容关注在概念上。

这里主要介绍三种可视化形式:

  1. 可视化卷积神经网络的中间输出
  2. 可视化卷积神经网络的过滤器(或者说可视化卷积神经网络过滤器所匹配的图像)
  3. 可视化图像中类激活的热力图

可视化卷积神经网络的中间输出

首先导入一个训练好的简单卷积神经网络模型,该模型主要用于猫狗图像的二分类,模型的结构如下所示。

然后下面是用于实验的图片,我们将把这张图片作为输入传入到神经网络,并获取到8个中间层的特征图输出:

大概过程可以用下图表述:

我们先关注第一个中间层的第一张特征图。

第一层能够获取到32张 148*148 的矩阵,把其中第一个矩阵作为图片格式输出一下,能够得到下图表示,可以发现第一张特征图主要是关注猫的面部特征。(绿色越深的位置表示了特征图提取特征的位置)

然后我们把八个层的所有特征图都输出一遍:

最后得出结论:

  1. 在卷积神经网络的第一层,特征图几乎保留了原始图像的所有信息,除了个别图片只提取了猫的某个部位(比如第二排第一个的特征几乎只提取了猫耳朵的信息)
  2. 随着层数的加深,特征图变得越来越模糊抽象。图像变得模糊是因为我们对原图像进行了最大池化,丢掉了一些几乎无用的像素点。特征图因此也开始关注更加局部的特征,比如尖耳朵、圆脑袋、五官的分布位置等。

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

以深度卷积神经网络模型VGG16为例,第7个卷积层有256个3*3*3的过滤器,每个过滤器都应该存在一个最佳匹配的图像,或者说像素特征。

这里说明一下为什么选择VGG16,我自己尝试过采用自建的模型进行可视化,但由于自建模型卷积层数较低,而较低层的卷积核表述的信息很多都是颜色图像和一些简单纹理,并不是一个好的例子,因此采用较深的VGG16

我们可以通过梯度上升的方式来计算出近似最佳匹配的图像矩阵。整个计算过程如下图表述:

可以看一下初始点位X0的图像表示:

我们先关注一下第一个卷积核经过40次梯度下降所匹配的输入图像特征:

似乎 block3_conv1 的第一个卷积核响应的特征是波卡尔点图案,我们再分别输出三个卷积块的前60个卷积核所匹配的输入图像:

block1_conv1

block2_conv1

block3_conv1

block4_conv1

可以发现随着层数加深,过滤器所匹配的图像变得越来越复杂,表述的形状也越来越精细。

模型的第一层和第二层大多包含一些简单的方向边缘和颜色以及一些纹理,到了第三层,纹理变得更加精细丰富,而第四层则表示了类似于自然图像中的纹理:羽毛、眼睛、树叶等。

可视化类激活的热力图

可视化类激活的热力图能够在图像上标注特定的位置,以得知神经网络通过图像的哪个部分来进行决策。

比如下面这张热力图则表示神经网络对大象的分类中,是通过大象头部的特征进行了决策。

这种方式还可以用于调试神经网络的决策过程,比如神经网络分类出错了,可以通过这种方式去看看,神经网络是因关注了什么特征而导致了出错。

热力图显示的原理在书中解释的非常简略,这里我再进行一个详细的补充。

上述过程描述的是单张特征图的计算过程,但我们有512张特征图,因此整个过程还需要执行512次,拿到一个14*14*512的热力图处理后的特征图集合。

最终我们需要获取到一张14*14的热力图,因此我们对上述的14*14*512的特征图向量进行加权平均

这里简单放一下处理过程的代码:

# 拿到非洲象的后验概率输出,也就是Y
african_elephant_output = model.output[:, 386]
# 拿到最后一个卷积层的14*14*512特征图向量X
last_conv_layer = model.get_layer('block5_conv3')
# 求grads=dY/dX
grads = K.gradients(african_elephant_output, last_conv_layer.output)[0]
# 对grads进行加权平均
pooled_grads = K.mean(grads, axis=(0, 1, 2))
iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])
pooled_grads_value, conv_layer_output_value = iterate([x])
# 分别对512层特征图都乘上对应grads的加权值
for i in range(512):
conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
# 加权平均获取到14*14的热力图
heatmap = np.mean(conv_layer_output_value, axis=-1)

然后我们看一下处理之前的加权平均显示的feature_map:

处理之后的heat_map

可以发现,颜色鲜艳的区域变得更少更集中。然后通过opencv把heat_map的格式套在原图上,就能够得到对应位置的热力图了。

《Python深度学习》《卷积神经网络的可视化》精读的更多相关文章

  1. 精读《V8 引擎 Lazy Parsing》

    1. 引言 本周精读的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎为了优化性能,做了怎样的尝试吧! 这篇文章介绍的优化技术叫 preparser,是通过跳过不必要函数编译的方式优化性 ...

  2. 深入浏览器工作原理和JS引擎(V8引擎为例)

    浏览器工作原理和JS引擎 1.浏览器工作原理 在浏览器中输入查找内容,浏览器是怎样将页面加载出来的?以及JavaScript代码在浏览器中是如何被执行的? 大概流程可观察以下图: 首先,用户在浏览器搜 ...

  3. [翻译] V8引擎的解析

    原文:Parsing in V8 explained 本文档介绍了 V8 引擎是如何解析 JavaScript 源代码的,以及我们将改进它的计划. 动机 我们有个解析器和一个更快的预解析器(~2x), ...

  4. 一文搞懂V8引擎的垃圾回收

    引言 作为目前最流行的JavaScript引擎,V8引擎从出现的那一刻起便广泛受到人们的关注,我们知道,JavaScript可以高效地运行在浏览器和Nodejs这两大宿主环境中,也是因为背后有强大的V ...

  5. Chrome V8引擎系列随笔 (1):Math.Random()函数概览

    先让大家来看一幅图,这幅图是V8引擎4.7版本和4.9版本Math.Random()函数的值的分布图,我可以这么理解 .从下图中,也许你会认为这是个二维码?其实这幅图告诉我们一个道理,第二张图的点的分 ...

  6. (译)V8引擎介绍

    V8是什么? V8是谷歌在德国研发中心开发的一个JavaScript引擎.开源并且用C++实现.可以用于运行于客户端和服务端的Javascript程序. V8设计的初衷是为了提高浏览器上JavaScr ...

  7. 浅谈Chrome V8引擎中的垃圾回收机制

    垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...

  8. V8引擎嵌入指南

    如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...

  9. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  10. 深入出不来nodejs源码-V8引擎初探

    原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...

随机推荐

  1. nodejs pm2 详解

    一.PM2是什么 pm2是可以用于生产环境的Nodejs的进程管理工具,并且它内置一个负载均衡.它不仅可以保证服务不会中断一直在线,并且提供0秒reload功能,还有其他一系列进程管理.监控功能.并且 ...

  2. Blob 和 ArrayBuffer

    Blob 和 ArrayBuffer Blob 对象表示的是二进制到文本的对象: ArrayBuffer 对象表示一段二进制数据,用来模拟内存里面的数据. Blob 关于 Blob 的详细内容:了解 ...

  3. Flutter:StatefulWidget 怎么传参

    定义好一个有状态(或无状态)的组件之后,需要为其传递一些参数,希望组件能够更加灵活使用.那么,在 Flutter 中如何为其传递参数呢? 以下是 StatefulWidget 传递值的步骤,一共三步: ...

  4. OpenAI Java SDK——chatgpt-java-v1.0.3更新支持GPT-3.5-Turbo,支持语音转文字,语音翻译。

    简介 chatgpt-java是一个OpenAI的Java版SDK,支持开箱即用.目前以支持官网全部Api.支持最新版本GPT-3.5-Turbo模型以及whisper-1模型.增加chat聊天对话以 ...

  5. go语言初记

    快速了解 http://go-tour-zh.appspot.com/welcome/1 (可以需要爬墙) 下面记录下了解go的过程,特别记录下与你脑子里原有"观念"不同的地方: ...

  6. 小程序-扩展能力图片上传Uploader组件

    微信小程序中有一些扩展组件可以用,例如其中的图片上传组件,不论样式还是上传时的动画,都比较好,在使用过程中也遇到了一些问题,在这记录一下,也期望能让后来用的人少走弯路. 第一步,首先访问网址,http ...

  7. Appium常见属性和命令

    from appium import webdriverimport time, tracebackdesired_caps = {}desired_caps['platformName'] = 'A ...

  8. 微信电脑版 v3.9.2.12 绿色便携版

    修改历史: 2023.03.01:自改官方 3.9.2.12 最新正式版本2023.01.31:自改官方 3.9.0.28 最新正式版本2023.01.11:自改官方 3.9.0.21 最新正式版本- ...

  9. linux系统过滤文件,并且通过时间对过滤的文件排序

    命令如下所示: find /home/deep/tf/20220601/study -name '*.h5' |xargs ls -lta

  10. 通过pxelinux引导管理器网络引导slax linux

    前提条件 1.用于引导服务器具备tftp服务和http服务: 2.使用syslinux项目下lpxelinux.0做为pxe引导文件,原因:测试发现lpxelinux.0对http协议支持更好,可以更 ...