LeNet-5模型是Yann LeCun教授与1998年在论文Gradient-based learning applied to document recognition中提出的,它是第一个成功应用于数字识别问题的卷积神经网络。在MNIST数据集上,LeNet-5模型可以达到大约99.2%的正确率。

LeNet-5模型总共有7层,下图展示了LeNet-5模型的架构。

LeNet-5模型结构图

下边详细介绍LeNet-5模型每一层的结构。

第一层,卷积层(C1)

这一层的输入就是原始的图像像素,LeNet-5模型接受的输入层大小为32x32x1。第一个卷积层过滤器的尺寸为5x5,深度为6不使用全0填充步长为1。因为没有使用全0填充,所以这 一 层的输出的尺寸为32-5+1=28深度为6。这 一 个卷积层总共有5x5x1x6+6=156 个参数,其中6个为偏置项参数。因为下一层的节点矩阵有28x28x6=4704个节点,每个节点和5x5=25个当前层节点相连,所以本层卷积层总共有4704x(25+1)= 122304个连接 。


第二层,池化层(S2)

这一层的输入为第一层的输出,是一个28x28x6的节点矩阵。本层采用的过滤器大小为2x2长和宽的步长均为2,所以本层的输出矩阵大小为14x14x6。


第三层,卷积层(C3)

本层的输入矩阵大小为14x14x6,使用的过滤器大小为5x5深度为16。本层不使用全0填充,步长为1。本层的输出矩阵大小为 10x10x16。按照标准的卷积层 ,本层应该有5x5x6x16+16=2416个参数,10x10x16(25+1)=41600个连接 。


第四层,池化层(S4)

本层的输入矩阵大小为10x10x16,采用的过滤器大小为2×2步长为2。本层的输出矩阵大小为5x5x16


第五次,卷积层(C5)

本层的输入矩阵大小为5x5x16,使用的过滤器的大小为5×5,深度为120,。本层不使用全0填充,步长为1.本层的输出矩阵大小为1x1x120。总共有5x5x16x120+120=48120个参数。

本层也可以作如下理解:

(本层的输入矩阵大小为5x5x16,因为过滤器的大小就是5×5,所以和全连接层没有区别,在之后的 TensorFlow 程序实现中也会将这一层看成全连接层。如果将5x5x16矩阵中的节点拉成一个向量,那么这一层和全连接层输入就一样了。)


第六层,全连接层(F6)

本层的输入节点个数为120个,输出节点个数为84个,总共参数为120x84+84=10164个。


第七层,全连接层(Output)

本层的输入节点个数为84个,输出节点个数为10 个,分别代表数字0到9,总共参数为84x10+10=850个。LeNet-5模型论文中最后一层输出层的结构和全连接层有区别,但我们这用全连接层近似的表示 。


下边是用TensorFlow实现的LeNet-5模型:

