社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

计算机视觉工坊 • 2 年前 • 336 次点击  

转自 | 机器学习算法那些事


介绍

深入学习中最具争议的话题之一是如何解释和理解一个经过训练的模型——特别是在医疗等高风险行业的背景下。“黑匣子”一词经常与深度学习算法联系在一起,如果我们不能解释模型是如何工作的,我们怎么能相信模型的结果呢?这是个合理的问题。
以一个为检测癌症而训练的深度学习模型为例,这个模型告诉你,它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] \ = occlusion
tmp[y:y + occlusion_center.shape[0], x:x + occlusion_center.shape[1]] = occlusion_center
yield 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/

本文仅做学术分享,如有侵权,请联系删文。

干货下载与学习

后台回复:巴塞罗 自治大学课件,即可下载国外大学沉淀数年3D Vison精品课件

后台回复:计算机视觉书籍,即可下载3D视觉领域经典书籍pdf

后台回复:3D视觉课程,即可学习3D视觉领域精品课程

计算机视觉工坊精品课程官网:3dcver.com

1.面向自动驾驶领域的多传感器数据融合技术

2.面向自动驾驶领域的3D点云目标检测全栈学习路线!(单模态+多模态/数据+代码)
3.彻底搞透视觉三维重建:原理剖析、代码讲解、及优化改进
4.国内首个面向工业级实战的点云处理课程
5.激光-视觉-IMU-GPS融合SLAM算法梳理和代码讲解
6.彻底搞懂视觉-惯性SLAM:基于VINS-Fusion正式开课啦
7.彻底搞懂基于LOAM框架的3D激光SLAM: 源码剖析到算法优化
8.彻底剖析室内、室外激光SLAM关键算法原理、代码和实战(cartographer+LOAM +LIO-SAM)

9.从零搭建一套结构光3D重建系统[理论+源码+实践]

10.单目深度估计方法:算法梳理与代码实现
11.自动驾驶中的深度学习模型部署实战
12.相机模型与标定(单目+双目+鱼眼)
13.重磅!四旋翼飞行器:算法与实战
14.ROS2从入门到精通:理论与实战
15.国内首个3D缺陷检测教程:理论、源码与实战
16.基于Open3D的点云处理入门与实战教程
17.透彻理解视觉ORB-SLAM3:理论基础+代码解析+算法改进

重磅!计算机视觉工坊-学习交流群已成立

扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

同时也可申请加入我们的细分方向交流群,目前主要有ORB-SLAM系列源码学习、3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、深度估计、学术交流、求职交流等微信群,请扫描下面微信号加群,备注:”研究方向+学校/公司+昵称“,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进去相关微信群。原创投稿也请联系。

▲长按加微信群或投稿微信: dddvision

▲长按关注公众号

3D视觉从入门到精通知识星球:针对3D视觉领域的视频课程(三维重建系列三维点云系列结构光系列手眼标定相机标定激光/视觉SLAM自动驾驶 )、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近6000星球成员为创造更好的AI世界共同进步,知识星球入口:

学习3D视觉核心技术,扫描查看介绍,3天内无条件退款
 圈里有高质量教程资料、答疑解惑、助你高效解决问题
觉得有用,麻烦给个赞和在看~  

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/149567
 
336 次点击