序
一直很好奇,CNN的N个feature maps出来的图像是怎样的图像;是怎么提取原始图像的特征。虽然知道 features map,也就是特征图,理应是跟原始图像的某一部分相似,才能有效地提取出原始图像的特征,也就是之前CNN理解文章里面关于老鼠的介绍,要提取老鼠的某一个身体形状,对应的特征图,必定是跟老鼠形状相似的特征图,才能提取处出来。即当filter和我们的原始图像的对应部分越像,它们卷积的结果就会越大,因此输出的像素点就越亮
所以这次将会试着把原始图的几个layers的所有特征图可视化。看看CNN网络是怎么提取特征。
(1)提取VGG pretrain模型
vgg = tf.keras.applications.VGG19(include_top=False, weights='imagenet')
vgg.trainable = False
#打印所有的layers
for layer in vgg.layers:
print(layer.name)
我们将会提取 以下五层的layers的features map作为一个演示
#直接提取VGG的layers
layers = [vgg.get_layer('block1_conv1'),
vgg.get_layer('block2_conv1'),
vgg.get_layer('block3_conv1'),
vgg.get_layer('block4_conv1'),
vgg.get_layer('block5_conv1')]
#创建模型,将会输出五个layers的output,即feature maps
outputs= [layer.output for layer in layers]
model = tf.keras.Model([vgg.input], outputs)
(2)可视化
def plot_convolutional_filters(img):
img = np.expand_dims(img, axis=0) #多加一个维度
pred = model.predict(img) #应该会输出五个layers的predict的feature maps
images_per_row = 8
for layer_name, layer_pred in zip(layer_names, pred):
n_features = layer_pred.shape[-1] #features 数
size = layer_pred.shape[1] #应该是 5 ,因为有5个layers
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_pred[0,:, :, col * images_per_row + row]
#===============================================================
#normalize image
channel_image -= channel_image.mean()
channel_image /= channel_image.std()
#range between 0,1
#===============================================================
channel_image *= 64
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='gray')
原始图片为:
def image_process(path):
image = Image.open(path).convert('RGB')
image = image.resize((657,657))
image = np.array(image)/255
return image
content_path = tf.keras.utils.get_file('YellowLabradorLooking_new.jpg', 'https://storage.googleapis.com/download.tensorflow.org/example_images/YellowLabradorLooking_new.jpg')
img = image_process(content_path)
plt.imshow(img)
它的filters 可视化的结果如下 :
(3)总结解释
首先,仔细观察block1_conv1层的特征图
我们可以看得出,这一层,主要是做边缘检测,即狗狗的大小,而且也有颜色的区分,这一层在努力把狗的颜色给识别出来。 当我们看到block2_conv1出来的图像,这里几乎完全都是形状的捕捉。所以浅层做的主要是边缘识别,颜色识别等等特征。
而深层的特征图,因为经过反复的卷积,这里的特征图大小会缩小,越来越“像素化,因此这里的特征图对应的都是原始图片的一个细节,一个特征,所以特征图出来的都是某一个部位特别发白(因为我用了gray的颜色),所以发亮就是发白。 所以深层可以激活图片的显著特征,比如狗狗的手脚,后面的草坪等等特征。
随着CNN的层数增加,每一层的输出图像越来越抽象复杂,因此可以推断,随着CNN的深入,网络层学得的特征越来越高级和复杂。
========================end