#!/usr/bin/env python
# -*- coding:utf-8 -*-# ---------------------------------------【导入模块和数据】------------------------------------------------------
import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data# --------------------------------------【配置神经网络结构相关的参数】-------------------------------------------
# MNIST数据集相关的常数
INPUT_NODE = 784  # 输入层节点数,因为图片是28*28*1的格式,每个像素点对应一个节点就是784
OUTPUT_NODE = 10  # 输出层节点数,0-9十个数字# 图片相关参数
IMAGE_SIZE = 28   # 图片大小
NUM_CHANNELS = 1  # 通道数
NUM_LABELS = 10   # 标签数量# 第一层卷积神经网络配置(深度和尺寸)
CONV1_DEEP = 32
CONV1_SIZE = 5
# 第二层卷积神经网络配置(深度和尺寸)
CONV2_DEEP = 64
CONV2_SIZE = 5
# 全连接层的节点个数
FC_SIZE = 512BATCH_SIZE = 100  # Batch的大小
LEARNING_RATE_BASE = 0.8  # 基础学习率
LEARNING_RATE_DECAY = 0.99  # 学习率衰减速率
REGULARIZATION_RATE = 0.0001  # L2正则化参数(描述模型复杂度的正则化项在损失函数中的系数(lambda)
TRAINING_STEPS = 3000  # 训练轮数
MOVING_AVERAGE_DECAY = 0.99  # 滑动平均衰减率,decay# ---------------------------------------------定义前向传播过程--------------------------------------------
def inference(input_tensor, train, regularizer):# 第一层,卷积层# 声明第一层卷积层的变量并实现前向传播过程,# 通过使用不同的命名空间来隔离不同层的变量,这可以让每一层中的变量命名只需要考虑在当前层的作用,不用担心重名的问题# 和标准的LeNet-5模型不大一样,这定义的卷积层输入为28*28*1的原始MNIST图片像素。# 卷积核大小5*5,深度为16,步长为1,,使用全0填充,输出为28*28*32的矩阵with tf.variable_scope('layer1-conv1'):# conv1_weights的大小为5*5*1*32conv1_weights = tf.get_variable("weight", [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],initializer=tf.truncated_normal_initializer(stddev=0.1))# conv1_biases的大小为32conv1_biases = tf.get_variable("bias", [CONV1_DEEP],initializer=tf.constant_initializer(0.0))# 计算卷积层:边长为5,深度为32,步长为1,且用全0填充conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding="SAME")# 注意这里tf.nn.bias_add函数,函数给每一个节点加上偏置项relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))# 第二层,池化层# 实现第二层的前向传播。这里选用最大池化层,池化层的过滤器边长为2,步长为2,且使用全0补充# 这一层的输入是上一层的输出,即28*28*32的矩阵,输出为14*14*32的矩阵with tf.variable_scope('layer2-pool1'):pool1 = tf.nn.max_pool(relu1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")# 第三层,卷积层# 这一层的输入为14*14*32的矩阵# # 卷积核大小5*5,深度为64,步长为1,,使用全0填充,输出为14*14*64的矩阵with tf.variable_scope('layer3-conv2'):# conv2_weights的大小为5*5*32*64conv2_weights = tf.get_variable("weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP],initializer=tf.truncated_normal_initializer(stddev=0.1))# conv2_biases的大小为64conv2_biases = tf.get_variable("bias", [CONV2_DEEP], initializer=tf.constant_initializer(0.0))# 卷积运算conv2 = tf.nn.conv2d(pool1, conv2_weights, strides=[1, 1, 1, 1], padding="SAME")relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_biases))# 第四层,池化层# 这里选用最大池化层,池化层的过滤器边长为2,步长为2,且使用全0补充# 输入为14*14*64,输出为7*7*64with tf.variable_scope('layer4-pool2'):pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")# 将第四层的输出转化为第五层全连接层的输入格式。第四层的输出7*7*64的矩阵,然而第五层全连接层需要的输入格式为向量,# 所以在这里需要将这个7*7*64的矩阵拉直成一个向量。with tf.variable_scope('flatten'):fla = tf.contrib.layers.flatten(pool2)nodes = fla.shape[1]# 第五层,全连接层# 输入是拉直后的一组向量,长度为3136,输出时一组长度为512的向量# 这里引入了dropout,dropout在训练时会随机将部分节点的输出改为0.dropout可以避免过拟合问题,# 从而使得模型在测试数据上的效果更好# dropout一般只在全连接层使用,卷积层或者池化层不使用with tf.variable_scope('layer5-fc1'):fc1_weights = tf.get_variable("weight", [nodes, FC_SIZE],initializer=tf.truncated_normal_initializer(stddev=0.1))# 只有全连接层的权重需要加入正则化if regularizer is not None:tf.add_to_collection('losses', regularizer(fc1_weights))fc1_biases = tf.get_variable('bias', [FC_SIZE], initializer=tf.constant_initializer(0.1))fc1 = tf.nn.relu(tf.matmul(fla, fc1_weights) + fc1_biases)if train:fc1 = tf.nn.dropout(fc1, 0.5)# 第六岑,输出层# 输入为长度为512的向量,输出为一组长度为10的向量,这一层的输出通过Softmax之后就得到了最后的分类结果with tf.variable_scope('layer6-fc2'):fc2_weights = tf.get_variable("weight", [FC_SIZE, NUM_LABELS],initializer=tf.truncated_normal_initializer(stddev=0.1))if regularizer is not None:tf.add_to_collection('losses', regularizer(fc2_weights))fc2_biases = tf.get_variable("bias", [NUM_LABELS], initializer=tf.constant_initializer(0.1))logit = tf.matmul(fc1, fc2_weights) + fc2_biases# 返回第六层输出return logit# -------------------------定义向后传播和训练过程(包括损失函数的计算,最终预测)-------------------------------
def train(mnist):"""训练模型"""# 定义额输入输出placeholderx = tf.placeholder(tf.float32, shape=[None, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS], name="x-input")y_ = tf.placeholder(tf.float32, shape=[None, OUTPUT_NODE], name="y-input")# 定义正则化的方法regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)# 向前传播求出yy = inference(x, False, regularizer)# 定义存储训练轮数的变量。这个变量不需要计算滑动平均值,所以这里指定这个变量为不可训练的变量(trainable=False)# 在使用TensorFlow训练神经网络时,一般会将代表训练轮数的变量指定为不可训练的参数global_step = tf.Variable(0, trainable=False)# 给定滑动平均衰减速率和训练轮数,初始化滑动平均类# 定训练轮数的变量可以加快训练前期的迭代速度variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)# 用tf.trainable_variable()获取所有可以训练的变量列表,全部使用滑动平均variables_averages_op = variable_averages.apply(tf.trainable_variables())# 定义损失函数# 因为标准答案是一个长度为10的一维数组,argmax可以从这个矩阵(y_)的轴为1的部分取最大值的序号# 注意前面已经热点化答案了,所以最大值为1,其他值为0cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))# 获取总损失平均值cross_entropy_mean = tf.reduce_mean(cross_entropy)# 给损失加上正则化的损失# 使用get_collection获取losses集合的全部值的列表,然后用add_n求列表的所有值的和loss = cross_entropy_mean + tf.add_n(tf.get_collection("losses"))# 求加上指数衰减的学习率learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,global_step,mnist.train.num_examples / BATCH_SIZE,LEARNING_RATE_DECAY,staircase=True)# 优化损失函数# global_step初始值为0,在loss更新后会+1,用来记录更新的次数# 返回值是训练之后的梯度,会随着global_step递增train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)# 反向传播更新参数之后需要更新每一个参数的滑动平均值,用下面的代码可以一次完成这两个操作with tf.control_dependencies([train_step, variables_averages_op]):train_op = tf.no_op(name="train")# y是计算得出的预测答案,而y_是正确答案,用argmax获取答案的序号(也即是数字的值)# equal()判断两个答案是否相等,是就返回True,否就返回Falsecorrect_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))# cast()把一个布尔类型的数转换为实数,然后用reduce_mean计算平均值,获取准确率accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))# 开启会话,计算with tf.Session() as sess:# 初始化全局变量tf.global_variables_initializer().run()for i in range(TRAINING_STEPS):# tensorflow的数据集特有的一种batch_size获取方法xs, ys = mnist.train.next_batch(BATCH_SIZE)xs = np.reshape(xs, (BATCH_SIZE, IMAGE_SIZE, IMAGE_SIZE, NUM_CHANNELS))_, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})if i % 1000 == 0:print("After %d training step(s), loss on training batch is %g" % (step, loss_value))test_x, test_y = mnist.test.next_batch(1000)test_x = test_x.reshape(-1, 28, 28, 1)train_acc = accuracy.eval(feed_dict={x: test_x, y_: test_y})print(train_acc)def main(argv=None):# tf.reset_default_graph()mnist = input_data.read_data_sets('../datasets/MNIST_data/', one_hot=True)train(mnist)if __name__ == "__main__":main()

                                                                关注微信公众号【计算机视觉联盟】,获取更多内容!

