当使用神经网络时,我们可以通过其准确性来评估模型的性能,但是当涉及到计算机视觉问题时,它不仅是具有最佳的准确性,而且还涉及可解释性以及对哪些特征/数据点的理解帮助决策。模型关注正确的特征比模型的准确性更重要。
理解CNN的主要方法是类激活图(CAM)、梯度加权类激活映射(Grad-CAM)和优化的梯度-CAM(Grad-CAM++)。想法是相同的:如果我们获取最后一个卷积层的输出特征图并对它们应用权重,我们会得到一个热图,该热图指示输入图像的哪些部分具有高权重(代表整个图像的特征)。
CAM 是一种可视化CNN 看到或关注的内容并为我们生成类输出的方法。
通过将图像传递给CNN,我们获得了同一图像的低分辨率特征图。
CAM的思想是去除那些全连接的神经网络,并用全局平均池化层代替它们,其中特征图中所有像素的平均值就是其全局平均值。通过将GAP 应用于所有特征图,您将获得标量值。
对于这些标量值,我们应用权重来指示每个特征图对特定类的重要性。权重是通过训练线性模型来学习的。
激活图将是所有这些特征图的加权组合。
defgenerate_cam(input_model, image, layer_name='block5_conv3', H=224, W=224): cls=np.argmax(input_model.predict(image)) # 获取预测类conv_output=input_model.get_layer(layer_name).output#获取最后一个输出层的权重last_conv_layer_model=keras.Model(input_model.inputs, conv_output) #使用最后一个输出层创建模型class_weights=input_model.get_layer(layer_name).get_weights()[0] # 获取最后一个输出层的权重输出层\\ class_weights=class_weights[0,] class_weights=np.mean(class_weights, axis=(0, 1)) last_conv_output=last_conv_layer_model.predict(image) #最后一个输出层输出的特征图last_conv_output=last_conv_output[0,] cam=np.dot(last_conv_output, class_weights) cam=zoom(cam, H/cam.shape[0]) #空间插值/缩放到图像大小cam=cam/np.max(cam) #Normalizing the gradcam returncam 但CAM最大的缺点之一是必须重新训练模型才能获得全局平均池化后得到的权重。对于每个类别,必须学习一个线性模型。也就是说会有n个权重(等于最后一层的过滤器)* n个线性模型(等于类别)。并且还必须修改网络架构才能创建CAM,这对于现有模型来说改变太大,因此Grad-CAM解决了这些缺点。
Grad-CAM 背后的想法是依赖最后一个卷积层的特征图中使用的梯度,而不是使用网络权重。这些梯度是通过反向传播获得的。
这不仅解决了重新训练问题,还解决了网络架构修改问题,因为仅使用梯度而不是GAP 层。
我们只计算最后一个卷积层中顶部预测类的特征图的梯度。然后我们对这些权重应用全局平均。权重与最后一层得到的特征图的点积就是Grad-CAM的输出。然后通过对其应用ReLU,仅识别图像中对我们的图像有积极贡献的部分。
最后一步是将Grad-CAM 调整为图像大小并对其进行标准化,以便它可以覆盖在图像上。
defgrad_cam(input_model, image, layer_name='block5_conv3',H=224,W=224): cls=np.argmax(input_model.predict(image)) #获取预测类y_c=input_model.output[0, cls] #概率得分conv_output=input_model.get_layer(layer_name).output#cnn最后一层的张量grads=K.gradients(y_c, conv_output)[0] #预测类wrt conv_output层的梯度get_output=K.function([input_model .input], [conv_output, grads]) output, grads_val=get_output([image]) #给出图像直到conv_output 层的输出以及该层的梯度值output, grads_val=output[0,], grads_val[ 0,]weights=np.mean(grads_val, axis=(0, 1)) #梯度的平均值,作为我们的权重cam=np.dot(output,weights) #Grad-CAM 输出cam=NP。 max(cam, 0) #应用Relu cam=zoom(cam,H/cam.shape[0]) #空间插值/缩放至图像大小cam=cam/cam.max() #标准化gradcam returncam
Grad -CAM++不仅包含gradcam技术,还添加了引导反向传播,仅反向传播类预测的正梯度。
之所以对Grad-CAM++ 进行这种优化,是因为Grad-CAM 在识别和关注多次出现或占用空间较小的对象时存在问题。
因此,Grad-CAM++ 通过使用更大的因子而不是像Grad-CAM 那样使用恒定因子来缩放与预测类别相关的梯度像素,从而更加重视(正梯度)。该比例因子在代码中用alpha 表示。
defgrad_cam_plus(input_model,图像,layer_name='block5_conv3',H=224,W=224): cls=np.argmax(input_model.predict(图像)) y_c=input_model.output [0,cls] conv_output=input_model.get_layer( layer_name).output grads=K.gradients(y_c, conv_output)[0]first=K.exp(y_c)*grads#用于计算第一、第二和第三梯度的变量第二个=K.exp(y_c)*grads*grads第三=K.exp(y_c)*grads*grads*grads #梯度计算get_output=K.function([input_model.input], [y_c,first,second,third, conv_output, grads]) y_c, conv_first_grad, conv_second_grad,conv_third_grad, conv_output, grads_val=get_output([img]) global_sum=np.sum(conv_output[0].reshape((-1,conv_first_grad[0].shape[2])), axis=0) #用于计算alpha值对于每个空间位置alpha_num=conv_second_grad[0] alpha_denom=conv_second_grad[0]*2.0+conv_third_grad[0]*global_sum.reshape((1,1,conv_first_grad[0].shape[2])) alpha_denom=np.where( alpha_denom!=0.0, alpha_denom, np.ones(alpha_denom.shape)) alphas=alpha_num/alpha_denom #计算权重和alpha,这是我们乘以更重要的权重的尺度weights=np.maximum(conv_first_grad[0] , 0.0) alpha_normalization_constant=np.sum(np.sum(alphas, axis=0),axis=0) alphas/=alpha_normalization_constant.reshape((1,1,conv_first_grad[0].shape[2])) #标准化alpha #权重与alpha相乘得到空间重要性deep_linearization_weights=np.sum((weights*alphas).reshape((-1,conv_first_grad[0].shape[2])),axis=0) grad_CAM_map=np.sum(deep_linearization_weights *conv_output[0], axis=2) #Grad-CAM++ 地图cam=np.maximum(grad_CAM_map, 0) cam=zoom(cam,H/cam.shape[0]) cam=cam/np.max(cam) returncam
这里我们使用VGG16 比较一些图像。从下图中您可以看到CAM、Grad-CAM 和Grad-CAM++ 的视图有多么不同。虽然它们都主要关注其上半身,但Grad-CAM++ 能够将其整体视为重要部分,而CAM 将其某些部分视为非常重要的特征,而某些部分则视为其预测的辅助特征。而Grad-CAM 只关注其冠和翼作为决策的重要特征。
对于这张风筝图像,CAM 显示它聚焦于除风筝(即天空)之外的所有物体,但使用gradcam,您会看到模型聚焦于风筝,而gradcam++ 通过添加重要的突出空间更进一步这是加强的。这里需要注意的是,模型错误地将其分类为降落伞,但风筝类别紧随其后。换句话说,CAM 实际上更好地捕获了错误的原因。