这个例子展示了如何使用类激活映射(CAM)来研究和解释用于图像分类的深度卷积神经网络的预测。
深度学习网络通常被认为是“黑盒”,无法弄清楚网络学习了什么,或者网络的哪一部分输入负责对网络的预测。当这些模型失败并给出错误的预测时,它们经常在没有任何警告或解释的情况下壮观地失败。类激活映射[1]是一种技术,你可以使用它来获得卷积神经网络预测的可视化解释。不正确的、看似不合理的预测往往有合理的解释。使用类激活映射,您可以检查输入图像的某个特定部分是否“混淆”了网络并导致它做出错误的预测。
您可以使用类激活映射来识别训练集中的偏差并提高模型的准确性。如果您发现网络基于错误的特性进行预测,那么您可以通过收集更好的数据使网络更加健壮。例如,假设您训练一个网络来区分猫和狗的图像。该网络在训练集上具有较高的准确率,但在真实示例上表现较差。通过对训练示例使用类激活映射,您会发现网络的预测不是基于图像中的猫和狗,而是基于背景。然后你意识到所有的猫的图片背景都是红色的,所有的狗的图片背景都是绿色的,这就是网络在训练中学习到的背景颜色。然后你就可以收集没有这种偏见的新数据。
这个示例类激活映射显示输入图像的哪个区域对预测类贡献最大鼠标
.红色区域贡献最大。
加载预训练的卷积神经网络用于图像分类。SqueezeNet, GoogLeNet, ResNet-18和MobileNet-v2是相对较快的网络。SqueezeNet是最快的网络,它的类激活图的分辨率是其他网络的4倍。对于网络末端有多个完全连接层的网络,如AlexNet、VGG-16和VGG-19,不能使用类激活映射。
netname =.“squeezenet”;网= eval(网络);
创建一个网络摄像头
对象并连接到你的网络摄像头。
相机=摄像头;
提取网络的图像输入大小和输出类别。的activationLayerName
在本例的最后定义的Helper函数返回要从中提取激活的层的名称。这一层是ReLU层,它跟随网络的最后一个卷积层。
inputSize = net.Layers (1) .InputSize (1:2);类= net.Layers . class(结束);layerName = activationLayerName(网络);
创建图形并在循环中执行类激活映射。要终止循环的执行,请关闭图形。
h =图('单位',“归一化”,'位置',[0.05 0.05 0.9 0.8],'可见的',“上”);尽管ishandle (h)
用网络摄像头拍张照片。调整图像的大小,使其最短边的长度(在本例中为图像高度)等于网络的图像输入大小。当你调整大小时,保持图像的宽高比。您还可以将图像调整为更大或更小的尺寸。放大图像可以提高最终类激活图的分辨率,但可能导致总体预测的准确性降低。
计算调整大小的图像在ReLU层的激活,ReLU层紧随网络的最后一个卷积层。
IM =快照(摄像机);IMRESIZED = IMRESIZE(IM,[输入(1),NAN]);ImageActivations =激活(NET,IMRESIZED,LAYRNAME);
特定职业的职业激活图是ReLU层的激活图,ReLU层紧随最后的卷积层,并根据每个激活对该职业最终得分的贡献进行加权。这些权重等于该类网络的最终完全连接层的权重。SqueezeNet没有最终完全连接的层。相反,在最后一个卷积层之后的ReLU层的输出已经是类激活映射。
您可以为任何输出类生成类激活映射。例如,如果网络进行了错误的分类,您可以比较真实类和预测类的类激活映射。对于本例,为预测的得分最高的类生成类激活映射。
scores = squeeze(mean(imageactivities,[1 2]));如果网络~ =“squeezenet”fcWeights = net.Layers (end-2) .Weights;fcBias = net.Layers (end-2) .Bias;分数= fcWeights*分数+ fcBias;[~, classIds] = maxk(分数,3);weightVector = shiftdim (fcWeights (classIds (1):), 1);classActivationMap = (imageActivations。* weightVector, 3)总和;其他的[~, classIds] = maxk(分数,3);classActivationMap = imageActivations (:,:, classIds (1));结束
计算顶级类标签和最终标准化类得分。
成绩= exp(分数)/笔(exp(分数));maxScores =分数(classIds);标签=类(classIds);
绘制类激活映射。在第一副图中显示原始图像。在第二个次要情节中,使用CAMshow
Helper函数(在本示例的最后定义)用于在原始图像的灰度化版本上显示类激活映射。显示前三名的预测标签和他们的预测分数。
subplot(1,2,1) imshow(im) subplot(1,2,2) CAMshow(im,classActivationMap) title(string(labels) +“,”+字符串(maxScores));drawnow结束
清除摄像头对象。
清除相机
网络正确地将此图像中的对象正确标识为Loafer(一种鞋类)。右侧图像中的类激活映射显示了输入图像的每个区域对预测类的贡献游手好闲的人
.红色区域贡献最大。该网络根据整个鞋子进行分类,但最强的输入来自红色区域——也就是鞋尖和鞋口。
网络将此图像分类为鼠标。正如类激活映射所示,预测不仅基于图像中的鼠标,还基于键盘。由于训练集可能有许多鼠标靠近键盘的图像,网络预测包含键盘的图像更可能包含鼠标。
该网站将这个咖啡杯的图像归类为扣环。如类激活映射所示,由于图像包含太多混淆对象,网络对图像进行了错误分类。该网络检测并关注手表腕带,而不是咖啡杯。
CAMshow (im,凸轮)
覆盖类激活映射凸轮
在黑暗的灰度版本的图像上即时通讯
.函数将类激活映射的大小调整为即时通讯
,将其标准化,从下面开始阈值化,并使用飞机
colormap。
功能CAMshow(im,CAM) imSize = size(im);(凸轮凸轮= imresize imSize (1:2));凸轮= normalizeImage (CAM);凸轮(凸轮< 0.2)= 0;提出=喷气(255)。* linspace (1255 0) ';凸轮= ind2rgb (uint8(凸轮* 255),提出)* 255;combinedImage = double(rgb2gray(im))/2 + CAM;combinedImage = normalizeImage (combinedImage) * 255;imshow (uint8 (combinedImage));结束功能N = normalizeImage(I) minimum = min(I(:));最大= max(我(:));N = (I-minimum) /(最大最小);结束功能LayerName = ActivationLayerName(NetName)如果网络= =“squeezenet”layerName =“relu_conv10”;elseif网络= =“googlenet”layerName =“inception_5b-output”;elseif网络= =“resnet18”layerName =“res5b_relu”;elseif网络= =“mobilenetv2”layerName ='out_relu';结束结束
[1] Zhou, Bolei, Aditya Khosla, Agata Lapedriza, Aude Oliva, Antonio Torralba。"学习深度特征以实现鉴别定位"在计算机视觉与模式识别会议论文集, 2921 - 2929页。2016.
激活
|squeezenet
|occlusionSensitivity
|gradCAM
|imageLIME