干货| LeNet-5模型详解(附Python详细代码及注释)相关推荐

  1. 【项目实践】:KNN实现手写数字识别(附Python详细代码及注释)

    ↑ 点击上方[计算机视觉联盟]关注我们 本节使用KNN算法实现手写数字识别.KNN算法基本原理前边文章已经详细叙述,盟友们可以参考哦! 数据集介绍 有两个文件: (1)trainingDigits文件 ...

  2. sklearn预测评估指标:混淆矩阵计算详解-附Python计算代码

    目录 前言 混淆矩阵 python代码 前言 很多时候需要对自己模型进行性能评估,对于一些理论上面的知识我想基本不用说明太多,关于校验模型准确度的指标主要有混淆矩阵.准确率.精确率.召回率.F1 sc ...

  3. python直线拟合_RANSAC算法详解(附Python拟合直线模型代码)

    之前只是简单了解RANSAC模型,知道它是干什么的.然后今天有个课程设计的报告,上去讲了一下RANSAC,感觉这个东西也没那么复杂,所以今天就总结一些RASAC并用Python实现一下直线拟合. RA ...

  4. 蓝牙:CRC原理详解(附crc16校验代码)

    CRC原理详解(附crc16校验代码) 参考链接: https://www.cnblogs.com/esestt/archive/2007/08/09/848856.html Cyclic Redun ...

  5. word2vec模型原理(附python实现代码)

    附python实现代码 模型训练 import logging import gensim from gensim.models import word2vec # 设置输出日志 logging.ba ...

  6. 机器学习最易懂之贝叶斯模型详解与python实现

    文章目录 0.预备知识 0.1 先验概率.条件概率.后验概率 0.2 贝叶斯公式 0.3 极大似然估计 0.4 生成模型与判别模型 1.朴素贝叶斯模型 1.1 朴素贝叶斯的符号说明 1.2 朴素贝叶斯 ...

  7. Linux用户、权限及改变文件所有者及文件所属组多例详解 附python代码

    https://blog.csdn.net/hanhanwanghaha宝藏女孩 欢迎您的关注! 欢迎关注微信公众号:宝藏女孩的成长日记 如有转载,请注明出处(如不注明,盗者必究) Linux用户.权 ...

  8. 【diffusion】扩散模型详解!理论+代码

    0.项目视频详解 视频教程见B站https://www.bilibili.com/video/BV1e8411a7mz 1.diffusion模型理论(推导出损失函数) 1.1.背景 随着人工智能在图 ...

  9. CRC原理详解(附crc16校验代码)

    CRC原理详解 算法原理 查表法 反向算法 附录1:crc16校验表及用法 算法原理 Cyclic Redundancy Check循环冗余检验,是基于数据计算一组效验码,用于核对数据传输过程中是否被 ...

