这也说明了在输入图像像素细微改变时输出类别将如何产生变化。梯度的所有正值都表明,像素值的细微变化会增加输出值:
这些梯度与图像的形状相同(梯度是针对每个像素计算的),对直观感觉产生影响。
那么如何生成显著图呢?首先使用下述代码读取输入图像。
然后,通过VGG16模型生成显著图:
- # Utility to search for layer index by name.
- # Alternatively we can specify this as -1 since it corresponds to the last layer.
- layer_idx = utils.find_layer_idx(model, 'predictions')
-
- # Swap softmax with linear
- model.layers[layer_idx].activation = activations.linear
- model = utils.apply_modifications(model)
-
- #generating saliency map with unguided backprop
- grads1 = visualize_saliency(model, layer_idx,filter_indices=None,seed_input=image)
- #plotting the unguided saliency map
- plt.imshow(grads1,cmap='jet')
可以看到,模型更加关注狗的面部。下图呈现了使用导向反向传播后的结果:
- #generating saliency map with guided backprop
- grads2 = visualize_saliency(model, layer_idx,filter_indices=None,seed_input=image,backprop_modifier='guided')
- #plotting the saliency map as heatmap
- plt.imshow(grads2,cmap='jet')
导向反向传播将所有的负梯度变为0,即只更新对类别概率有积极影响的像素。
CAM(Class Activation Maps)(梯度加权)
CAM也是一种神经网络可视化技术,基本原理是根据其梯度或对输出的贡献来权衡激活图。
以下节选自Grad-CAM论文给出了该技术的要点:
本质上,只需取用最后一个卷积层的特征映射,并使用相对于特征图的输出梯度对每个滤波器进行加权(相乘),就能达到目的。生成加权梯度类激活图的过程包括以下步骤:
- 利用最后一层卷积层输出的特征图。对于VGG16来说,该特征映射的大小为14x14x512。
- 计算输出与特征图相对应的梯度。
- 进行梯度全局平均池化。
- 将特征映射与相应的池化梯度相乘。
可以看到输入图像及其对应的类激活图如下:
下图为类激活图。
将过程分层输出可视化
卷积神经网络的起始层通常寻求边缘(edge)等小的细节信息。随着对模型的深入了解,其特征也会发生变化。
对于模型不同层输出的可视化可以直观地呈现图像在相应层上突出显示的特性。为了针对后续问题进行架构微调,可视化是非常重要的一步。因为我们可以看到不同层的不同特性,并决定模型中使用的具体层。
例如,在比较神经风格迁移问题中不同层的性能时,可视化输出可以给予极大的助力。
下述程序展示了如何实现VGG16模型的不同层的输出:
- #importing required libraries and functions
- from keras.models import Model
- #defining names of layers from which we will take the output
- layer_names = ['block1_conv1','block2_conv1','block3_conv1','block4_conv2']
- outputs = []
- imageimage = image.reshape((1, image.shape[0], image.shape[1], image.shape[2]))
- #extracting the output and appending to outputs
- for layer_name in layer_names:
- intermediate_layer_model = Model(inputs=model.input,outputs=model.get_layer(layer_name).output)
- intermediate_output = intermediate_layer_model.predict(image)
- outputs.append(intermediate_output)
- #plotting the outputs
- fig,ax = plt.subplots(nrows=4,ncols=5,figsize=(20,20))
-
- for i in range(4):
- for z in range(5):
- ax[i][z].imshow(outputs[i][0,:,:,z])
- ax[i][z].set_title(layer_names[i])
- ax[i][z].set_xticks([])
- ax[i][z].set_yticks([])
- plt.savefig('layerwise_output.jpg')
如图所示,VGG16(除block5外)的每一层都从图像中提取了不同特征。起始层对应的是类似边缘的低级特征,而后一层对应的是车顶、排气等特征。
结语
(编辑:ASP站长网)
|