Python深度学习读书笔记(五)(卷积神经网络可视化)

卷积神经网络的可视化:可视化卷积神经网络中间输出(中间激活),可视化卷积神经网络的过滤器,可视化图像中类激活的热力图。

  1. 可视化中间激活:对于指定输入,展示网络中各个卷积层和池化层输出的特征图(层的输出通常叫做层的激活)

         特征图中,第一层是更重边缘探测器的集合,随着层数加深,激活变得越来越抽象,激活的稀疏度随着层数的加深而增大。

          深度神经网络可以有效的作为信息蒸馏管道,输入原始数据,反复对其进行变换,过滤无关信息,放大和细化有用的信息。

from keras.models import load_model
model=load_model('cats_and_dogs_small_2.h5')
model.summary()

#预处理单张图像
img_path='D:\\jupyter_code\\kaggle\\train1\\test\\cats\\cat.1700.jpg'
from keras.preprocessing import image
import numpy as np
#图像预处理为一个4D张量
img=image.load_img(img_path,target_size=(150,150))
#将python图像库转换为一个numpy数组
img_tensor=image.img_to_array(img)
#拓展转换后的数组形状,完成4D张量的转换
img_tensor=np.expand_dims(img_tensor,axis=0)
img_tensor/=255.

print(img_tensor.shape)

import matplotlib.pyplot as plt
plt.imshow(img_tensor[0])
plt.show()

#用输入输出张量列表将模型实例化,(图像批量作为输入,输出所有卷积层的激活)
from keras import models
#提取前8层的输出
layer_outputs=[layer.output for layer in model.layers[:8]]
activation_model=models.Model(inputs=model.input,outputs=layer_outputs)
#返回8个Numpy数组组成的列表,每个层对应激活一个numpy数组。
activations=activation_model.predict(img_tensor)

first_layer_activation=activations[0]
print(first_layer_activation.shape)
#打印特征图形状可以看到有32个通道,每层对应4个通道

#将第7个通道可视化
import matplotlib.pyplot as plt
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_names,layer_activation in zip(layer_names,activations):
    #特征图中特征格式
    n_feature=layer_activation.shape[-1]
    #特征形状
    size=layer_activation.shape[1]
    n_cols=n_feature//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]
            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[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_names)
            plt.grid(False)
            plt.imshow(display_grid,aspect='auto',cmap='viridis')

 

2.可视化卷积神经网络的过滤器(显示过滤器响应的视觉模式)

显示每个过滤器所响应的视觉模式,通过在输入空间中进行梯度上升来实现:从空白输入图像开始,将梯度下降应用于卷积神经网络输入图像的值,目的是让某个过滤器的响应最大化。得到的输入图像是选定过滤器具有最大响应的图像。

卷积神经网络中每一层都设置一组过滤器,以便其输入表示为过滤器的组合。随着层数加深,卷积神经网络中过滤变得越来越复杂,越来越精细。

#可视化卷积神经网络的过滤器

#为过滤器的可视化定义损失张量
from keras.applications import VGG16
#此处的k为TensorFlow
from keras import backend as K

model=VGG16(weights='imagenet',include_top=False)

layer_name='block3_conv1'
filter_index=0

layer_output=model.get_layer(layer_name).output
loss=K.mean(layer_output[:,:,:,filter_index])
#获取损失相对于输入的梯度,此处K.gradients相当于tf.gradients,实现对ys(loss),xs(model.input)求导
grads=K.gradients(loss,model.input)[0]
#梯度标准化技巧
grads/=(K.sqrt(K.mean(K.square(grads)))+1e-5)

#给定Numpy输入值,得到Numpy输出值
#iterare将一个Numpy张量转换为2个Numpy张量组成的列表
iterate=K.function([model.input],[loss,grads])
import numpy as np
loss_value,grads_value=iterate([np.zeros((1,150,150,3))])

#通过随机梯度下降让损失最大化
input_img_data=np.random.random((1,150,150,3))*20+128
#每次梯度更新的步长
step=1.
for i in range(40):
    #计算损失值和梯度值
    loss_value,grads_value=iterate([input_img_data])
    #沿着让损失最大化的方向调节输入图像(梯度上升)
    input_img_data+=grads_value*step
    
#将张量转换为有效图像的使用函数
def deprocess_image(x):
    #张量标准化,均值为0 ,标准差为0.1
    x-=x.mean()
    x/=(x.std()+1e-5)
    x*=0.1
    #将x裁剪到(0,1)区间
    x+=0.5
    x=np.clip(x,0,1)
    #x转RGB数组
    x*=255
    x=np.clip(x,0,255).astype('uint8')
    return x

#生成过滤器的可视化函数
def generate_pattern(layer_name,filter_index,size=150):
    #构建损失函数,该层第n个过滤器的激活最大化
    layer_output=model.get_layer(layer_name).output
    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])
    
    input_img_data=np.random.random((1,size,size,3))*20+128
    #运行40次梯度上升
    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]
    return deprocess_image(img)

plt.imshow(generate_pattern('block3_conv1',0))

layer_name='block2_conv1'
size=64
margin=5

results=np.zeros((8*size+7*margin,8*size+7*margin,3))

for i in range(8):
    for j in range(8):
        filter_img=generate_pattern(layer_name,i+(j*8),size=size)
        
        horizontal_start=i*size+i*margin
        horizontal_end=horizontal_start+size
        vertical_start=j*size+j*margin
        vertical_end=vertical_start+size
        
        results[horizontal_start:horizontal_end,vertical_start:vertical_end,:]=filter_img
        
plt.figure(figsize=(20,20))
plt.imshow(results)

3.可视化类激活的热力图(了解一张图像的那一部分让神经网络做出了分类决策)

类激活图可视化:类激活热力图是与特定输出类别相关的二维分数网络,对任何输入图像的每个位置都要进行计算,表示每个位置对类别的重要程度。

实现方法:给定输入图像,对于卷积层的输出特征图,用类别相对于通道的梯度对这个特征图这个每个通道进行加权。

由“每个通道类别的重要程度”对 “不同通道激活程度”的空间图加权,得到“类别激活程度”(A->B)&(A->C)à(B->C)

你可能感兴趣的:(读书笔记)