最新文章

  1. IE下的优秀js调试工具Companion.JS
  2. 任何时候不要把普通PC机接入到三层交换机
  3. Python Inotify 监视LINUX文件系统事件
  4. 【Python翻屏软件】英文1秒翻,水准堪比专九,这下考级有救了。
  5. 如何快速压测电商网站?
  6. 深度学习在AEC中的应用探索
  7. 后缀的形容词_构词法(18)构成形容词的常见后缀 3
  8. imx6 i2c分析
  9. 虚电路子网和数据报子网的比较
  10. 中国软件开发project师之痛
  11. Nodejs 使用express模块创建一个服务器
  12. [jqGrid]关于loadonce:true后trigger(reloadGrid)无效,loadonce:false后无法翻页的问题(来自stackoverflow)...
  13. 基于Java实现的快速排序
  14. DotNetBar 5.9 with Office 2007 style controls Released,Are you ready? cracked perfectly!
  15. DFS 下沙小面的(2)
  16. QT之Tcp数据发送测试工具
  17. 电路分析基础知识点总结
  18. 第2.2节 串行SPI接口控制PE4312数控衰减器
  19. GridView合并单元格求和方法
  20. 带你认识40G单纤双向光模块-QSFP+ BiDi光模块

热门文章

  1. influxdb mysql对比_influxdb基础入门
  2. js事件里面套事件怎么不管用_原生js利用localstorage实现简易TODO list应用
  3. android将项目添加到github,将github库作为依赖添加到Android-Studio项目中
  4. 电脑练习打字软件_练习打字软件Master of Typing 3 Mac
  5. 计算机系统结构循环间相关,计算机系统结构(双语)
  6. 画春天的景色计算机教案,大班绘画春天来了教案
  7. 矩阵每一行重复_python:19.顺时针打印矩阵
  8. oracle 11g 使用图解,oracle 11g adrci 工具使用方法
  9. 全志a33android编译,编译lichee - 全志A33的环境搭建
  10. Java io流小技巧_选择用流的小规律(java)基本的io流