LeNet-5

LeNet-5

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模型接受的输入层大小为32321。第一个卷积层过滤器的尺寸为55,深度为6,不使用全0填充,步长为1。因为没有使用全0填充,所以这一层的输出的尺寸为32-5+1=28,深度为6。这个卷积层总共有5516+6=156个参数,其中6个为偏置参数。因为下一层的节点矩阵有28286=4704个节点,每个节点和55个当前层节点相连,所以卷积层总共有4704(25+1)= 122304个连接。

第二层,池化层

这一层的输入为第一层的输出,是一个28286的节点矩阵。本层采用的过滤器大小为22,长和宽的步长均为2,所以本层的输出矩阵大小为1414*6。

第三层,卷积层

本层的输入矩阵大小为14146,使用的过滤器大小为55,深度为16。本层不使用全0填充,步长为1。本层的输出矩阵大小为101016.按照标准的卷积层本层应该有55616+16=2416个参数,101016*(25+1)=41600个连接。

第四层,池化层

本层的输入矩阵大小为101016,采用的过滤器大小为22,步长为2。本层的输出矩阵大小为55*16。

第五层,全连接层

本层的输入矩阵大小为5516,在LeNet-5模型论文中将这一层称为卷积层,但是因为过滤器的大小就是55,所以和全连接层没有区别。本层的输出节点个数为120,总共有5516120+120=48120个参数。

第六层,全连接层

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

第七层,全连接层

本层的输入节点个数为84个,输出节点个数为10个,总共参数为84*10+10=850个。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : LaoChen_ZeroonE


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

#输出维度
OUTPUT_NODE = 10

#输入维度
IMAGE_SIZE = 28
NUM_CHANNELS = 1
NUM_LABELS = 10
#第一层卷积尺寸和深度
CONV1_DEEP = 32
CONV1_SIZE = 5
#第二层卷积尺寸和深度
CONV2_DEEP = 64
CONV2_SIZE = 5
#全连接节点个数
FC_SIZE = 512

BATCH_SIZE = 100    #一个训练batch中训练数据个数
LEARNING_RATE_BASE = 0.01    #基础学习率
LEARNING_RATE_DECAY = 0.99    #学习衰减率
REGULARIZATION_RATE = 0.0001    #描述模型复杂度的正则化项在损失函数中的系数
TRAINING_STEPS = 6000    #训练轮数
MOVING_AVERAGE_DECAY = 0.99    #滑动平均衰减率

def inference(input_tensor, train, regularizer):
    #和标准LeNet-5不一样,这里使用了全0填充,所以输出为28*28*32的矩阵
    with tf.variable_scope('layer1-conv1'):
        conv1_weights = tf.get_variable(
            "weight", [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP],
            initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_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')
        relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))

    #实现第二层池化层的向前传播过程。这里选用最大池化层,池化层的过滤器边长为2
    #输入为28*28*32,输出为14*14*32
    with tf.name_scope("layer2-pool1"):
        pool1 = tf.nn.max_pool(relu1, ksize = [1,2,2,1],strides=[1,2,2,1],padding="SAME")

    #第三层卷积层的变量实现和向前传播过程。输入为14*14*32的矩阵,输出为14*14*64的矩阵
    with tf.variable_scope("layer3-conv2"):
        conv2_weights = tf.get_variable(
            "weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP],
            initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv2_biases = tf.get_variable("bias", [CONV2_DEEP], initializer=tf.constant_initializer(0.0))
        #使用边长为5,深度为64的过滤器,过滤器移动的步长为1,使用全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))

    #第四层池化层的向前传播过程,输入为14*14*64,输出为7*7*64
    with tf.name_scope("layer4-pool2"):
        pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

    #将第四层池化层的输出转化为第五层全连接层的输入,第四层的输出为7*7*64然而第五层全连接需要的格式为向量,所以将矩阵转化为向格式,
    #pool2.get_shape()函数得到矩阵的维度,计算将矩阵拉直成向量之后的长度,pool_shape[0]为一个batch中数据个数
    pool_shape = pool2.get_shape().as_list()
    nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
    #通过tf.reshape函数将矩阵变成一个batch的向量
    reshaped = tf.reshape(pool2, [pool_shape[0], nodes])

    #第五层全连接变量和向前传播过程,输入是拉直后的向量长度为3136,输出是一组长度为512的向量
    #dropout在训练时会随机将部分节点的输出改为0,可以避免过拟合
    #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 != 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(reshaped, fc1_weights) + fc1_biases)
        if train: fc1 = tf.nn.dropout(fc1, 0.5)

    #第六层全连接的变量和向前传播过程。输入为长度512的向量,输出为一组长度为10的向量
    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 != 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):
    # 定义输出为4维矩阵
    x = tf.placeholder(tf.float32, [
        BATCH_SIZE,    #第一维表示一个batch中样例个数
        IMAGE_SIZE,    #第二、三维表示图片的尺寸
        IMAGE_SIZE,
        NUM_CHANNELS],    #第四维表示图片的深度,对于RGB格式深度为3
                       name='x-input')
    y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE], name='y-input')

    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)    #L2正则化

    #定义卷积神经网络向前传播的过程,参数train,用与区分训练和测试过程,在这个过程中用到dropout方法,dropout可以
    #提升模型可靠性并防止过拟合,dropout只在训练时用
    y = inference(x, False, regularizer)

    # 定义训练轮数及相关的滑动平均类 ,
    # 定义储存训练轮输的变量,这个变量不需要计算滑动平均值,所以这里指定这个变量为不可训练变量trainable=False
    global_step = tf.Variable(0, trainable=False)

    # 给定滑动平均衰减率和训练轮数的变量,初始化滑动平均类
    # 定训练轮数变量可以加快训练早期变量的更新速度 .
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)

    # 在所有代表神经网络参数的变量上使用滑动平均,tf.trainable_variables()返回图上集合GraphKeys.TRAINABLE_VARIABLES中的元素,
    # 就是没有指定 trainable=False 的参数。
    variables_averages_op = variable_averages.apply(tf.trainable_variables())

    # 计算交叉熵及其平均值
    #  sparse_softmax_cross_entropy_with_logits第一个参数是神经网络不包括softmax层的向前传播结果,第二个参数是正确答案。
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
    # 交叉熵平均值
    cross_entropy_mean = tf.reduce_mean(cross_entropy)

    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)

    # 优化损失函数
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)

    # 反向传播更新参数和更新每一个参数的滑动平均值,还有tf.group
    with tf.control_dependencies([train_step, variables_averages_op]):
        train_op = tf.no_op(name='train')


    # 初始化TensorFlow持久化类。
    saver = tf.train.Saver()
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINING_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)

            reshaped_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: reshaped_xs, y_: ys})

            if i % 1000 == 0:
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))


def main(argv=None):
    mnist = input_data.read_data_sets("D:/datasets/MNIST_data", one_hot=True)
    #数据集会自动被分成3个子集,train、validation和test。以下代码会显示数据集的大小。

    print("Training data size: ", mnist.train.num_examples)    #Training data size:  55000
    print("Validating data size: ", mnist.validation.num_examples)    #Validating data size:  5000
    print("Testing data size: ", mnist.test.num_examples)    #Testing data size:  10000

    train(mnist)


if __name__=='__main__':
    main()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值