深度学习中最具争议的话题之一是如何解释和理解经过训练的模型——尤其是在医疗保健等高风险行业的背景下。“黑匣子”一词通常与深度学习算法相关联。如果我们无法解释模型的工作原理,我们如何信任模型的结果?这是一个合理的问题。以经过训练以检测癌症的深度学习模型为例。该模型告诉您它有99%的把握检测出癌症,但它不会告诉您为什么或如何做出该决定。在MRI扫描中发现重要线索?或者它只是扫描上的一个污点被错误地检测为肿瘤?这对患者来说是生死攸关的问题,医生可能会犯下严重后果的大错误。在本文中,我们探讨了如何可视化卷积神经网络(CNN),这是一种深度学习架构,特别用于最先进的基于图像的应用程序。我们将了解可视化CNN模型的重要性,以及可视化它们的方法。我们还将查看一个用例,以帮助您更好地理解该概念。CNN模型可视化的重要性正如我们在上面的癌症肿瘤示例中看到的,了解我们的模型在做什么以及它如何做出预测决策是绝对关键的。下面列出的原因是深度学习从业者要记住的最重要的原因:了解模型的工作原理超参数调优找出模型失败的地方并能够修复它向消费者/最终用户或业务主管解释决定让我们看看在一个示例中,可视化神经网络模型可以帮助理解模型的一些不良行为并提高性能。以下示例来自:http://intelligence.org/files...。曾几何时,美国陆军想要使用神经网络来自动检测伪装的敌方坦克。研究人员使用50张带有伪装树木的坦克照片和50张没有坦克的树木照片对神经网络进行了训练。使用标准的监督学习技术,研究人员对神经网络进行了训练,使其权重正确加载训练集:输出“是”表示50张伪装坦克的照片,输出“否”表示50张树木的照片。这并不能保证,甚至不能暗示,新的例子会被正确分类。一个神经网络可能已经“学习”了100个不会泛化到任何新问题的特例。聪明的是,研究人员最初拍摄了200张照片,100张坦克照片和100张树木照片。他们在训练场只用了5??0个。研究人员在剩下的100张照片上运行了神经网络,在没有进一步训练的情况下,神经网络正确地对剩下的所有照片进行了分类。好的!将完成的工作交给五角大楼的研究人员抱怨说,在他们自己的测试中,神经网络在区分照片方面与机器一样好。原来,在研究人员的数据集中,伪装坦克的照片是在阴天拍摄的,而没有伪装的照片则是在晴天拍摄的。神经网络学会了区分阴天和晴天,但无法区分伪装的坦克和空旷的森林。CNN模型的可视化方法一般来说,CNN模型的可视化方法可以根据其内部工作方式分为三个部分。我们破译单个神经元或神经元组的激活函数以了解它们在做什么基于梯度的方法——这些在训练模型时倾向于操纵由前向传播和反向传播形成的梯度我们将在以下部分详细介绍它们。在这里,我们将使用keras作为我们的库来构建深度学习模型,并使用keras-vis来可视化它们。在继续之前,请确保您的系统上安装了这些程序。注:本文使用“IdentifytheDigits”竞赛给出的数据集。要运行下面提到的代码,您必须将其下载到您的系统中。此外,在开始下面的实施之前,请按照提供的步骤进行操作。数据集:https://datahack.analyticsvid...准备步骤:https://www.analyticsvidhya.c...一、基本方法1.1绘制模型架构最简单的方法就是打印模型。在这里,您还可以打印神经网络层的形状和每一层的参数。在keras中可以这样实现:model.summary()===========================================conv2d_1(Conv2D)(无,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(扁平化)(无,9216)0____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________dropout_2(Dropout)(无,128)0______________________________________________________________________preds(密集)(无,10)1290===================================================================总参数:1,199,882可训练参数:1,199,882不可训练参数: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最大激活为了理解我们的神经网络在做什么,我们可以对输入图像应用一个过滤器,然后绘制输出。这使我们能够了解哪些输入模式会激活特定的过滤器。例如,可能有一个面部过滤器会在图像中出现面部时激活。fromvis.visualizationimportvisualize_activationfromvis.utilsimportutilsfromkerasimportactivationsfrommatplotlibimportpyplotasplt%matplotlibinlineplt.rcParams['figure.figsize']=(18,6)#按名称搜索图层索引。#或者,我们可以指定-1,因为它对应于最后一层。layer_idx=utils.find_layer_idx(model,'preds')#用线性替换softmaxmodellayers[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:运行下面的脚本进行检查。foroutput_idxinnp.arange(10):#这次让我们关闭详细输出以避免混淆img=visualize_activation(model,layer_idx,filter_indices=output_idx,input_range=(0.,1.))plt.figure()plt.title('Networksperceptionof{}'.format(output_idx))plt.imshow(img[...,0])2.2ImageOcclusion在一个图像分类问题中,一个自然的问题是模型是否真正识别了的位置对象,或者简单地使用周围的上下文。我们在上面基于梯度的方法中简要介绍了这一点。基于遮挡的方法试图通过用灰色方块系统地遮挡输入图像的不同部分来回答这个问题,并监控分类器的输出。这些示例清楚地表明模型正在定位场景中的对象,因为当对象被遮挡时正确类别的概率会显着降低。为了理解这个概念,让我们从数据集中随机获取一张图像,并尝试绘制图像的热图。这将使我们直观地了解图片的哪些部分对于清楚区分类别很重要。defiter_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)foryinrange(occlusion_padding,image.shape[0]+occlusion_padding,size):forxinrange(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_center产生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)#matplotlibimshow数的图片img=data.reshape(28,28)#遮盖img_size=img.shape[0]occlusion_size=4print('occlusion...')heatmap=np.zeros((img_size,img_size),np.float32)class_pixels=np.zeros((img_size,img_size),np.int16)fromcollectionsimportdefaultdictcounters=defaultdict(int)forn,(x,y,img_float)inenumerate(iter_occlusion(data,size=occlusion_size)):X=img_float.reshape(1,28,28,1)out=model.predict(X)#print('#{}:{}@{}(正确类:{})'.format(n,np.argmax(out),np.amax(out),out[0][correct_class]))#print('x{}-{}|y{}-{}'.format(x,x+occlusion_size,y,y+occlusion_size))热图[y:y+occlusion_size,x:x+occlusion_size]=out[0][correct_class]class_pixels[y:y+闭塞_size,x:x+occlusion_size]=np.argmax(out)counters[np.argmax(out)]+=13.Gradient-basedmethods3.1Saliencymaps正如我们在坦克例子中看到的,我们如何知道我们的模型关注哪一部分以获得预测?为此,我们可以使用显着图。使用显着图的概念非常简单——我们计算输出类相对于输入图像的梯度。这应该告诉我们输出类值如何相对于输入图像像素的微小变化而变化。梯度中的所有正值都告诉我们,对该像素的微小变化会增加输出值。因此,将这些具有与图像相同形状的渐变可视化应该会提供一些直觉。直观地,此方法突出显示对输出贡献最大的显着图像区域。class_idx=0indices=np.where(val_y[:,class_idx]==1.)[0]#从这里选择一些随机输入。idx=indices[0]#让完整性检查所选图像。frommatplotlibimportpyplotasplt%matplotlibinlineplt.rcParams['figure.figsize']=(18,6)plt.imshow(val_x[idx][...,0])fromvis.visualizationimportvisualize_saliencyfromvis.utilsimportutilsfromkerasimportactivations#按名称搜索层索引#或者,我们可以指定-1,因为它对应于最后一层。layer_idx=utils.find_layer_idx(model,'preds')#将softmaxmodel.layers[layer_idx]替换为线性层val_x[idx])#可视化为热图。plt.imshow(grads,cmap='jet')#这个对应线性层。对于np.arange(10)中的class_idx: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])fori,枚举中的修饰符([None,'guided','relu']):grads=visualize_saliency(model,layer_idx,filter_indices=class_idx,seed_input=val_x[idx],backprop_modifier=modifier)ifmodifierisNone:modifier='vanilla'ax[i+1].set_title(modifier)ax[i+1].imshow(grads,cmap='jet')3.2basedClassActivationMapsofGradients类激活图是另一种可视化模型在进行预测时看到的内容的方法。使用倒数第二个卷积层输出,而不是对输出使用梯度。这样做是为了利用存储在倒数第二层中的空间信息。fromvis.visualizationimportvisualize_cam#这个对应的是线性层。对于np.arange(10)中的class_idx: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])fori,枚举中的修饰符([None,'guided','relu']):grads=visualize_cam(model,layer_idx,filter_indices=class_idx,seed_input=val_x[idx],backprop_modifier=modifier)ifmodifierisNone:modifier='vanilla'ax[i+1].set_title(modifier)ax[i+1].imshow(grads,cmap='jet')在这篇文章中,我们介绍了如何对CNN模型进行可视化,以及为什么要对其进行可视化,并且我们结合了一个例子来实现它。可视化具有广泛的应用。文渊网络仅供学习,如有侵权请联系删除。学习Python的路上肯定会遇到困难,不要慌张,我这里有一套学习资料,包括40+电子书,800+教学视频,涉及Python基础、爬虫、框架、数据分析、机学习等等,别怕你学不会!https://shimo.im/docs/JWCghr8...《Python学习资料》关注公众号【蟒圈】,每日优质文章推送。
