当你训练神经网络对图像进行分类时,你有没有想过网络理解图像的方式是否与人类感知信息的方式相同?这个问题很难回答,因为大多数时候深度神经网络被视为黑盒子。我们向它提供输入数据并获得输出。如果整个过程出现问题,很难调试。尽管预测相当准确,但这并不意味着它们可以与人类的感知方式相媲美。为什么会这样?假设您需要对大象和企鹅进行二进制分类(我知道这是一项简单的任务)。现在您已经获得了数据集,训练了模型并部署了它。这个模型一定适用于大部分数据,但总有误判的可能。有些人可能将其视为极端情况,但您认为什么时候物体可以被CNN清楚地识别?结合以上,很明显,在图像中,大象往往伴随着草木,而企鹅往往伴随着冰雪出现。所以,实际上,模型学会了区分植被和冰雪的颜色/形状,而不是真正学会按物体分类。从以上案例来看,颜色通道统计等简单的图像处理技术与训练模型是一样的。因为没有智能,模型只能靠颜色来区分物体。现在你可能会问,你怎么知道CNN在找什么?答案是,Grad-CAM。加权梯度类激活映射(Grad-CAM)我们在这篇博客中实现了加权梯度类激活映射。首先,我们需要知道这不是唯一的解决方案。原作说加权梯度类激活图(Grad-CAM)传递任意目标概念(比如类别“狗”甚至单词“狗”的对数)的梯度,并将这些知识传递给卷积的***这些层依次生成粗略的定位图,突出显示对预测相关概念至关重要的图像区域。通俗地说,我们只是获取最终卷积层的特征图,然后通过与该通道关联的类的梯度对该特征中的每个通道进行加权。这种方法无非就是输入图像如何通过每个通道对类别的重要性来激活不同的通道,最重要的是它不需要对现有架构进行任何重新训练或更改。特定类的特征空间得分为对应类的输出值y^c,对特征图A_ij进行偏导,对i和j维的特征进行全局平均池化操作。然后,我们将结果与沿其通道轴k的特征图相乘。***,对通道维度k的结果进行平均/合并。因此,特征空间的得分凸性大小为i×j。Σ表示法用于描述池化和平均操作。ReLU激活函数用于得分图,然后对其进行归一化以输出正区域预测。实施出于本博客的目的,我们应用预训练的VGG模型并导入一些必要的包以开始实施代码。fromkeras.applications.vgg16importVGG16,preprocess_input,decode_predictionsfromkeras.preprocessingimportimageimportkeras.backendasKimportnumpyasnpimportcv2importsys我们使用Keras自带的VGG16模型。并加载一些有助于加载和操作图像的函数。model=VGG16(weights="imagenet")img_path=sys.argv[1]img=image.load_img(img_path,target_size=(224,224))x=image.img_to_array(img)x=np.expand_dims(x,axis=0)x=preprocess_input(x)我们首先初始化模型,通过命令行参数加载图片。VGG网络只接受(224×224×3)尺寸的图片,所以我们需要将图片缩放到指定尺寸。由于我们只通过网络传递一个图像,因此我们需要扩展第一个维度,将其扩展为大小为1的批次。然后,我们通过辅助函数preprocess_input从输入图像中减去平均RGB值来对图像进行归一化。preds=model.predict(x)class_idx=np.argmax(preds[0])class_output=model.output[:,class_idx]last_conv_layer=model.get_layer("block5_conv3")这里我们先看一下顶级预测图片。所以我们得到了图像的预测并索引了得分最高的类别。请记住,我们可以计算任意类的特征图。然后,我们可以取VGG16中最后一个卷积层的输出block5_conv3。生成的特征图大小应为14×14×512。grads=K.gradients(class_output,last_conv_layer.output)[0]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])foriinrange(512):conv_layer_output_value[:,:,i]*=pooled_grads_value[i]如上所述,我们计算相似输出值的梯度关于到特征图。然后,我们沿着通道维度以外的轴汇集梯度。***,我们用计算出的梯度值对输出特征图进行加权。heatmap=np.mean(conv_layer_output_value,axis=-1)heatmap=np.maximum(heatmap,0)heatmap/=np.max(heatmap)然后,我们将加权后的featuremaps沿通道维度进行平均,得到大小为一张14*14的热图。***,我们对heatmap进行归一化,使其值在0到1之间。img=cv2.imread(img_path)heatmap=cv2.resize(heatmap,(img.shape[1],img.shape[0]))heatmap=np.uint8(255*heatmap)heatmap=cv2.applyColorMap(heatmap,cv2.COLORMAP_JET)superimposed_img=cv2.addWeighted(img,0.6,heatmap,0.4,0)cv2.imshow("原始",img)cv2.imshow("GradCam",superimposed_img)cv2.waitKey(0)***,我们使用OpenCV读取图像并将得到的热图缩放到原始图像大小。我们混合原始图像和热图,将热图叠加到图像上。从上图可以清楚地看出,CNN在图像中寻找的是区分这些类的位置。该技术不仅适用于本地化,还适用于视觉问答、图像标注等,对调试数据需求构建精准模型也有很大帮助。虽然这种技术不涉及太多参数调整,但我们可以使用额外的数据和数据增强技术来更好地泛化模型。原文链接:http://www.hackevolve.com/where-cnn-is-looking-grad-cam/almosthuman2014)》]点此阅读本作者更多好文
