深度学习之经典卷积神经网络——LeNet

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/BigDream123/article/details/100102468

LeNet由卷积神经网络的祖师爷LeCun提出,用来解决手写数字识别的视觉任务。从那时起,卷积神经网络的架构基本就定下来了:卷积层、池化层、全连接层。如今各大深度学习框架中所使用的LeNet都是简化改进过的LeNet-5(-5表示具有5个层),和原始的LeNet有些许不同,比如把激活函数改为了现在很常用的ReLu。

LeNet的结构:

LeNet-5包含7层(不包括输入层)每一层都包含可训练参数(权重)。当时的输入图片是32*32尺寸的图片

1、C1层(卷积层):6@28x28

C1层使用了6个卷积核,每个卷积核大小为5x5,这样就得到了6个feature map(特征图)

(1)特征图

每个卷积核(5x5)与原始图像(32x32)卷积得到的特征图的尺寸为(32-5+1)x(32-5+1)即28x28

(2)参数个数

由于参数(权值)共享的原因,对于同个卷积核每个神经元均使用相同的参数,因此,参数个数为(5×5+1)×6= 156,其中5×5为卷积核参数,1为偏置参数

(3)连接数

卷积后的大小为28x28,因此每个特征图有28x28个神经元,每个卷积核参数为5×5+1,因此连接数为(5×5+1)×6×28×28=122304

2、S2(池化层):6@14x14

池化层的池化单元大小为2x2

(1)特征图

由于池化的strides为2,每个池化单元之间没有重叠,故6个特征图经过池化以后尺寸变为(28-2)/2 + 1 = 14,即为14x14(也可以这样理解,每个池化单元为2x2,每个池化单元之间没有重叠,相当于每两行两列重新算出一个特征值来,即相当于图像减半)

(2)参数个数

S2层每个特征图都共享相同的w和b两个参数,即共有6x2=12个参数

(3)连接数

下采样之后的图像大小为14×14,因此S2层的每个特征图有14×14个神经元,每个池化单元连接数为2×2+1(1为偏置量),因此,该层的连接数为(2×2+1)×14×14×6 = 5880

3、C3(卷积层):16@10x10

C3层有16个卷积核,、每个卷积核的大小为5x5

(1)特征图

每个卷积核大小为5x5,输入大小为14x14,故特征图大小为(14-5+1)x(14-5+1)即10x10

(2)参数个数

注意:C3与S2并不是全连接而是部分连接,有些是C3连接到S2三层、有些四层、甚至达到6层,通过这种方式提取更多特征,连接的规则如下表所示:

例如第一列表示C3层的第0个特征图(feature map)只跟S2层的第0、1和2这三个feature map相连接,计算过程为:用3个卷积模板分别与S2层的3个feature maps进行卷积,然后将卷积的结果相加求和,再加上一个偏置,再取sigmoid得出卷积后对应的feature map了。其它列也是类似(有些是3个卷积模板,有些是4个,有些是6个)。因此,C3层的参数数目为(5×5×3+1)×6 +(5×5×4+1)×9 +5×5×6+1 = 1516

(3)连接数

卷积后的特征图大小为10x10,参数个数为1516,故连接数为1516x10x10 = 151600

4、S4(池化层):16@5x5

(1)特征图大小

与S2分析类似,由于池化单元为2x2,strides=2,故通过池化后图像尺寸减半,即5x5

(2)参数个数

每个特征图都共享w和b两个参数,即参数个数为16x2 = 32

(3)连接数

 连接数为(2×2+1)×5×5×16 = 2000

5、C5(卷积层):120

(1)特征图大小

每个卷积核为5x5,卷积核数目为120,因此有120个特征图,每个特征图的大小为(5-5+1)x(5-5+1)即1x1。这样该层恰好变成了全连接,这只是巧合,如果输入比32x32大,则该层就不是全连接层了。

(2)参数个数

和之前计算类似,参数个数为120x(5x5x16+1)=48120

(3)连接数

连接数为48120×1×1=48120

6、F6(全连接层):84

(1)特征图大小

F6层有84个单元,之所以选这个数字的原因是来自于输出层的设计,对应于一个7×12的比特图,如下图所示,-1表示白色,1表示黑色,这样每个符号的比特图的黑白色就对应于一个编码。

该层有84个特征图,特征图大小与C5一样都是1×1,与C5层全连接。

(2)参数个数

