美文网首页
基于MNIST数据集的tensorflow最佳实践样例解读

基于MNIST数据集的tensorflow最佳实践样例解读

作者: snowpigppp | 来源:发表于2019-03-22 16:15 被阅读0次

代码来源于TensorFlow实战Google深度学习框架(第2版)中,5.5的基于MNIST数据集的tensorflow最佳实践样例,根据这几天的学习及在网上的查找,给出书中的代码附加我个人的理解,希望能给大家一些参考,同时也让自己加深记忆。

下面是mnist_train.py,主要用来初始化参数及训练神经网络

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_inference
import os

# 配置神经网络参数
BATCH_SIZE = 100 # 每次训练batch中训练数据个数
LEARNING_RATE_BASE = 0.8 # 开始的学习率
LEARNING_RATE_DECAY = 0.99 # 学习率下降速度
REGULARIZATION_RATE = 0.0001 # 正则化项的系数
TRAINING_STEPS = 30000 # 训练轮数
MOVING_AVERAGE_DECAY = 0.99 # 滑动平均模型中的衰减率,决定模型更新速度,越大模型越稳定
MODEL_SAVE_PATH="MNIST_model/" # 模型保存位置
MODEL_NAME="mnist_model" #模型名称


def train(mnist):
    # placeholder提供输入数据,防止每次训练生成张量导致计算图过大
    # tf.placeholder(数据类型,数据维度,变量名称)
    x = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
    y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')

    # 定义正则化项计算方式(正则化是为了防止参数过多,导致过拟合)
    # L1正则化/L2正则化tf.contrib.layers.l2_regularizer(系数)
    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
    # 调用mnist_inference(前向传播过程)
    y = mnist_inference.inference(x, regularizer)
    # 存储训练轮数,不需要滑动平均,故trainable=False,用它控制滑动平均衰减率
    global_step = tf.Variable(0, trainable=False)

    # tf.train.ExponentialMovingAverage(decay,step)
    # 定义一个滑动平均的类
    # 此时衰减率为min{decay,(1+step)/(10+step)}
    # (1+step)/(10+step)单调递增,故一开始的衰减率为(1+step)/(10+step)
    # 此时由于衰减率较小,故模型更新速度较快
    # 随着训练轮数增多,(1+step)/(10+step)越来越大,模型更新速度越来越慢,直至增大到decay
    # 从而使模型在测试数据上更加robust(健壮)
    variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, 
                                                          global_step)
    
    # tf.trainable_variables返回的是需要训练的变量列表
    # 对所有需要训练的变量应用滑动平均模型
    variables_averages_op = variable_averages.apply(tf.trainable_variables())
    
    # tf.nn.sparse_softmax_cross_entropy_with_logits(logits,labels)
    # 实现使用了softmax回归之后的交叉熵损失函数
    # 当分类问题正确答案只有一个时使用该函数计算交叉熵,加速交叉熵计算
    # logits为神经网络的输出(未经softmax回归)
    # labels为正确答案,即正确答案对应的类别编号
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, 
    # tf.argmax(y_, 1)给出y_中最大值的索引,即正确答案对应的类别编号
                                                                   labels=tf.argmax(y_, 1))
    
    # 计算cross_entropy所有元素的平均值(cross_entropy包含当前训练batch中的每个样本对应的交叉熵)
    cross_entropy_mean = tf.reduce_mean(cross_entropy)
    
    # tf.get_collection('losses') 计算losses中所有元素的和,即全部weights正则化和
    loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    
    # tf.train.exponential_decay设置参数更新过程中学习率的变化,指数衰减
    # 设置指数衰减是使梯度下降过程中首先快速下降,而后越来越慢
    # 每训练mnist.train.num_examples / BATCH_SIZE次后,学习率乘以LEARNING_RATE_DECAY
    # 为什么每mnist.train.num_examples / BATCH_SIZE次下降一次呢?
    # 是因为这样在此次学习率上就训练了全部的样本,全部样本对梯度下降结果贡献一致
    # staircase=True表示使用阶梯状衰减学习率
    learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,
                                               global_step,
                                               mnist.train.num_examples / BATCH_SIZE, 
                                               LEARNING_RATE_DECAY,
                                               staircase=True)
    
    # tf.train.GradientDescentOptimizer(学习率) 随机梯度下降算法
    # tf.train.AdamOptimizer() 利用自适应学习率的优化算法
    # 损失函数优化器的minimize()中global_step=global_steps能够提供global_step自动加一的操作
    train_step = tf.train.GradientDescentOptimizer(learning_rate).\
                                                   minimize(loss,global_step=global_step)
    
    # 每过一次数据,反向传播更新神经网络参数,同时计算参数的滑动平均值
    # 下方代码完成这两项工作
    # tf.control_dependencies()表示在完成括号内的操作后才能继续执行with内代码
    # 这行的意思是,执行train_step,variables_averages_op,然后什么都不做
    # 等价于train_op = tf.group(train_step,variables_averages_op)
    with tf.control_dependencies([train_step, variables_averages_op]):
        train_op = tf.no_op(name='train')

    # 保存
    saver = tf.train.Saver()
    
    # 用上下文管理器创建会话,不需要专门关闭会话
    with tf.Session() as sess:
        # 初始化所有变量
        tf.global_variables_initializer().run()
        
        # 开始循环训练
        for i in range(TRAINING_STEPS):
            
            # 取出batch个样本,xs为输入,ys为输出
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            
            #运行train_op,loss,global_step,运行这些的输入x为xs,y为ys
            #train_op的运行相当于train_step, variables_averages_op两项
            _, 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))
                saver.save(sess, 
                           os.path.join(MODEL_SAVE_PATH, MODEL_NAME), 
                           global_step=global_step)


