更多详情,请点击链接。
在前面的章节中,我们介绍了卷积网络的工作原理,并通过代码实践体验了卷积网络在图像信息提取中的有效性。现在一个问题是,我们知道卷积网络的运算过程,却不知道它为什么能有效识别图片。也就是说,我们知道它是什么却不知道它是为什么。在本节中,我们将了解卷积网络如何通过可视化从图片中提取有效信息。
自2013年以来,研究人员发现了许多有效的可视化方法来研究卷积网络对图片信息的学习过程。通过可视化呈现,我们人类可以有效地认识卷积网络的学习过程。我们会直观的看到体积和网络的每一层是如何提取图片信息的,然后直观的展示Max Pooling层的作用。先来看看我们自己的网络是怎么学习图片的。卷积网络会对图片数据进行逐层计算和过滤,我们把过滤后的数据“画”出来看看。首先,让我们加载在前两部分中训练的网络:
从keras.models导入load_model
#在前面的部分中,在训练网络之后,我们使用以下名称存储训练好的网络。现在我们重新加载它。
model=load _ model(' cats _ and _ dogs _ small _ 2 . H5 ')
模型.摘要()
您可以查看前面几节中的代码。到时候,训练完网络,我们就储存起来。现在,我们将存储的网络重新载入内存。上述代码运行后,结果如下:
从上面的结果,我们可以看到,我们的网络有几个卷积层和最大池层。我们用一张图片进入网络,每一层都会对图片进行计算,然后提取信息。我们将从每一层提取的信息画出来看看。我们先加载一张图片,在上面做一些数据转换,然后把图片画出来看看:
img _ path='/users/陈一/documents/人工智能/all/cats _ and _ dogs _ small/test/cats/cat . 1700 . jpg '
预处理导入图像
将numpy作为np导入
将matplotlib.pyplot作为plt导入
#将图片缩小到150*150像素
img=image.load_img(img_path,target_size=(150,150))
img _张量=image.img_to_array(img)
img _ tensor=NP . expand _ dims(img _ tensor,轴=0)
#在0和1之间转换像素值。
img_tensor /=255。
打印(img_tensor.shape)
图表()
plt.imshow(img_tensor0)
上述代码运行后,结果如下:
我们分别提取网络中的前八层,即包含卷积和最大池的网络层,代码如下:
从keras导入模型
将matplotlib.pyplot作为plt导入
'''
我们提取网络的前八层,即包含卷积和最大池的网络层,
以下代码将把前八层网络的输出结果放入数组layers_outputs中。
'''
layer_outputs=
activation_model=模型。模型(输入=模型.输入,输出=图层_输出)
#执行下面的代码后,我们可以在图片上得到卷积层和max pooling层的计算结果。
activations=activation _ model . predict(img _张量)
#我们把第一层卷积网络的识别结果画到图片信息上。
first _ layer _ activation=activations 0
打印(first_layer_activation.shape)
图表()
PLT . matshow(first _ layer _ activation 0,4,cmap='viridis ')
上面的代码专门提取了网络的前八层包括卷积和max pooling,然后传入上图。这八个网络层将从图片中分离出来。
抽取信息,上面代码把第一次卷积层从图片中获取的信息绘制出来,上面代码运行结果如下:大家看的上面图片就是第一层卷积网络从原图片中抽取出来的信息。网络层获得的信息表示是148*14832,也就是抽取出的图像大小是148\148个像素,其中每个像素对应一个含有32个元素的向量,我们只把向量中前4个元素表示的信息视觉化,如果我们把前7个元素视觉化看看,其代码如下:
plt.figure()
plt.matshow(first_layer_activation<0, :, : , 7>, cmap = 'viridis')
上面代码运行结果如下,注意你自己运行结果跟我很可能不一样,因为网络对图像的学习结果与它所运行的环境相关,不是确定性的:
上面结果表明网络把绿色值高的像素点抽取出来了。接下来我们用代码把每一层卷积运算后所识别的图片信息绘制出来:
layer_names = <>
for layer in model.layers<:8>:
layer_names.append(layer.name)
images_per_row = 16
for layer_name, layer_activation in zip(layer_names, activations):
#layer_activation的结构为(1, width, height, array_len)
#向量中的元素个数
n_features = layer_activation.shape<-1>
#获得切片的宽和高
size = layer_activation.shape<1>
#在做卷积运算时,我们把图片进行3*3切片,然后计算出一个含有32个元素的向量,这32个元素代表着网络从3*3切片中抽取的信息
#我们把这32个元素分成6列,绘制在一行里
n_cols = n_features // images_per_row
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>
#这32个元素中,不一定每个元素对应的值都能绘制到界面上,所以我们对它做一些处理,使得它能画出来
channel_image -= channel_image.mean()
channel_image /= channel_image.std()
channel_image *= 64
channel_image += 128
channel_image = np.clip(channel_image, 0, 255).astype('uint8')
display_grid
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')
上面代码运行后,得到的部分结果如下:
上图表示的是,第一次卷积网络从图片中抽取处理的信息,它主要抽取猫的边缘,经过第一层后,原来图片的很多信息还保留着,这些信息将交由后面的卷积网络继续抽取,我再看看最后一层网络抽取出来的信息:
随着卷积网络的层次越高,它抽取出的信息就越抽象,就越难以被人的直觉所理解。我们把卷积层对图片的识别结果绘制出来,从中我们能观察到,网络层次越高,对图片所表示规律的抽取越深,它展现出来就越抽象,这些抽象特性可能表示所有猫所具备的共同特质,神经网络就如同信息抽取蒸馏管,每经过一处,图片中包含的噪音就去除掉一层,网络就越能得到越纯粹的该类图片所表示的共同信息。
这个过程与人的认知过程很像,我们看几张猫图片后,就能够把世界上所有的猫都识别出来,我们并没有看到黑猫图片后,给一只白猫就认不出来,因此人通过视觉把图像传送到脑中后,脑神经通过层层运算,把图像中蕴含的本质信息抽取出来,于是人看到一张黑猫的图片,就把其中蕴含的“猫”的抽象信息获取,下次看到一只白猫时,大脑也把白猫所表示的“猫”的抽象信息获取到,两者一比对,大脑就知道,黑猫白猫本质上是同一类事物。加入让你绘制一个骑自行车的人,我们大多数人都会画出如下形式:
上面图案表示着我们对“人其自行车”的概念性,抽象认知,我们看到任何骑自行车的人,我们都会抽象出上面这幅图案,我们把各种无关的信息取出掉,例如背景,人的衣服,形态等,无关紧要的信息全部去光后,就会得到上面的信息。