代码来源于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~
网友评论