def main(argv=None):
    # 读取数据集
    mnist = input_data.read_data_sets("D:\\testpython\\201806-github\\201806-github\\datasets\\MNIST_data", one_hot=True)
    train(mnist)

if __name__ == '__main__':
    main()

下面是mnist_inference.py,主要进行神经网络的前向传播过程,同时计算loss中的正则项

import tensorflow as tf

# 节点数量等
INPUT_NODE = 784 # 输入维度(28*28展开)
OUTPUT_NODE = 10 # 输出维度(判断0-9,故输出十维)
LAYER1_NODE = 500 # 神经网络隐层有一层,这一层的节点设定500个

# 其实就是初始化了weights,顺便计算了weights正则化项,并记录到了'losses'里
def get_weight_variable(shape, regularizer):
    # tf.get_variable(变量名称,变量维度,初始化方法)
    weights = tf.get_variable("weights", shape, \
                              # tf.truncated_normal_initializer()正态分布
                              initializer=tf.truncated_normal_initializer(stddev=0.1))
    if regularizer != None: 
        # tf.add_to_collection(‘list_name’, element)
        # 将元素element添加到列表list_name中
        # regularizer(weights)计算含权重系数的weights的L2正则化结果
        tf.add_to_collection('losses', regularizer(weights))
    return weights

def inference(input_tensor, regularizer):
    # with tf.variable_scope(命名空间名称,reuse=True/False)
    # 创建命名空间,管理变量命名空间
    # reuse=True,可以用tf.get_variables获取已经创建的变量,反之不可以
    with tf.variable_scope('layer1'):
        # 调用上文get_weight_variable函数,得到初始化的weights
        weights = get_weight_variable([INPUT_NODE, LAYER1_NODE], regularizer)
        # 偏置项初始化为0
        biases = tf.get_variable("biases", [LAYER1_NODE], \
                                initializer=tf.constant_initializer(0.0))
        # 计算layer1各节点的结果
        layer1 = tf.nn.relu(tf.matmul(input_tensor, weights) + biases)

    with tf.variable_scope('layer2'):
        weights = get_weight_variable([LAYER1_NODE, OUTPUT_NODE], regularizer)
        biases = tf.get_variable("biases", [OUTPUT_NODE], \
                                 initializer=tf.constant_initializer(0.0))
        layer2 = tf.matmul(layer1, weights) + biases

    return layer2

这样采用写注释的方式记忆会更加深刻一些,对不明白的函数也不会选择一带而过😊

一起加油bia~

相关文章

网友评论

      本文标题:基于MNIST数据集的tensorflow最佳实践样例解读

      本文链接:https://www.haomeiwen.com/subject/fjdrvqtx.html