基于keras的LeNet-5模型可视化、网络特征可视化及kernel可视化

基于keras的LeNet-5模型可视化、网络特征可视化及kernel可视化

  卷积神经网络中模型、层中输出的特征和kernel的可视化,对卷积神经网络的设计起到很重要的帮助。在此,以最简单的LeNet-5和手写数字集为例,对LeNet-5进行模型可视化、网络中特征可视化话及kernel可视化。代码链接在本文最后。


1. LeNet-5详解

  LeNet5 这个网络虽然很小,但是它包含了深度学习的基本模块:卷积层,池化层,全链接层。是其他深度学习模型的基础, 这里我们对LeNet5进行深入分析。同时,通过实例分析,加深对与卷积层和池化层的理解。
  LeNet-5网络模型结构
  LeNet-5共有7层,不包含输入,每层都包含可训练参数;每个层有多个Feature Map,每个FeatureMap通过一种卷积滤波器提取输入的一种特征,然后每个FeatureMap有多个神经元。
   各层参数详解:
   1、INPUT层-输入层
   首先是数据 INPUT 层,输入图像的尺寸统一归一化为32*32。
   注意:本层不算LeNet-5的网络结构,传统上,不将输入层视为网络层次结构之一。
   2、C1层-卷积层
   输入图片:32*32
   卷积核大小:5*5
   卷积核种类:6
   输出featuremap大小:28*28 (32-5+1)=28
   神经元数量:28*28*6
   可训练参数:(5*5+1) * 6(每个滤波器5*5=25个unit参数和一个bias参数,一共6个滤波器)
   连接数:(5*5+1)*6*28*28=122304
   3、S2层-池化层(下采样层)
   输入:28*28
   采样区域:2*2
   采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
   采样种类:6
   输出featureMap大小:14*14(28/2)
   神经元数量:14*14*6
   可训练参数:2*6(和的权+偏置)
   4、C3层-卷积层
   输入:S2中所有6个或者几个特征map组合
   卷积核大小:5*5
   卷积核种类:16
   可训练参数:6*(3*5*5+1)+6*(4*5*5+1)+3*(4*5*5+1)+1*(6*5*5+1)=1516
   连接数:10*10*1516=151600
   5、S4层-池化层(下采样层)
   输入:10*10
   采样区域:2*2
   采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
   采样种类:16
   输出featureMap大小:5*5(10/2)
   神经元数量:5*5*16=400
   可训练参数:2*16=32(和的权+偏置)
   连接数:16*(2*2+1)*5*5=2000
  6、C5层-卷积层
  输入:S4层的全部16个单元特征map(与s4全相连)
  卷积核大小:5*5
  卷积核种类:120
  输出featureMap大小:1*1(5-5+1)
  可训练参数/连接:120*(16*5*5+1)=48120
  7、F6层-全连接层
  输入:c5 120维向量
  计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数输出。
  可训练参数:84*(120+1)=10164
  8、Output层-全连接层
  Output层也是全连接层,共有10个节点,分别代表数字0到9,且如果节点i的值为0,则网络识别的结果是数字i。采用的是径向基函数(RBF)的网络连接方式。假设x是上一层的输入,y是RBF的输出,则RBF输出的计算方式是:
  RBF输出的计算方式
  上式w_ij 的值由i的比特图编码确定,i从0到9,j取值从0到7*12-1。RBF输出的值越接近于0,则越接近于i,即越接近于i的ASCII编码图,表示当前网络输入的识别结果是字符i。该层有84x10=840个参数和连接。


2. 基于Keras的LeNet-5的实现

from keras.models import Sequential
from keras.layers import Dense,Flatten
from keras.layers.convolutional import Conv2D,MaxPooling2D
from keras.utils.np_utils import to_categorical
from keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape((-1,28,28,1))  
y_train = to_categorical(y_train,10)   
x_test = x_test.reshape((-1,28,28,1))  
y_test = to_categorical(y_test,10) 

