LeNet详解

鉴于网上很多的LeNet讲解,但是有没有指明这时LeNet的简化版,本文特对Yann Lecun的原文进行一点讲解,原文地址:Gradient-Based Learning Applied to Document Recognition

1. LeNet的网络结构

这里写图片描述
以下用Cx代表convolutional layer,用Sx代表sub-sampling layer,用Fx代表fully-connected layer。

  • C1:
    C1是convolutional layer,有6个filter map,卷积核大小为 5×5 ,stride大小为 1×1 ,输入大小是 32×32 ,输出的feature map大小是 28×28×6 。C1有156个训练参数,122,304个连接。(注意:如果输入大小为 28×28 ,则需要加上2的padding将输入增加到 32×32 )
  • S2:
    S2是一个sub-sampling,pooling_size的大小为(2,2), stride的大小为(2,2), 与现在的max pooling不同。LeNet是把 2×2 的一个unit的所有数值相加,然后乘以一个系数 coefficient ,最后加上一个偏置 bias ,得出的结果再送入一个 sigmoid 函数作为最终这一层的输出。这里的 coefficient bias 都是可以训练的,因此有12个训练参数。因此现在的max_pooling是没有参数的,但是LeNet的sub-sampling是有训练参数的。
  • C3:
    C3是convolutional layer,有16个filter map, 卷积核大小为 5×5 ,stride大小为 1×1 ,没有padding,输入大小是 14×14×6 ,输出大小是 10×10×16 。C3有1516个训练参数,有156000个连接。
  • S4:
    和S2相同,S2拥有32个训练参数和2000个连接。
  • C5:
    C5是一个convolutional layer,卷积核的大小为 5×5 ,stride大小为 1×1 ,没有padding,拥有120个filter。由于S4的输出为 5×5×16 ,因此C5的输出大小为 1×1×120 。C5设置为convolutional layer的原因是如果LeNet-5的输入变大,而其他的保持不变,那么此时特征图的维数就会比1*1大,就不能说是一个全连接层了。而且C5的由来也符合卷积的方法,只不过最后刚好是 1×1 而已。
  • F6:
    F6是一个全连接层,有84个神经元元(之所以选这个数字的原因来自于输出层的设计,下面会有说明),与C5层构成相连。有10164个可训练参数。
  • output:
    output是一个Gaussian连接,与全连接不同的是,全连接是将F6的输出与权重进行点积,再加上一个偏置。然后将结果传入sigmoid函数单元产生一个状态。而gaussian连接的计算方式为:

    yi=j=1n(xjwji)2i{0,1,,9}

    对于本例而言, i{0,1,,83} 。即计算ERBF距离,最后的输出层是由欧式径向基单元(Euclidean Radial Badi)组成,每类一个单元,每个有84个输入。每个输出ERBF单元计算输入向量和参数向量之间的欧式距离。输入离参数向量越远,ERBF输出越大。因此,一个ERBF输出可以被理解为衡量输入模式和与ERBF相关联类的一个模型的匹配程度的惩罚项。同时ERBF参数向量起着F6层目标向量的角色。这些向量的成分是+1或者-1,也可以防止F6层的Sigmoid函数饱和。

  • 损失函数:
    使用MLE(最大似然估计)和MSE(最小均方差)。

2. LeNet的TensorFlow实现

最接近原始的LeNet-5:

2.1 代码

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

mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
batch_size = 128
epochs = 100
with tf.variable_scope("input"):
    x = tf.placeholder(shape=(None, 784), dtype=tf.float32, name="input_x")
    y = tf.placeholder("float", name="input_y")

def lenet(input):
    with tf.variable_scope("reshape"):
        input = tf.reshape(input, [-1, 28, 28, 1], name="reshape_input_x")

    with tf.variable_scope("conv_1"):
        weights1 = tf.Variable(tf.truncated_normal(shape=[5, 5, 1, 6], mean=0, stddev=0.1), name="weights1")
        bias1 = tf.Variable(tf.truncated_normal(shape=[6], mean=0, stddev=0.1), name="bias1")
        c1 = tf.nn.conv2d(input=input, filter=weights1, strides=[1,1,1,1], padding="SAME")+bias1
        s2 = tf.nn.max_pool(c1, ksize=(1,2,2,1),strides=[1,2,2,1], padding="VALID")

    with tf.variable_scope("conv_2"):
        weights2 = tf.Variable(tf.truncated_normal(shape=[5, 5, 6, 16], mean=0, stddev=0.1), name="weights2")
        bias2 = tf.Variable(tf.truncated_normal(shape=[16]))
        c3 = tf.nn.conv2d(input=s2, filter=weights2, strides=[1,1,1,1], padding="VALID")+bias2
        s4 = tf.nn.max_pool(c3, ksize=(1,2,2,1),strides=[1,2,2,1], padding="VALID")

    with tf.variable_scope("conv_3"):
        weights3 = tf.Variable(tf.truncated_normal(shape=[5,5,16,120], mean=0, stddev=0.1))
        bias3 = tf.Variable(tf.truncated_normal(shape=[120], mean=0, stddev=0.1))
        c5 = tf.nn.conv2d(input=s4, filter=weights3, strides=[1,1,1,1], padding="VALID")+bias3

    c5_shape_li = c5.get_shape().as_list()
    with tf.variable_scope("fc_1"):
        weights4 = tf.Variable(tf.truncated_normal(shape=[120, 84], mean=0, stddev=0.1))
        bias4 = tf.Variable(tf.truncated_normal(shape=[84], mean=0, stddev=0.1))
        with tf.variable_scope("flatten"):
            o5_flatten = tf.reshape(tensor=c5, shape=[-1, c5_shape_li[1] * c5_shape_li[2] * c5_shape_li[3]], name="flatten")
        f6 = tf.matmul(o5_flatten, weights4) + bias4

    with tf.variable_scope("output"):
        weights5 = tf.Variable(tf.truncated_normal(shape=[84, 10], mean=0, stddev=0.1))
        bias5 = tf.Variable(tf.truncated_normal(shape=[10], mean=0, stddev=0.1))
        output = tf.matmul(f6, weights5) + bias5

    return output

