ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

《人工智能实践:Tensorflow笔记》听课笔记25_7.2lenet5代码讲解

2019-09-01 16:02:00  阅读:283  来源: 互联网

标签:25 lenet5 卷积 笔记 forward tf mnist SIZE


附:课程链接
第七讲.卷积神经网络
7.2lenet5代码讲解

由于个人使用Win7系统,并未完全按照课程所讲,以下记录的也基本是我的结合课程做的Windows系统+PyCharm操作。且本人有python基础,故一些操作可能简略。并未完全按照网课。

记住编写代码时,除注释内容外,字符均使用英文格式。

一、Lenet神经网络结构为:

Lenet5神经网络是LeCun等人在1998年提出的。
Lenet5使用了6个5×5×1的核对输入的32×32×1的图片进行卷积计算,卷积计算后的结果通过激活函数,由于不使用零填充、步长为1,用此公式:
在这里插入图片描述
计算得到输出尺寸为28。
因为用了6个核,所以输出深度是6。之后又用2×2的核对28×28×6的图片进行池化操作、步长为2,又用公式求得输出尺寸为14。
(可见通过池化操作减少了75%的操作,池化操作不改变输入图片的深度。)所以输出是14×14×6。
使用16个5×5×6的核(核的深度要和输入的深度一致,所以核的深度是6),这个5×5×6的核对输入图片14×14×6进行卷积计算,卷积计算的结果通过激活函数。由于用了16个5×5×6的核,输出的深度等于使用卷积核的个数,是10×10×16。再用2×2的核对输入的10×10×16的图片进行池化操作,池化操作对每个深度分别操作。池化不改变图片的深度,输出是5×5×16的图片,最后把5×5×16的图片转换成一维数组,喂入全连接网络,计算分类评估值。
上述全过程如下:
在这里插入图片描述
二、对Lenet神经网络微调,以适应mnist数据集

mnist数据集存放的是28×28×1的灰度图片,我们把Lenet5进行更改,让其匹配28×28×1的输入图片。
微调操作:
在这里插入图片描述
微调后的结构:
在这里插入图片描述
三、代码
Lenet神经网络在mnist数据集上的实现,主要分为三个部分:前向传播过程(mnist_lenet5_forward.py)、反向传播过程(mnist_lenet5_backward.py)、测试过程(mnist_lenet5_test.py)。

1、前向传播过程
在前向传播过程中,搭建了神经网络。

"""
    前向传播
"""
import tensorflow as tf

#在前向传播中,首先定义了神经网络的相关参数
IMAGE_SIZE = 28 #mnist数据集每张图片分辨率,也就是横向和纵向的边长都是28个像素点
NUM_CHANNELS = 1    #是灰度图,所以通道数是1
CONV1_SIZE = 5  #第一层卷积核大小为5
CONV1_KERNEL_NUM = 32   #第一层核个数为32
CONV2_SIZE = 5  #第二层卷积核大小为5
CONV2_KERNEL_NUM = 64   #第二层卷积核个数为64
FC_SIZE = 512   #第一层全连接网络有512个神经元
OUTPUT_NODE = 10    #第二层全连接网络有10个神经元,对应了十分类的输出

"""
    权重w生成函数,与之前一样
"""
def get_weight(shape,regularizer):  #shape表示生成张量的维度,regularizer表示正则化权重
    w = tf.Variable(tf.truncated_normal(shape,stddev=0.1))   #生成去掉过大偏离点的正太分布随机数
    if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
    #如果使用正则化(regularizer != None),则把每一个w的正则化计入到总losses
    return w

"""
    偏置b生成函数,与之前一样
"""
def get_bias(shape):    #shape表示生成张量的维度
    b = tf.Variable(tf.zeros(shape))   #生成初始值为0的偏置b
    return b

"""
    卷积层计算函数
"""
def conv2d(x,w):
    return tf.nn.conv2d(x,w,strides=[1,1,1,1],padding = 'SAME') #给出输入图片x、所用卷积核w
    #x是对输入的描述,是个四阶张量。一阶给出一次喂入多少张图片,也就是batch,二、三阶分别给出图片行、列分辨率,四阶给出输入的通道数。
    #w是对卷积核的描述,也是个四阶张量。一、二阶分别给出图片行、列分辨率。三阶是通道数,四阶是有多少个卷积核。
    #strides为卷积核滑动步长,二、三阶表示滑动步长都是1。
    #使用零填充,所以padding = 'SAME'。

"""
    最大池化层计算函数
"""
def max_pool_2x2(x):
    return tf.nn.max_pool(x,ksize = [1,2,2,1],strides=[1,2,2,1],padding = 'SAME')
    #x是对输入的描述,是个四阶张量。一阶给出一次喂入多少张图片,也就是batch,二、三阶分别给出图片行、列分辨率,四阶给出输入的通道数。
    #池化层大小ksize是2*2的。
    #strides二、三阶表示滑动步长都是1。
    #使用零填充,所以padding = 'SAME'。


