tensorflow基础学习—LeNet-5模型

LeNet-5模型是第一个成功应用于数字识别问题中的卷积神经网络,在MNIST 数据集上, LeNet-5 模型可以达到大约99.2% 的正确率。LeNet-5 模型总共有7 层
在这里插入图片描述第一层:卷积层:
这一层的输入就是原始的图像像素, LeNet-5 模型接受的输入层大小为32 * 32 1 。第一个卷积层过滤器的尺寸为5 × 5 ,深度为6 ,不使用全0 填充,步长为1 。因为没有使用全0填充,所以这一层的输出的尺寸为32-5+1=28 , 深度为6 。这一个卷积层总共有5 × 5 × 1 × 6+6=156 个参数,其中6 个为偏置项参数。因为下一层的节点矩阵有2828*6=4704个节点,每个节点和5 × 5=25 个当前层节点相连,所以本层卷积层总共有4704 × (25 + 1) = 122304 个连接。

第二层:池化层:
这一层的输入为第一层的输出, 是一个28×28 × 6 的节点矩阵。本层采用的过滤器大小为2 × 2 ,长和宽的步长均为2 ,所以本层的输出矩阵大小为14 × 14 × 6 。

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

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

第五层:全连接层:
本层的输入矩阵大小为5516 ,在LeNet-5 模型的论文中将这一层称为卷积层,但是因为过滤器的大小就是5 × 5 ,所以和全连接层没有区别,在之后的TensorFlow 程序实现中,也会将这一层看成全连接层。如果将5516 矩阵中的节点拉成一个向量,那么这一层和全连接层输入就一样了。本层的输出节点个数为120 ,总共有5x5x16x120+120=48120 个参数。

第六层:全连接层:
本层的输入节点为120个,输出节点个数为84个,总共参数为120*84+84=10164个

第七层:全连接层:
本层的输入节点个数为84 个,输出节点个数为10 个,总共参数为84 × 10+10=850 个。上面介绍了LeNet-5 模型每一层结构和设置,下面给出一个TensorFlow 的程序来实现一个类似LeNet-5 模型的卷积神经网络来解决MNIST 数字识别问题。通过TensorFlow 训练卷积神经网络的过程和训练全连接神经网络是完全一样的。损失函数的计算、反向传播过程的实现都可以给出的mnist_train.py 程序。唯一的区别在卷积神经网络的输入层为一个三维矩阵,所以需要调整一下输入数据的格式:

#调整输入数据的placeholder的格式,输入为一个四维矩阵
x=tf.placeholder(tf.float32,[BATCH_SIZE,minist_inference.IMAGE_SIZE,
minist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS],name='x-input')
#第四维表示图片的深度,对于RGB格式的图片,深度为3

#类似输入一个训练数据合适调整为四维矩阵,并将这个调整后的数据传入see.run过程
reshaped_xs=np.reshape(VATCH_SIZE,minist_inference.IMAGE_SIZE,
minist_inference.IMAGE_SIZE,mnist_inference.NUM_CHANNELS)

下面给出修改程序

import tensorflow as tf

#配置神经网络参数
INPUT_NODE=784
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

#定义卷积神经网络的前向传播过程。这里添加了一个新的参数train ,用于区分训练过程和测试
#过程。在这个程序中将用到dropout方法,dropout可以进一步提升模型可靠性并防止过拟合,
# dropout 过程只在训练时使用。
def inferrnce(input_tensorflow,train,regularizer):
    #声明第一层卷积层的变量并实现前向传播过程。通过使用不同的命名空间来隔离不同层的变量,
    #这可以让每一层的变量命名只需要考虑当前层的的作用,而不需要考虑重名的问题,和标准
    # LeNet-5 模型不大一样,这里定义的卷积层输入为28*28*1的原始MNIST图片像素,因为卷积
    #层中使用全0填充,所以输出为28*28*32的矩阵。
    with tf.variable_scope('later1-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
    #使用全0填充且移动的不长为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_initeralizer(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,2,2,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'
        )
    #将第四层池化层输出转化为第五层全连接层的输入格式。第同层的输出为7x7x64 的矩阵,
    #然而第五层全连接层需要的输入格式为向量,所以在这里面要将这个7x7x64 的矩阵拉直成一
    #个向盐。pool2.get_shape 函数可以得到第四层输出矩阵的维度而不需要手工计算。注意
    #因为每一层神经网络的输入输出都为一个batch 的矩阵,所以这里得到的维度也包含了一个
    #batch数据的个数
    pool_shape=pool2.get_shape().as_list()
    #计算将矩阵拉直成向量之后的长度,这个长度就是矩阵长宽及深度的乘积。注意在这里
    # pool_shape[O]为一个batch 中数据的个数。
    nodes=pool_shape[1]*pool_shape[2]*pool_shape[3]
    #通过tf.reshape函数将第四层的输出变成一个batch的向量
    reshapeed=tf.reshape(pool2,[poop_shape[0],nodes])
    #声明第五层全连接层的变量并实现前向传播过程。这一层的输入是拉直之后的一组向盘,
    #向盘长度为3136,输出是一组长度为512 的向量。这一层和之前介绍的基本一致,唯一的
    #区别就是引入了dropout 的概念。dropout 在训练时会随机将部分节点的输出改为0
    #dropout 可以避免过拟合问题,从而使得模型在测试数据上的效果更好。
    #dropout一般只在全连接层而不是卷积层或者池化层使用。
    with tf.variable_scope('layer5-fc1'):
        fc1_weight=tf.get_variable(
            'weight',[nodes,FC_SIZE],initializer=tf.constant_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的向量,这一层的输出通过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!=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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值