predict = lenet(x)
with tf.variable_scope("loss"):
    loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=predict, labels=y))

with tf.variable_scope("train"):
    optimizer = tf.train.AdamOptimizer(learning_rate=0.0001).minimize(loss)
    correct_train = tf.equal(tf.arg_max(predict, 1), tf.arg_max(y, 1))
    accuracy_train = tf.reduce_mean(tf.cast(correct_train, "float"))

with tf.Session() as sess:
    saver = tf.summary.FileWriter("../log/", sess.graph)
    sess.run(tf.global_variables_initializer())
    for epoch in tqdm(range(10)):
        epoch_loss = 0
        for _ in range(int(mnist.train.num_examples / batch_size)):
            epoch_x, epoch_y = mnist.train.next_batch(batch_size)
            _, c = sess.run([optimizer, loss], feed_dict={x: epoch_x, y: epoch_y})
            epoch_loss += c
        print("accuracy", sess.run(accuracy_train, feed_dict={x: mnist.test.images, y:mnist.test.labels}),
              'loss:', epoch_loss)

    correct = tf.equal(tf.argmax(predict, -1), tf.argmax(y, -1))

    accuracy = tf.reduce_mean(tf.cast(correct, 'float'))
    print('Accuracy:', accuracy.eval({x: mnist.test.images, y: mnist.test.labels}))

2.2 结构图:

这里写图片描述

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeNet-5是一个经典的卷积神经网络模型,由Y. LeCun在1998年提出,它是第一个成功应用于手写数字识别的深度学习模型。LeNet-5主要由两个部分组成,一部分是卷积神经网络(Convolutional Neural Network,CNN),另一部分是全连接神经网络(Fully Connected Neural Network, FCNN)。下面详细介绍一下LeNet-5的网络结构。 整个网络的结构可以分为7层,包括3个卷积层、2个池化层、1个全连接层和1个输出层。下面分层来介绍整个网络的结构: 1. 输入层(Input Layer):LeNet-5的输入层是32*32的彩色图像,即输入图片的大小为32*32*3。 2. 第一个卷积层(Convolutional Layer):第一个卷积层有6个卷积核,每个卷积核大小为5*5*3,步长为1。因此,输出的特征图大小为28*28*6。每个卷积核的权重参数是共享的,也就是说,每个卷积核在所有的输入图片上的权重是相同的,这样可以减少模型的参数数量。 3. 第一个池化层(Pooling Layer):第一个池化层使用2*2的最大池化,步长为2。因此,输出的特征图大小为14*14*6。最大池化操作能够保留特征图中最强的特征,同时减小特征图的大小。 4. 第二个卷积层(Convolutional Layer):第二个卷积层有16个卷积核,每个卷积核大小为5*5*6,步长为1。因此,输出的特征图大小为10*10*16。 5. 第二个池化层(Pooling Layer):第二个池化层使用2*2的最大池化,步长为2。因此,输出的特征图大小为5*5*16。 6. 第三个卷积层(Convolutional Layer):第三个卷积层有120个卷积核,每个卷积核大小为5*5*16,步长为1。因此,输出的特征图大小为1*1*120。 7. 全连接层(Fully Connected Layer):全连接层有84个神经元,将前面的特征图拉成一个向量,作为全连接层的输入。 8. 输出层(Output Layer):输出层是一个10个神经元的softmax分类器,用于预测输入图片的数字标签。 总的来说,LeNet-5是一个非常简单的卷积神经网络模型,但它在手写数字识别任务上表现出了非常优秀的性能。同时,它也为后来更复杂的卷积神经网络模型的发展奠定了基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值