"""
    搭建神经网络,描述从输入到输出的数据流
"""
def forward(x,train,regularizer):
    conv1_w = get_weight([CONV1_SIZE,CONV1_SIZE,NUM_CHANNELS,CONV1_KERNEL_NUM],regularizer) #初始化第一层卷积核
    conv1_b = get_bias([CONV1_KERNEL_NUM])  #初始化第一层偏置
    conv1 = conv2d(x,conv1_w)   #执行卷积计算,输入是x,卷积核是初始化的conv1_w
    relu1 = tf.nn.relu(tf.nn.bias_add(conv1,conv1_b))   #对卷积后的输出conv1添加偏置,通过激活函数
    pool1 = max_pool_2x2(relu1) #将激活后的输出进行最大池化

    conv2_w = get_weight([CONV2_SIZE,CONV2_SIZE,CONV1_KERNEL_NUM,CONV2_KERNEL_NUM],regularizer) #第二层卷积核的深度等于上层卷积核的个数
    conv2_b = get_bias([CONV2_KERNEL_NUM])
    conv2 = conv2d(pool1,conv2_w)   #第二层的输入是上一层的输出pool1
    relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_b))   #通过激活函数
    pool2 = max_pool_2x2(relu2) #通过最大池化。pool2是第二层卷积的输出。需要把它从三维张量变为二维张量

    pool_shape = pool2.get_shape().as_list()    #得到pool2输出矩阵的维度存入list()中
    nodes = pool_shape[1] * pool_shape[2] * pool_shape[3]
    #提取特征的长度(pool_shape[1]),提取特征的宽度(pool_shape[2]),提取特征的深度(pool_shape[3])
    #这三个相乘就是所有特征点的个数
    reshaped = tf.reshape(pool2,[pool_shape[0],nodes])  #pool_shape[0]是一个batch的值。
    #将pool2表示成batch行所有特征点作为个数列的二维形状,喂入全连接网络中

    #通过第一层全连接网络
    fc1_w = get_weight([nodes,FC_SIZE],regularizer)
    fc1_b = get_bias([FC_SIZE])
    fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_w) + fc1_b) #把上层的输出reshaped乘以本层线上的权重,加上偏置,过激活函数
    if train: fc1 = tf.nn.dropout(fc1,0.5) #如果是训练阶段,则对该层输出使用50%的dropout

    #通过第二层全连接网络
    fc2_w = get_weight([FC_SIZE,OUTPUT_NODE],regularizer)   #初始化第二层全连接网络的w
    fc2_b = get_bias([OUTPUT_NODE]) #初始化第二层全连接网络的b
    y = tf.matmul(fc1,fc2_w) + fc2_b    #上层的输出和本层线上的权重相乘,加上偏置,得到输出y

    return y

2.反向传播过程
在反向传播过程中,基本与之前的代码相同。只增加了对输入数据的形状调整。

"""
    反向传播
"""
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_lenet5_forward
import os   #os模块
import numpy as np

BATCH_SIZE = 100    #定义每轮喂入神经网络多少张图片
LEARNING_RATE_BASE = 0.005    #最开始的学习率
LEARNING_RATE_DECAY = 0.99  #学习率衰减率
REGULARIZER = 0.0001    #正则化系数
STEPS = 50000   #共训练多少轮
MOVING_AVERAGE_DECAY = 0.99 #滑动平均衰减率
MODEL_SAVE_PATH = "mnist_model" #模型的保存路径
MODEL_NAME = "mnist_model"  #模型保存的文件名
train_num_examples = 60000