#model=load_model('E:/LeNet/LeNet-5_model.h5')
model = Sequential()
model.add(Conv2D(6,(5,5),strides=(1,1),input_shape=(28,28,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Conv2D(16,(5,5),strides=(1,1),padding='valid',activation='relu',kernel_initializer='uniform'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(120,activation='relu'))
model.add(Dense(84,activation='relu'))
model.add(Dense(10,activation='softmax'))
model.compile(optimizer='sgd',loss='categorical_crossentropy',metrics=['accuracy'])
model.summary()

model.fit(x_train,y_train,batch_size=100,epochs=50,shuffle=True)
model.save('E:/LeNet/LeNet-5_model.h5')
#[0.10342620456655367 0.9834000068902969]
loss, accuracy=model.evaluate(x_test, y_test,batch_size=100)
print(loss, accuracy)

3. LeNet-5模型可视化

  keras有模块可视化工具,可以以图片方式可视化网络结构,但在这之前需要先安装下面的包:  
  pip install pydot
  pip install graphviz  
  但安装完上面的包后,直接运行还是会报错。实际上问题在于执行plot_model需要graphviz的二进制文件,解决方法是在graphviz官网下载界面http://www.graphviz.org/download/选择自己操作系统对应的版本的.msi文件
  例如Windows的下载链接是https://graphviz.gitlab.io/_pages/Download/windows/graphviz-2.38.msi,安装完成后将安装的Graphviz2.38/bin添加环境变量即可。
  在代码中添加

from keras.utils import plot_model
plot_model(model, to_file='model.png',show_shapes=True)

  生成的模型结构图片如下
  LeNet-5模型可视化图片


4. 网络特征可视化

#----------------------------------各个层特征可视化-------------------------------
#查看输入图片
from keras import backend as K
from keras.models import load_model
import numpy as np
import matplotlib.pyplot as plt
from keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()
#加载前面保存的模型
model=load_model('E:/LeNet/LeNet-5_model.h5')
#查看输入图片
fig1,ax1 = plt.subplots(figsize=(4,4))
ax1.imshow(np.reshape(x_test[12], (28, 28)))
plt.show()

image_arr=np.reshape(x_test[12], (-1,28, 28,1))
#可视化第一个MaxPooling2D
layer_1 = K.function([model.layers[0].input], [model.layers[1].output])
# 只修改inpu_image
f1 = layer_1([image_arr])[0]
# 第一层卷积后的特征图展示,输出是(1,12,12,6),(样本个数,特征图尺寸长,特征图尺寸宽,特征图个数)
re = np.transpose(f1, (0,3,1,2))
for i in range(6):
    plt.subplot(2,4,i+1)
    plt.imshow(re[0][i]) #,cmap='gray'  
plt.show()
#可视化第二个MaxPooling2D
layer_2 = K.function([model.layers[0].input], [model.layers[3].output])
f2 = layer_2([image_arr])[0]
# 第一层卷积后的特征图展示,输出是(1,4,4,16),(样本个数,特征图尺寸长,特征图尺寸宽,特征图个数)
re = np.transpose(f2, (0,3,1,2))
for i in range(16):
    plt.subplot(4,4,i+1)
    plt.imshow(re[0][i]) #, cmap='gray'
plt.show() 

运行结果:
输入图片
第一个MaxPooling2D
第二个MaxPooling2D


5. kernel可视化

from keras import backend as K
from keras.models import load_model
import numpy as np
import matplotlib.pyplot as plt
model=load_model('E:/LeNet/LeNet-5_model.h5')
#----------------------------------可视化滤波器-------------------------------

#将张量转换成有效图像
def deprocess_image(x):
    # 对张量进行规范化
    x -= x.mean()
    x /= (x.std() + 1e-5)
    x *= 0.1
    x += 0.5
    x = np.clip(x, 0, 1)
    # 转化到RGB数组
    x *= 255
    x = np.clip(x, 0, 255).astype('uint8')
    return x

for i_kernal in range(10):
    input_img=model.input
    ## 构建一个损耗函数,使所考虑的层的第n个滤波器的激活最大化,-1层softmax层
    loss = K.mean(model.layers[-1].output[:,i_kernal])
    # loss = K.mean(model.output[:, :,:, i_kernal])
    # 计算输入图像的梯度与这个损失
    grads = K.gradients(loss, input_img)[0]
    # 效用函数通过其L2范数标准化张量
    grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)
    # 此函数返回给定输入图像的损耗和梯度
    iterate = K.function([input_img, K.learning_phase()], [loss, grads])
    # 从带有一些随机噪声的灰色图像开始
    np.random.seed(0)
    #图像通道
    num_channels=1
    #输入图像尺寸
    img_height=img_width=28
    #归一化图像
    input_img_data = (255- np.random.randint(0,255,(1,  img_height, img_width, num_channels))) / 255.
    failed = False
    # run gradient ascent
    print('####################################',i_kernal+1)
    loss_value_pre=0
     # 运行梯度上升500步
    for i in range(500):
        loss_value, grads_value = iterate([input_img_data,1])
        if i%10 == 0:
            # print(' predictions: ' , np.shape(predictions), np.argmax(predictions))
            print('Iteration %d/%d, loss: %f' % (i, 500, loss_value))
            print('Mean grad: %f' % np.mean(grads_value))


            if all(np.abs(grads_val) < 0.000001 for grads_val in grads_value.flatten()):
                failed = True
                print('Failed')
                break
            # print('Image:\n%s' % str(input_img_data[0,0,:,:]))
            if loss_value_pre != 0 and loss_value_pre > loss_value:
                break
            if loss_value_pre == 0:
                loss_value_pre = loss_value

            # if loss_value > 0.99:
            #     break

        input_img_data += grads_value * 1 #e-3
    plt.subplot(2,5, i_kernal+1)
    # plt.imshow((process(input_img_data[0,:,:,0])*255).astype('uint8'), cmap='Greys') #cmap='Greys'
    img_re = deprocess_image(input_img_data[0])
    img_re = np.reshape(img_re, (28,28))
    plt.imshow(img_re) #cmap='Greys'
plt.show()

运行结果:
layer-1
layers[3]
这里写图片描述


GitHub连接:https://github.com/1057520143/LeNet
码云连接:https://gitee.com/liao1057520143/LeNet


参考博客:
https://blog.csdn.net/xinfeng2005/article/details/78697415
http://cuijiahua.com/blog/2018/01/dl_3.html
https://blog.csdn.net/da_kao_la/article/details/80025124

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值