由于是全连接,参数数量为(120+1)×84=10164。跟经典神经网络一样,F6层计算输入向量和权重向量之间的点积,再加上一个偏置,然后将其传递给sigmoid函数得出结果。

(3)连接数

由于是全连接,连接数与参数数量一样,也是10164。

7、OUTPUT(输出层):10

Output层也是全连接层,共有10个节点,分别代表数字0到9。

(1)特征图大小

该层采用径向基函数(RBF)的网络连接方式,假设x是上一层的输入,y是RBF的输出,则RBF输出的计算方式是:

上式中的Wij的值由i的比特图编码确定,i从0到9,j取值从0到7×12-1。RBF输出的值越接近于0,表示当前网络输入的识别结果与字符i越接近。

(2)参数个数

由于是全连接,参数个数为84×10=840

(3)连接数

由于是全连接,连接数与参数个数一样,也是840

这里使用TensorFlow构建LeNet网络实现手写数字识别,利用mnist数据集实现

# LeNet-5 简单实现手写数字识别

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

mnist = input_data.read_data_sets('MNIST_data/', one_hot=True)
# 权重参数初始化
def weight_variable(shape):
    initial = tf.truncated_normal(shape,stddev=0.1)
    return tf.Variable(initial)

# 偏置参数初始化
def bias_variable(shape):
    initial = tf.constant(0.1,shape=shape)
    return tf.Variable(initial)


# 定义卷积层
"""
conv2d(x,W,strides=[1,1,1,1],padding='SAME')参数含义与上述类似
        x:input
        W:filter,滤波器大小
        strides:步长,1*1,表示filter窗口每次水平移动1格,每次垂直移动1格
        padding:填充方式,补零('SAME')
"""
def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')

# 定义池化层
'''
max_pool(x,ksize,strides,padding)参数含义
        x:input
        ksize:filter,滤波器大小2*2
        strides:步长,2*2,表示filter窗口每次水平移动2格,每次垂直移动2格
        padding:填充方式,补零
'''
def max_pool_2x2(x):
    return tf.nn.max_pool2d(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

def compute_accuracy(test_xs, test_ys):
    # 使用全局变量prediction
    global prediction
    # 获得预测值y_pre
    y_pre = sess.run(prediction, feed_dict = { x: test_xs, keep_prob: 1})
    # 判断预测值y和真实值y_中最大数的索引是否一致,y_pre的值为1-10概率, 返回值为bool序列
    correct_prediction = tf.equal(tf.argmax(y_pre, 1), tf.argmax(test_ys, 1))
    # 定义准确率的计算
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) #tf.cast将bool转换为float32
    # 计算准确率
    result = sess.run(accuracy)
    return result


# 定义输入输出数据
x = tf.placeholder(tf.float32,[None,784])# 图片为28*28=784

y = tf.placeholder(tf.float32,[None,10])# 输出标签为0-9

keep_prob = tf.placeholder(tf.float32) # dropout的比例

x_image = tf.reshape(x,[-1,28,28,1]) # 对输入数据重新排列,形成28*28*1

# 卷积层1
W_conv1 = weight_variable([5,5,1,32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

# 卷积层2
W_conv2 = weight_variable([5,5,32,64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

# 全连接层1
W_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_pool2_flatten = tf.reshape(h_pool2,[-1,7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flatten,W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1,keep_prob)

# 全连接层2
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2) + b_fc2)

# 计算loss
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y * tf.log(prediction), reduction_indices=[1]))
# 神经网络训练
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy) #0.0001

# 定义Session
sess = tf.Session()
init = tf.global_variables_initializer()
# 执行初始化
sess.run(init)

# 进行训练迭代
for i in range(1000):
    # 取出mnist数据集中的100个数据
    batch_xs, batch_ys = mnist.train.next_batch(50) #100
    # 执行训练过程并传入真实数据
    sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys, keep_prob: 0.5})
    if i % 100 == 0:       
    # 判断预测值y和真实值y_中最大数的索引是否一致,y_pre的值为1-10概率, 返回值为bool序列
        correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(batch_ys, 1))
    # 定义准确率的计算
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) #tf.cast将bool转换为float32
        result = sess.run(accuracy,feed_dict={x:batch_xs,y:batch_ys,keep_prob:1})
        print(result)

猜你喜欢

转载自blog.csdn.net/BigDream123/article/details/100102468