声明:本文为博主原创文章,转载请附上博文链接!
原文链接:https://editor.csdn.net/md?not_checkout=1&articleId=109632935
下面代码附上了最详细的代码解析,适合零基础学习。
本文主要参考了《tensorflow实战Google深度学习框架》一书,个人非常推荐零基础的可以看看,有需要的电子版书的评论区留言。
不多说,下面是代码,主要是书上的注释和我个人的一些理解。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
Input_node = 784 # 输入层的节点数。对于 MNIST 数据集,这个就等于图片的像素。
Output_node = 10 # 输出层的节成数。这个等于类别的数目。因为在 MNIST数据集中要区分的足 0~ 9这10个数宇,所以这里输出层的节点数为10
Layer_node = 500 # 隐藏层节点数。这里使用只有一个隐藏层的网络结构作为样例。这个隐藏层有 500 个节点。
Batch_size = 100 # 一个训练 batch 中的训练数据个数。
learning_rate_base = 0.8 # 基础的学习率。
learning_rate_decay = 0.99 # 学习率的衰减率。
Regularization_rate = 0.0001 # 描述模型复杂度的正则化项在损失函数中的系数。
Epoch = 30000 # 训练轮数。
Moving_average_decay = 0.99 # 滑动平均衰减率。
# 一个辅助函数,给定神经网络的输入和所有参数,计算神经网络的前向传播结果。在这里定义了一个使用ReLU激活函数的三层全连接神经网络。通过加入隐藏层实现了多层网络结构,
# 通过ReLU激活函数实现了去线性化。在这个函数中也支持传入用于计算参数平均值的类,这样方便在测试时使用滑动平均模型。
def inference(input_tensor,avg_class,weight1,bias1,weight2,bias2):
# 当没有提供滑动平均类时,直接使用参数当前的取值。
if avg_class == None:
# 计算隐藏层的前向传播结果,这里使用了ReLU激活函数。
layer1 = tf.nn.relu(tf.matmul(input_tensor, weight1)+bias1)
# 计算输出层的前向传播结果。因为在计算损失函数时会并计算softmax函数,
# 所以这里不需要加入激活函数。而且不加入softmax 不会影响预测结果。
# 因为预测时使用的是不同类别对应节点输出值的相对大小,有没有softmax层对最后分类结果的计算没有影响。
# 于是在计算整个神经网络的前向传播时可以不加入最后的softmax
output = tf.matmul(layer1, weight2) + bias2
return output
else:
# 首先使用avg_class.average 函数来计算得出变量的滑动平均值,
# 然后再计算相应的神经网络前向传播结果。
layer1 = tf.nn.relu(tf.matmul(input_tensor,avg_class.average(weight1))+avg_class.average(bias1))
output = tf.matmul(layer1, avg_class.average(weight2)) + avg_class.average(bias2)
return output
# 训练模型的过程。
def train(mnist):
# 输入参数设置
x = tf.placeholder(tf.float32, [None, Input_node], name="x-input")
y_ = tf.placeholder(tf.float32, [None, Output_node],name="y-input")
# 生成隐藏层的参数。
weight1 = tf.Variable(tf.truncated_normal([Input_node, Layer_node], stddev=0.1))
bias1 = tf.Variable(tf.constant(0.1,shape=[Layer_node]))
# 生成输出层的参数。
weight2 = tf.Variable(tf.truncated_normal([Layer_node, Output_node], stddev=0.1))
bias2 = tf.Variable(tf.constant(0.1, shape=[Output_node]))
# 计算在当前参数下神经网络前向传播的结果。这里给出的用于计算滑动平均的类为None,所以的函数不会使用参数的滑动平均值。
y = inference(x, None, weight1, bias1, weight2, bias2)
# 定义在储训练轮数的变量。这个变盘不需要计算滑动平均值 所以这里指定这个变量为不可训练的变量 Ctrainable=Fasle)。
# 在使用 TensorFlow 训练神经网络时,一般会将训练轮数的变量指定为不可训练的参数。
global_step = tf.Variable(0, trainable=False)
# 给定消动平均哀减率和训练轮数的变茧,初始滑动平均类。
variable_average = tf.train.ExponentialMovingAverage(Moving_average_decay, global_step)
# 在所有代友神经网络参数的变盘上使用滑动平均。其他辅助变量(比如global_step )就不需要了。这个集合的元索就是所有没有指定trainable=False的参数。
variable_average_op = variable_average.apply(tf.trainable_variables())
# 计算使用了滑动平均之后的前向传播结果。滑动平均不会改变变变量本身的值, 而是会维护个影子变量来记录其滑动平均值。所以当面要使用这个滑动平均值时明确调用 average 函数。
average_y = inference(x, variable_average, weight1, bias1, weight2, bias2)
# 计算交叉熵作为刻画预训值和真实值之间差距的损失函数。这里使用了TensorFlow中提供的sparse_softmax_cross_entropy_with_logits函数来计算交叉焰。
# 当分类问题只有一个正确答案时,可以使用这个函数来加速交叉熵的计算MNIST问题的图片中包含了0~9 10个数字,所以可以使用这个函数来计算交叉熵损失。
# 这个函数的第一个参神经网络不包括 softmax层的前向传播结果。第二个是训练数据的正确答案
# 因为标准答案来是长度为10一维数组,而该函数需要提供的是一个正确答案的数字,所以需要使用tf.argmax函数来得到正确答案对应的类别编号.
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_,1))
# 计算在batch中所有样例的交叉熵平均值。
cross_entropy_mean = tf.reduce_mean(cross_entropy)
# L2正则化损失函数
regularizer = tf.contrib.layers.l2_regularizer(Regularization_rate)
# 计算模型的正则化损失。一般只计算神经网络边上权重的正则化损失,而不使用bias
regularization = regularizer(weight1)+regularizer(weight2)
# 总损失悖于交叉悄损失利正则化损失的利。
loss = regularization + cross_entropy_mean
# 设定指数哀础的学习率
learning_rate = tf.train.exponential_decay(learning_rate_base, # 基础的学习率,随着跌代的进行,学习率在这个基础上递减
global_step, # 当前迭代的轮数
mnist.train.num_examples/Batch_size, # 过完所有训练需要的训练轮数
learning_rate_decay) # 学习率衰减速度
# 使用tf.train.GradientDescentOptimizer优化算法来优化损失函数。注意这里损失函数包含了交叉熵损失和12正则化损失。
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
# 检验使用了滑动平均模型的神经网络前向传播结果是否正确。tf.argmax(average_y 1)计算每个样例的预测答案。
# 其中average_y是一个batch_size*10的二维数组,每一行表示一个样例的前向传播结果。
# tf.argmax的第二个参数"1 ”表示选取最大值的操作仅在第一个维度中进行,也就是说,只在每行选取最大值对应的下标。
# 于是得到的结果是一个长度为batch的一维数组,这个一维数组中的值就表示了每个样例对应的数字识别结果
# tf.equal判断两个张量的每维是否相等,如果相等返回True ,否则返回False
correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_,1))
# 这个运算首先将这个布尔型的数值转换为实数型,然后计算平均值,这个平均值就是模型在这组数据上的正确率。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# 在训练神经网络模型时,每过遍数据既需要通过反向传播来更新神经网络中的参数,又要更新每个参数的滑动平均值。
# 为了次完成多个操作, TensorFlow提供了tf.control_dependencies和tf.group 两种机制 下面两行程序和
# train_op = tf. group(train_step, variables averages_op )是等价的
with tf.control_dependencies([train_step,variable_average_op]):
train_op = tf.no_op(name="train")
# 初始化会话并开始训练过程。
with tf.Session() as sess:
# 对所有变量初始化
tf.global_variables_initializer().run()
# 准备验证数据。 般在神经网络的训练过程中会通过验证数据来大致判断停止的
# 条件和评判训练的效果。
validate_feed = {x: mnist.validation.images,
y_: mnist.validation.labels}
# 准备验证数据。 一般在神经网络的训练过程中会通过验证数据来大致判断停止的条件和评判训练的效果。
test_feed = {x: mnist.validation.images,
y_: mnist.validation.labels}
# 开始训练
for i in range(Epoch):
if i % 1000 == 0:
# 计算滑动平均模型在验证数据上的结果。因为MNIST数据集比较小,所以可以处理所有的验证数据。
# 为了计算方便,本样例程序没有将验证数据划分为更小的batch.
# 当神经网络棋型比较复杂或者验证数据比较大时,太大的 batch会导致计算时间过长甚至发生内存溢出的错误。
validate_acc = sess.run(accuracy, feed_dict=validate_feed)
print("After %d training step(s), validation accuracy " "using average model is %g" % (i, validate_acc))
# 产生这轮使用的batch的训练数据,并运行训练过程。
xs, ys = mnist.train.next_batch(Batch_size)
sess.run(train_op, feed_dict={x: xs, y_: ys})
# 在训练结束之后,在测试数据上检测神经网络模型的最终正确率。
test_acc = sess.run(accuracy, feed_dict=test_feed )
print("After %d training step(s), test accuracy"
"using average model is %g" % (Epoch, test_acc))
# 主程序入口。
def main(argv=None):
# 声明处理MNIST数据集的类,这个类在初始时会自动下载数据。
mnist = input_data.read_data_sets("/mnist", one_hot=True)
train(mnist)
# TensorFlow 提供的一个主程序入口, tf.app.run()会调用上面定义的 main 函数
if __name__ == "__main__":
tf.app.run()
感慨一句,tensorflow确实比pytorch要复杂一点!!!努力成为一个TF. BOY!!!