深度学习(9): LeNet-5 网络模型小结

在这里插入图片描述

注:转载请标明原文出处链接:https://xiongyiming.blog.csdn.net/article/details/100013565


1989年,Yann Lecun在论文 Gradient-Based Learning Applied to Document Recognition 中提出了LeNet-5网络模型,它是一种用于手写体字符识别的非常高效的卷积神经网络。从此深度学习开始被人们所熟知。 LeNet-5 网络架构的成功应用,不断地推动着深度学习领域的发展。

1 MNIST手写字体数据集

如下图所示,MNIST数据集是一个手写体数据集,该数据集是机器学习领域中非常经典的一个数据集,数据集中每一个样本都是 0 ~ 9 的手写数字,该数据集由 4 部分组成:训练图片集、训练标签集、测试图片集和测试标签集。其中,训练集中有60000个样本,测试集中有10000个样本,每个样本都是一张 28x28 像素的灰度手写数字图片。为了便于存储和下载,官方对 MNIST数据集的图片进行集中处理,将每一张图片拉伸成为 (1, 784) 的向量表示。

在这里插入图片描述
数据集官方网站: http://yann.lecun.com/exdb/mnist/
MNIST数据集一共4个文件,训练集、训练集标签、测试集 和 测试集标签.

在这里插入图片描述



2 LeNet-5 网络模型

LeNet-5 网络模型作为卷积神经网络中的开创性工作,提取了三大思想:

  1. 局部感知

  2. 权值共享

  3. 下采样

因为图像特征分布在图像的像素上,利用卷积操作可以在多个位置提取相类似的特征,于是有了局部感知。另外由于当年并没有计算能力强悍的 GPU 来辅助训练神经网络,因此通过下采样层有效地加快训练和提取更高维特征,能够节省参数和计算,这与当年的技术相比是一个关键的优势。另外原论文中提到,全卷积不应该被放在第一层,图像特征有着高度的空间相关性,因此权值共享可以充分利用图像上的空间相关性。

论文地址
LeCun Y, Bottou L, Bengio Y, et al. Gradient-based learning applied to document recognition [J]. Proceedings of the IEEE, 1998, 86(11): 2278-2324.


LeNet-5模型框图如下图所示:

在这里插入图片描述

LeNet-5共有7层,不包含输入层,每层都包含可训练参数;每个层有多个Feature Map,每个Feature Map通过一种卷积滤波器提取输入的一种特征,然后每个Feature Map有多个神经元。

(1) INPUT层
首先是数据 INPUT 层,输入图像的尺寸统一归一化为 32x32。
注:INPUT层不属于LeNet-5的网络结构,传统上,一般不将INPUT层视为网络层次结构之一。

(2) C1层 (卷积层)
输入图片:32x32
卷积核大小:5x5
卷积核种类:6
输出6个特征图(feature map),每个特征图的大小:28x28

特征图大小的计算公式如下:

(1) o u t p u t h = ( i n p u t h + 2 × p a d d i n g h − k e r n e l h ) / s t r i d e + 1 outpu{t_h} = (inpu{t_h} + 2 \times paddin{g_h} - kerne{l_h})/stride + 1 \tag{1} outputh=(inputh+2×paddinghkernelh)/stride+1(1)

(2) o u t p u t w = ( i n p u t w + 2 × p a d d i n g w − k e r n e l w ) / s t r i d e + 1 outpu{t_w} = (inpu{t_w} + 2 \times paddin{g_w} - kerne{l_w})/stride + 1 \tag{2} outputw=(inputw+2×paddingwkernelw)/stride+1(2)

其中, o u t p u t output output 为卷积操作后得到的特征矩阵的大小, i n p u t input input 为输入矩阵的大小, p a d d i n g padding padding 输入矩阵边界的填充数量, k e r n e l kernel kernel 为卷积核的大小, s t r i d e stride stride 为卷积操作的步长。 h h h w w w 分别为操作矩阵的长和宽,一般来说矩阵为方阵时候, h = w h = w h=w .

