《AI安全之对抗样本入门》—1.3.9 可视化CNN

举报
华章计算机 发表于 2019/06/17 16:11:07 2019/06/17
【摘要】 本节书摘来自华章计算机《AI安全之对抗样本入门》一书中的第1章,第1.3.9节,作者是兜哥。

1.3.9 可视化CNN

CNN虽然接近人类识别物体的过程,但是理解CNN的原理却是非常艰难的过程。人们试图用可视化的方式来理解CNN各层对图像特征提取的方法。Keras之父、谷歌大脑人工智能和深度学习研究员Francois Chollet 在他的《Python深度学习》中给出一种可视化卷积的方法。卷积层通常由多个卷积核组成,每个卷积核都可以被视为一种特征提取方式。当使用一个卷积核处理图像数据后,卷积核会提取它关注的特征并形成新的图像,该图像也被称为特征图。输入的图像包含的特征与卷积核越接近,其特征图的值也越大。因此完全可以基于梯度,迭代调整输入图像的值,让特征图的值最大化。当特征图的值达到最大或者迭代求解趋于稳定时,可以认为这时的输入图像就是该卷积核的可视化图像。下面以Keras为例介绍核心代码实现。

image.png

 image.png

图1-23 Inception单元结构

#获取输出层的tensor

layer_output = model.get_layer(layer_name).output

#获取指定卷积核filter_index的输出,并作为损失函数

loss = K.mean(layer_output[:, :, :, filter_index])

#根据损失函数和输入层定义梯度

grads = K.gradients(loss, model.input)[0]

grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)

#实例化计算梯度的函数

iterate = K.function([model.input], [loss, grads])

#定义一个随机图像,图像底色为灰色,并叠加均值为0标准差为20的高斯噪声

input_img_data = np.random.random((1, size, size, 3)) * 20 + 128.

#迭代40轮,使用梯度上升算法求解,学习速率(步长)为step

step = 1.

for i in range(40):

        loss_value, grads_value = iterate([input_img_data])

        input_img_data += grads_value * step     

img = input_img_data[0]

以VGG16为例,如图1-24所示,在VGG16中具有多个卷积层,其中最典型的5个分别为block1_conv1、block2_conv1、block3_conv1、block4_conv1和block5_conv1。

image.png

Francois Chollet 使用上述方法可视化了这5个卷积层,block1_conv1的可视化结果如图1-25所示,block3_conv1的可视化结果如图1-26所示,block5_conv1的可视化结果如图1-27所示,可见第1层卷积提取的主要是边缘和纹路特征,越往后的卷积提取的特征越高级,到了第5层卷积已经提取很抽象的高级特征了。

 image.png

图1-25 block1_conv1可视化结果

下面我们以经典的小猪图像为例,展现在VGG16下各个卷积层处理的情况,相应的代码路径为:

https://github.com/duoergun0729/adversarial_examples/code/1-case2-keras.ipynb

首先实例化Keras下的VGG16模型,加载基于ImageNet 2012数据集预训练的参数。

 image.png

图1-26 block3_conv1可视化结果

#使用VGG16

from keras.applications.vgg16 import VGG16

import matplotlib.pyplot as plt

%matplotlib inline

model = VGG16(weights='imagenet')

之后加载经典的小猪图片(见图1-28),并进行预处理。

from keras.preprocessing import image

from keras.applications.vgg16 import preprocess_input, decode_predictions

import numpy as np

#小猪的路径

img_path = "../picture/pig.jpg"

#缩放到指定大小 224×224

img = image.load_img(img_path, target_size=(224, 224))

#展示图片

plt.imshow(img)

plt.show()

x = image.img_to_array(img)

# 扩展维度,适配模型输入大小 (1, 224, 224, 3)

x = np.expand_dims(x, axis=0)

# 图像预处理

x = preprocess_input(x)

 image.png

图1-27 block5_conv1可视化结果

对该图片进行预测,预测结果为小猪,满足预期。

 image.png

图1-28 经典的小猪图片

preds = model.predict(x)

print('Predicted:', decode_predictions(preds, top=3)[0])

Predicted: [('n03935335', 'piggy_bank', 0.6222573), ('n02395406', 'hog',

0.3228228), ('n02108915', 'French_bulldog', 0.013370045)]

获取block1_conv1、block3_conv1和block5_conv1对应的输出tensor,并基于VGG16定义新的模型,该模型的输入为图像,输出为以上三层的输出tensor。

from keras import models

layer_names=['block1_conv1', 'block3_conv1','block5_conv1']

# 获取指定层的输出:

layer_outputs = [model.get_layer(layer_name).output for layer_name in

layer_names]

# 创建新的模型,该模型的输出为指定的层的输出

activation_model = models.Model(inputs=model.input, outputs=layer_outputs)

针对小猪图像进行预测,获得指定层的输出结果。

#获得小猪的输出

activations = activation_model.predict(x)

遍历block1_conv1、block3_conv1和block5_conv1的各个卷积核的输出并可视化。这里需要指出的是,卷积核的输出结果的范围并不是固定的,为了可以展示成图片,需要根据对应的均值channel_image.mean()和标准差channel_image.std()进行归一化,然后再转换到图片对应的像素范围[0, 255]。为了便于显示,每层以8×8的格式展示前64个卷积核对应的图像。block1_conv1层可视化的结果如图1-29所示,block3_conv1层可视化的结果如图1-30所示,block5_conv1层可视化的结果如图1-31所示。可见第1层卷积层提取特征时尽可能保留了原图的细节,越往后的卷积层提取的特征越高级,保留原始图片的细节越来越少。到了最后几层,出现的空白越来越多,这意味着部分卷积核无法在图像中匹配特定的特征了,这也意味着越高级别的特征对应的矩阵越稀疏。

 image.png

图1-29 小猪图片在block1_conv1层的可视化结果

images_per_row = 8

for layer_name, layer_activation in zip(layer_names, activations):

    # 获取卷积核的个数

    n_features = layer_activation.shape[-1]

    # 特征图的形状 (1, size, size, n_features)

    size = layer_activation.shape[1]

    #最多展现8行

    n_cols=8

    display_grid = np.zeros((size * n_cols, images_per_row * size))

    for col in range(n_cols):

        for row in range(images_per_row):

            channel_image = layer_activation[0,:, :,

                                               col * images_per_row + row]

            # 归一化处理

            channel_image -= channel_image.mean()

            channel_image /= channel_image.std()

            # 数据扩展到[0,255]范围

            channel_image *= 128

            channel_image += 128   

            channel_image = np.clip(channel_image, 0, 255).astype('uint8')

            display_grid[col * size : (col + 1) * size,

                         row * size : (row + 1) * size] = channel_image

    # 展示图片

    scale = 1. / size

    plt.figure(figsize=(scale * display_grid.shape[1],

                        scale * display_grid.shape[0]))

    plt.title(layer_name)

    plt.grid(False)

    plt.imshow(display_grid, aspect='auto', cmap='viridis')

plt.show()

image.png

 image.png

图1-31 小猪图片在block5_conv1层的可视化结果


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。