#对于反向传播而言,要训练网络参数
def backward(mnist):    #在backward函数中读入mnist
    """
        x,y_是定义的占位符,指定参数为浮点型。由于卷积层输入为四阶张量,
        x的一阶表示每轮喂入的图片数量,  二、三阶分别表示图片的行、列分辨率,
        四阶表示输入的通道数
    """
    x = tf.placeholder(tf.float32, [
        BATCH_SIZE,
        mnist_lenet5_forward.IMAGE_SIZE,
        mnist_lenet5_forward.IMAGE_SIZE,
        mnist_lenet5_forward.NUM_CHANNELS])  #给x占位
    y_ = tf.placeholder(tf.float32, [None, mnist_lenet5_forward.OUTPUT_NODE])    #给y_占位
    y = mnist_lenet5_forward.forward(x,True,REGULARIZER)   #True表示训练参数时使用dropout操作
    global_step = tf.Variable(0,trainable=False)    #给轮数计数器赋初值,设定为不可训练

    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))  # 实现softmax和交叉熵的协同使用
    cem = tf.reduce_mean(ce)
    loss = cem + tf.add_n(tf.get_collection('losses'))  #调用包含正则化的损失函数loss

    #定义指数衰减学习率
    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        train_num_examples / BATCH_SIZE,
        LEARNING_RATE_DECAY,
        staircase=True)

    #定义训练过程
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)

    #定义滑动平均
    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    ema_op = ema.apply(tf.trainable_variables())
    with tf.control_dependencies([train_step, ema_op]):
        train_op = tf.no_op(name='train')

    #实例化saver
    saver = tf.train.Saver() #tf.compat.v1.train.Saver

    #在with结构中初始化所有变量
    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)

        ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)

        #在for循环中迭代STEPS轮
        for i in range(STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)  #每次读入BATCH_SIZE组图片和标签
            #用np.reshape实现了从数据集中取出的xs进行reshape操作
            reshaped_xs = np.reshape(xs,(
            BATCH_SIZE,
            mnist_lenet5_forward.IMAGE_SIZE,
            mnist_lenet5_forward.IMAGE_SIZE,
            mnist_lenet5_forward.NUM_CHANNELS))
            _,loss_value,step = sess.run([train_op,loss,global_step],feed_dict={x:reshaped_xs,y_:ys})
            #用sess.run把喂入神经网络的x做了同样的修改
            if i % 100 == 0:   #每100轮打印loss值
                print("After %d training steps(s),loss on training batch is %g."%(step,loss_value))
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step=global_step)   #保存模型到当前会话

def main():
    mnist = input_data.read_data_sets("mnist_work/", one_hot=True)
    #mnist = input_data.read_data_sets("./data/", one_hot=True)
    backward(mnist)

if __name__ == '__main__':
    main()

3、测试程序
在测试程序中,会输出识别准确率,也仅对x的形状进行了调整。由于测试是使用训练好的网络,所以不适用dropout,所有神经元都要参加运算。

import time #为了延时,导入了time模块
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_lenet5_forward
import mnist_lenet5_backward
import numpy as np

TEST_INTERVAL_SECS = 5  #定义程序循环的间隔时间是5s

def test(mnist):
    with tf.Graph().as_default() as g:  #绘制计算图中的节点
        #给输入图像x和y_占位
        x = tf.placeholder(tf.float32, [
            mnist.test.num_examples,
            mnist_lenet5_forward.IMAGE_SIZE,
            mnist_lenet5_forward.IMAGE_SIZE,
            mnist_lenet5_forward.NUM_CHANNELS])
        y_ = tf.placeholder(tf.float32, [None, mnist_lenet5_forward.OUTPUT_NODE])
        #用前向传播过程计算出y的值
        y = mnist_lenet5_forward.forward(x,False,None)

        #实例化可还原滑动平均的saver,这样所有参数在会话中北加载时会被赋值为各自的滑动平均值
        ema = tf.train.ExponentialMovingAverage(mnist_lenet5_backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)

        #计算正确率
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

        while True:
            with tf.Session() as sess:
                #加载训练好的模型ckpt,也就是把滑动平均值赋给各个参数
                ckpt = tf.train.get_checkpoint_state(mnist_lenet5_backward.MODEL_SAVE_PATH)
                #如果已有ckpt模型则恢复
                if ckpt and ckpt.model_checkpoint_path:
                    #恢复会话
                    saver.restore(sess,ckpt.model_checkpoint_path)

                    #恢复轮数
                    global_step = int(ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1])
                    reshaped_x = np.reshape(mnist.test.images, (
                    mnist.test.num_examples,
                    mnist_lenet5_forward.IMAGE_SIZE,
                    mnist_lenet5_forward.IMAGE_SIZE,
                    mnist_lenet5_forward.NUM_CHANNELS))

                    #计算准确率
                    accuracy_score = sess.run(accuracy,feed_dict = {x:reshaped_x,y_:mnist.test.labels})
                    #打印提示
                    print("After %s training step(s),test accuracy = %g"%(global_step,accuracy_score))

                #如果没有模型
                else:
                    print('No checkpoint file found')   #模型不存在提示
                    return

            time.sleep(TEST_INTERVAL_SECS)

def main():
    mnist = input_data.read_data_sets("mnist_work/", one_hot=True)
    test(mnist)

if __name__ == '__main__':
    main()

我们运行一下代码,看一下使用卷积之后的效果。
运行mnist_lenet5_backward.py:
在这里插入图片描述
运行mnist_lenet5_test.py:
在这里插入图片描述

【BUG:
在运行mnist_lenet5_backward.py时出现了这样的bug:err, “a Variable name or other graph key that is missing”)
解决方案
(我这里报错的原因是原来的文件夹内训练好的模型都还没删除,太多了,删掉以后就能正常运行了)】

至此,第七讲结束。

附:助教的Tensorflow笔记7

标签:25,lenet5,卷积,笔记,forward,tf,mnist,SIZE
来源: https://blog.csdn.net/weixin_42054023/article/details/100181976

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有