对于从 INPUT层 ——> C1层 (卷积层), h = w h = w h=w , i n p u t = 32 input=32 input=32, p a d d i n g = 0 padding=0 padding=0 k e r n e l = 5 kernel=5 kernel=5, s t r i d e = 1 stride=1 stride=1 ,则输出特征图大小为 (28x28):
o u t p u t = ( i n p u t + 2 × p a d d i n g − k e r n e l ) / s t r i d e + 1 = ( ( 32 + 2 × 0 − 5 ) / 1 ) + 1 = 28 output = (input + 2 \times padding - kernel)/stride + 1 = \left( {(32 + 2 \times 0 - 5)/1} \right) + 1 = 28 output=(input+2×paddingkernel)/stride+1=((32+2×05)/1)+1=28

神经元数量:28x28x6
可训练参数:(5x5+1) x 6=156 (每个滤波器5x5=25个unit参数和一个bias参数,一共6个滤波器)
连接数:(5x5+1)x6x28x28=122304

参数详细说明:
对输入图像进行第一次卷积运算(使用 6 个大小为 5x5 的卷积核),得到6个C1特征图(6个大小为28x28的 feature maps, 32-5+1=28)。我们再来看看需要多少个参数,卷积核的大小为5x5,总共就有6x(5x5+1)=156个参数,其中+1是表示一个核有一个bias。
对于卷积层C1,C1内的每个像素都 与 输入图像中的5x5个像素和1个bias有连接,所以总共有 (5x5+1)x6 x 28x28=122304 个连接(connection)。有122304个连接,但是我们只需要学习156个参数,主要是通过权值共享实现的。

(3) S2层-(Pooling层)
输入大小:28x28
采样区域:2x2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid函数
采样种类:6
输出6个特征图(feature map),每个特征图的大小:14x14 (28/2)

神经元数量:14x14x6
连接数:(2x2+1)x6x14x14
S2中每个特征图的大小是C1中特征图大小的1/4。

参数详细说明:
第一次卷积之后紧接着就是Pooling(池化)运算,使用 2x2核 进行Pooling操作,于是得到了S2,6个14x14的特征图(28/2=14)。
S2这个pooling层是对C1中的2x2区域内的像素求和乘以一个权值系数再加上一个偏置bias,然后将这个结果再做一次映射。故同时有(2x2+1)x6x14x14=5880个连接。


(4) C3层 (卷积层)
输入大小:S2中所有6个或者几个特征图(feature map)组合
卷积核大小:5x5
卷积核种类:16
输出16个特征图(feature map),每个特征图的大小:10x10
特征图大小的计算过程如下:
o u t p u t = ( i n p u t + 2 × p a d d i n g − k e r n e l ) / s t r i d e + 1 = ( ( 14 + 2 × 0 − 5 ) / 1 ) + 1 = 10 output = (input + 2 \times padding - kernel)/stride + 1 = \left( {(14 + 2 \times 0 - 5)/1} \right) + 1 = 10 output=(input+2×paddingkernel)/stride+1=((14+2×05)/1)+1=10

C3中的每个特征图是连接到S2中的所有(6个)或者几个特征图的,表示本层的特征图是上一层提取到的特征图的不同组合。

存在的一个方式是:C3的前6个特征图以S2中3个相邻的特征图子集为输入。接下来6个特征图以S2中4个相邻特征图子集为输入。然后的3个以不相邻的4个特征图子集为输入。最后一个将S2中所有特征图为输入。

则可训练参数:6x(3x5x5+1) + 6x(4x5x5+1) + 3x(4x5x5+1) + 1x(6x5x5+1) =1516

连接数:10x10x1516=151600

参数详细说明:
第一次Pooling之后是第二次卷积,第二次卷积的输出是C3,16个10x10的特征图,卷积核大小是 5x5 。我们知道S2 有6个 14x14 的特征图,那么问题来了,如何从6 个特征图得到 16个特征图了?
这里是通过对S2 的特征图特殊组合计算得到的16个特征图。如下图所示:

在这里插入图片描述

  1. C3的前6个特征图(对应上图第1个红框的6列)与S2层相连的3个特征图相连接;
  2. C3的后面6个特征图(上图第2个红框)与S2层相连的4个特征图相连接;
  3. C3的后面3个特征图(上图第3个红框)与S2层部分不相连的4个特征图相连接;
  4. C3的最后一个特征图(上图第4个红框)与S2层的所有特征图相连。
    卷积核大小依然为5x5,所以总共有:6x(3x5x5+1)+6x(4x5x5+1)+3x(4x5x5+1)+1x(6x5x5+1)=1516个参数。
    因为图像大小为10x10,所以共有151600个连接。

C3的前6个特征图(上图第1个红框)与S2中前3个特征图相连的卷积结构如下图所示:

在这里插入图片描述

上图对应的参数为 3x5x5+1,一共进行6次卷积得到6个特征图,所以有6x(3x5x5+1)参数。
那么为什么采用上述这样的组合了?
论文中说有两个原因:

  1. 减少参数;
  2. 这种不对称的组合连接的方式有利于提取多种组合特征。

(5) S4层 (Pooling层)
输入大小:10x10
采样区域:2x2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
采样种类:16
输出16个特征图(feature map),每个特征图的大小:5x5 (10/2)

神经元数量:5x5x16=400
连接数:16x(2x2+1)x5x5=2000

S4中每个特征图的大小是C3中特征图大小的1/4

参数详细说明:
S4是pooling层,窗口大小仍然是2x2,共计16个特征图(feature map),C3层的16个10x10的图分别进行以2x2为单位的Pooling操作得到16个5x5的特征图。所以共有5x5x5x16=2000个连接。连接的方式与S2层类似。

(6) C5层 (卷积层)
输入大小:S4层的全部16个单元特征map(与s4全相连)
卷积核大小:5x5
卷积核种类:120
输出120个特征图(feature map),每个特征图的大小:1x1

可训练参数/连接:120x(16x5x5+1)=48120

参数详细说明:
C5层是一个卷积层。由于S4层的16个图的大小为5x5,与卷积核的大小相同,所以卷积后形成的图的大小为1x1。
这里形成120个卷积结果。每个都与上一层的16个图相连。所以共有(5x5x16+1)x120 = 48120个参数,同样有48120个连接。

C5层的网络结构如下图所示:

在这里插入图片描述

(7) F6层 (全连接层)
F6层与C5进行全连接
输入大小:C5层输出的 120维向量(120x1)
计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数输出。
输出:84维向量(84x1)

可训练参数:84x(120+1)=10164

参数详细说明:
F6层是全连接层。F6层有84个节点,对应于一个7x12的比特图,-1表示白色,1表示黑色,这样每个符号的比特图的黑白色就对应于一个编码。
该层的训练参数和连接数是 (120+1)x84=10164 。

ASCII编码图如下:

在这里插入图片描述


F6层的连接方式如下:

在这里插入图片描述

(8) Output层 (全连接层)
Output层也是全连接层,共有10个节点,分别代表数字 0~9,且如果节点i的值为0,则网络识别的结果是数字 i i i 。采用的是径向基函数(RBF)的网络连接方式。假设 x x x 是上一层的输入, y y y 是RBF的输出,则RBF输出的计算方式是:
(3) y i = ∑ j ( x j − w i , j ) 2 {y_i} = \sum\limits_j {{{({x_j} - {w_{i,j}})}^2}} \tag{3} yi=j(xjwi,j)2(3)

其中, w i , j {w_{i,j}} wi,j 的值由 i i i 的比特图编码确定, i i i 从0~9, j j j 取值从 0 到 7x12-1。RBF输出的值越接近于0,则越接近于 i i i,即越接近于 i i i 的ASCII编码图,表示当前网络输入的识别结果是字符 i i i 。该层有 84x10=840 个参数和连接。

下图是LeNet-5识别 图片数字3,每一层特征图可视化的过程。

在这里插入图片描述



3 实验

LeNet-5采用上图架构。共7层,分别为卷积 ——> 最大池化 ——> 卷积 ——> 最大池化 ——> 全连接x3 。保留了LeNet-5中的大部分细节,未加入dropout,最后一层改用softmax。

代码主要参考博客:https://blog.csdn.net/chai_zheng/article/details/79751020

代码如下

# !/usr/bin/env python3
# coding=utf-8

"""
LeNet-5 Using TensorFlow
Date   : 2019.8.22
"""

import tensorflow.examples.tutorials.mnist.input_data as input_data
import tensorflow as tf

mnist = input_data.read_data_sets('./data/mnist/', one_hot=True) #读取路径下的数据集,如果路径下没有,就自动下载。

sess = tf.InteractiveSession()

x = tf.placeholder('float', shape=[None, 28*28])
y_true = tf.placeholder('float', shape=[None, 10])

x_image = tf.reshape(x, [-1, 28, 28, 1])


def weights(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)


def bias(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)


def conv2d(x, W):
    return tf.nn.conv2d(input=x, filter=W, strides=[1, 1, 1, 1], padding='SAME')


def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')


# 1st layer: conv + relu + max_pool
w_conv1 = weights([5, 5, 1, 6])
b_conv1 = bias([6])
h_conv1 = tf.nn.relu(conv2d(x_image, w_conv1)+b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

# 2nd layer: conv + relu + max_pool
w_conv2 = weights([5, 5, 6, 16])
b_conv2 = bias([16])
h_conv2 = tf.nn.relu(conv2d(h_pool1, w_conv2)+b_conv2)
h_pool2 = max_pool_2x2(h_conv2)
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*16])

# 3rd layer: 3*full connection
w_fc1 = weights([7*7*16, 120])
b_fc1 = bias([120])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, w_fc1)+b_fc1)

w_fc2 = weights([120, 84])
b_fc2 = bias([84])
h_fc2 = tf.nn.relu(tf.matmul(h_fc1, w_fc2)+b_fc2)

w_fc3 = weights([84, 10])
b_fc3 = bias([10])
h_fc3 = tf.nn.softmax(tf.matmul(h_fc2, w_fc3)+b_fc3)

cross_entropy = -tf.reduce_sum(y_true*tf.log(h_fc3))
train_step = tf.train.AdamOptimizer(1e-3).minimize(cross_entropy)
correct_prediction = tf.equal(tf.argmax(h_fc3, 1), tf.argmax(y_true, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))

sess.run(tf.global_variables_initializer())

for i in range(1000):
    batch = mnist.train.next_batch(60)
    if i%100 == 0:
        train_accuracy = accuracy.eval(session=sess, feed_dict={x: batch[0], y_true: batch[1]})
        print('step {}, training accuracy: {}'.format(i, train_accuracy))
    train_step.run(session=sess, feed_dict={x: batch[0], y_true: batch[1]})

print('test accuracy: {}'.format(accuracy.eval(session=sess, feed_dict={x: mnist.test.images, y_true:
    mnist.test.labels})))

运行结果如下

在这里插入图片描述



4 小结

在这里插入图片描述

如上图所示,对照着上图,对每层重要的参数进行总结:

(1) INPUT层
输入图像的尺寸统一归一化为 32x32。


(2) C1层 (卷积层)
输入图片:32x32
卷积核大小:5x5
卷积核种类:6
输出6个特征图(feature map),每个特征图的大小:28x28

(3) S2层-(Pooling层)
输入大小:28x28
采样区域:2x2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid函数
采样种类:6
输出6个特征图(feature map),每个特征图的大小:14x14 (28/2)

(4) C3层 (卷积层)
输入大小:S2中所有6个或者几个特征图(feature map)组合
卷积核大小:5x5
卷积核种类:16
输出16个特征图(feature map),每个特征图的大小:10x10

(5) S4层(Pooling层)
输入大小:10x10
采样区域:2x2
采样方式:4个输入相加,乘以一个可训练参数,再加上一个可训练偏置。结果通过sigmoid
采样种类:16
输出16个特征图(feature map),每个特征图的大小:5x5 (10/2)

(7) F6层 (全连接层)
F6层与C5进行全连接
输入大小:C5层输出的 120维向量(120x1)
计算方式:计算输入向量和权重向量之间的点积,再加上一个偏置,结果通过sigmoid函数输出。
输出:84维向量(84x1)

(8) Output层 (全连接层)
输入:84维向量(84x1)
输出:10维向量(10x1),代表所抽取的特征属于哪个类别


LeNet-5网络模型特点

  1. LeNet-5是一种用于手写体字符识别的非常高效的卷积神经网络;
  2. 卷积神经网络能够很好的利用图像的结构信息;
  3. 卷积层的参数较少,这也是由卷积层的主要特性即局部连接和共享权重所决定。




参考资料

[1] 图解深度学习
[2] 深度学习原理与实践
[3] TensorFlow实战Google深度学习框架(第2版)
[4] 网络解析(一):LeNet-5详解 | Jack Cui
[5] LeNet-5及其TensorFlow实现

相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页