代码: tensorflow/examples/tutorials/mnist/python
本文的目的是来展现如何使用Tensorflow训练和评估手写数字识别问题。本文的观众是那些对使用Tensorflow进行机器学习感兴趣的人。git
本文的目的并非讲解机器学习。github
请确认您已经安装了Tensorflow。算法
教程文件数组
文件 | 做用 |
mnist.py |
用来建立一个彻底链接的MNIST模型。 |
fully_connected_feed.py |
使用下载的数据集训练模型。 |
运行fully_connected_feed.py文件开始训练。网络
python fully_connected_feed.py
准备数据机器学习
MNIST是机器学习的一个经典问题。这个问题是识别28*28像素图片上的数字,从0到9。函数
更多信息,请参考Yann LeCun's MNIST page 或者 Chris Olah's visualizations of MNIST。post
数据下载单元测试
在run_training()方法以前,input_data.read_data_sets()方法可让数据下载到本机训练文件夹,解压数据并返回一个DataSet实例。
data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)
注意:fake_data是用来进行单元测试的,读者能够忽略。
数据集 | 做用 |
data_sets.train | 55000图片和标签,用来训练。 |
data_sets.validation | 5000图片和标签,用来在迭代中校验模型准确度。 |
data_sets.test | 10000图片和标签,用来测试训练模型准确度。 |
输入和占位符
placeholder_inputs()函数建立两个tf.placeholder,用来定义输入的形状,包括fetch_size。
images_placeholder = tf.placeholder(tf.float32, shape=(batch_size, mnist.IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))
在训练循环中,图片和标签数据集会被切分红batch_size大小,跟占位符匹配,而后经过feed_dict参数传递到sess.run()方法中。
建立图
建立占位符后,mnist.py文件中会经过三个步骤来建立图:inference(), loss()
, 和training()。
loss()
- 用来计算损失值。training()
- 计算梯度。inference层
inference()函数建立图,返回预测结果。
它把图片占位符看成输入,并在上面构建一对彻底链接的层,使用ReLU激活后,链接一个10个节点的线性层。
每一层都位于tf.name_scope
声明的命名空间中。
with tf.name_scope('hidden1'):
在该命名空间中,权重和偏置会产生tf.Variable实例,并具备所需的形状。
weights = tf.Variable(tf.truncated_normal([IMAGE_PIXELS, hidden1_units], stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))), name='weights') biases = tf.Variable(tf.zeros([hidden1_units]), name='biases')
例如,这些会在hidden1命名空间中建立,那么权重的惟一名称为“hidden1/weights”。
每一个变量使用初始化器做为构造函数。
一般,权重会使用tf.truncated_normal(截尾正态分布)
做为初始化器,它是一个2D张量,第一个参数表示该层中的神经元数,第二个表示它链接的层中的神经元数。再第一层hidden1中,权限矩阵的大小是[图片像素, hidden1神经元数],由于该权重链接图片输入。tf.truncated_normal初始化器会根据平均值和标准差产生一些随机数。
而后,偏置会使用tf.zeros
做为初始化器,保证开始时全部数都是0。它们的形状跟它们链接的层的神经元同样。
该图的三个主要运算:两个tf.nn.relu操做
(包括隐层中的一个tf.matmul操做
)和一个额外的tf.matmul操做。而后依次建立,链接到输入占位符或上一层的输出张量上。
hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
logits = tf.matmul(hidden2, weights) + biases
最后,logits张量包含输出结果。
损失
loss()函数经过添加所需的损失操做来进一步构建图形。
首先,将labels_placeholder的值转换为64位整数。 而后,添加tf.nn.sparse_softmax_cross_entropy_with_logits操做,以自动从labels_placeholder产生标签,并将inference()函数的输出与这些标签进行比较。
labels = tf.to_int64(labels) cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits, name='xentropy')
而后使用tf.reduce_mean将batch维度(第一维)的交叉熵的平均数做为总损耗。
loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')
而后返回包含损失值的张量。
tf.summary.scalar('loss', loss)
接下来,咱们实例化一个tf.train.GradientDescentOptimizer,进行梯度降低算法。
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
而后,咱们定义一个变量,用来做为全局训练步骤的计数器,而且tf.train.Optimizer.minimize op用于更新系统中的可训练权重,并增长全局步长。 一般,这个操做被称为train_op. 它是由TensorFlow会话运行的,以便引导一个完整的训练步骤。
global_step = tf.Variable(0, name='global_step', trainable=False) train_op = optimizer.minimize(loss, global_step=global_step)
训练模型
构建图形后,能够在full_connected_feed.py中由用户代码控制的循环中进行迭代训练和评估。
图
在run_training()函数的顶部,其中的命令指示全部构建的操做都与默认的全局tf.Graph实例相关联。
with tf.Graph().as_default():
tf.Graph是能够做为一组一块儿执行的操做的集合。 大多数TensorFlow用户只须要依赖于单个默认图形。
更复杂的使用多个图形是可能的,但超出了这个简单教程的范围。
会话
一旦全部的构建准备工做已经完成而且生成了全部必要的操做,就会建立一个tf.Session来运行图形。
sess = tf.Session()
或者,能够将会话生成到某个做用域中:
with tf.Session() as sess:
会话的空参数表示此代码将附加到默认本地会话(或建立还没有建立)。
在建立会话以后,全部的tf.Variable实例都经过在初始化操做中调用tf.Session.run来初始化。
init = tf.global_variables_initializer()
sess.run(init)
tf.Session.run方法将进行参数传递操做。在这个调用中,只进行变量的初始值。 图的其他部分都不在这里运行; 这在下面的训练循环中运行。
训练循环
在会话初始化变量后,能够开始训练。
用户代码控制每一步的训练,最简单的循环能够是:
for step in xrange(FLAGS.max_steps): sess.run(train_op)
可是,本教程稍微复杂一些,由于它还必须分割每一个步骤的输入数据,以匹配先前生成的占位符。
数据输入到图
对于每一个步骤,代码将生成一个Feed字典,其中包含一组数据,用于训练,由其所对应的占位符操做输入。
在fill_feed_dict()函数中,查询给定的DataSet用于其下一个batch_size图像和标签集,填充与占位符匹配的张量,其中包含下一个图像和标签。
images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size, FLAGS.fake_data)
而后生成一个python字典对象,其中占位符做为键,表明性的Feed张量做为值。
feed_dict = {
images_placeholder: images_feed,
labels_placeholder: labels_feed,
}
这将被传递给sess.run()函数的feed_dict参数,以供该训练循环使用。
检查状态
该代码指定在运行调用中获取的两个值:[train_op,loss]。
for step in xrange(FLAGS.max_steps): feed_dict = fill_feed_dict(data_sets.train, images_placeholder, labels_placeholder) _, loss_value = sess.run([train_op, loss], feed_dict=feed_dict)
由于要获取两个值,因此sess.run()返回一个包含两个项的元组。 要提取的值列表中的每一个Tensor对应于返回的元组中的numpy数组,在该训练步骤中填充该张量的值。 因为train_op是没有输出值的操做,返回的元组中的相应元素为None,所以被丢弃。 然而,若是模型在训练过程当中发生分歧,则损失张量的值可能变为NaN,所以咱们捕获该值用于记录。
假设没有NaN,训练运行良好,训练循环还会每100个步骤打印一个简单的状态文本,让用户知道训练状态。
if step % 100 == 0: print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
状态可视化
为了输出TensorBoard使用的事件文件,在图形构建阶段,全部的摘要(在这种状况下只有一个)被收集到一个Tensor中。
summary = tf.summary.merge_all()
而后在建立会话以后,能够将tf.summary.FileWriter实例化为写入事件文件,其中包含图形自己和摘要的值。
summary_writer = tf.summary.FileWriter(FLAGS.train_dir, sess.graph)
最后,每次评估摘要并将输出传递给add_summary()函数时,事件文件将被更新为新的摘要值。
summary_str = sess.run(summary, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)
当写入事件文件时,能够针对训练文件夹运行TensorBoard,以显示摘要中的值。
注意:有关如何构建和运行Tensorboard的更多信息,请参阅随附的教程Tensorboard:可视化学习。
保存检查点
为了输出一个检查点文件,能够用于稍后恢复模型进行进一步的训练或评估,咱们实例化一个tf.train.Saver。
saver = tf.train.Saver()
在训练循环中,将按期调用tf.train.Saver.save方法,将训练中各变量的值写入检查点文件。
saver.save(sess, FLAGS.train_dir, global_step=step)
在稍后的某些时候,可使用tf.train.Saver.restore方法来从新加载模型参数来恢复训练。
saver.restore(sess, FLAGS.train_dir)
评估模型
每一步,代码将尝试针对训练和测试数据集来评估模型。 do_eval()函数被执行三次,用于训练,验证和测试数据集。
print('Training Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.train) print('Validation Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.validation) print('Test Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.test)
请注意,更复杂的使用一般会将data_sets.test隔离,以便在大量超参数调整后才能进行检查。 然而,为了简单的小MNIST问题,咱们对全部数据进行评估。
构建评估图
在进入训练循环以前,评估操做应该是经过调用mnist.py中的evaluate()函数,使用与loss()函数相同的参数构建的。
eval_correct = mnist.evaluation(logits, labels_placeholder)
评估函数简单地生成一个tf.nn.in_top_k操做,若是真正的标签能够在K个最可能的预测中找到,那么能够自动对每一个模型输出进行评分。 在这种状况下,咱们将K的值设置为1,以便仅对真实标签考虑预测是否正确。
eval_correct = tf.nn.in_top_k(logits, labels, 1)
评估输出
而后能够建立一个填充feed_dict的循环,并针对eval_correct op调用sess.run()来评估给定数据集上的模型。
for step in xrange(steps_per_epoch): feed_dict = fill_feed_dict(data_set, images_placeholder, labels_placeholder) true_count += sess.run(eval_correct, feed_dict=feed_dict)
true_count变量简单地累加了in_top_k op已经肯定为正确的全部预测。 从那里能够从简单地除以实例的总数来计算精度。
precision = true_count / num_examples print(' Num examples: %d Num correct: %d Precision @ 1: %0.04f' % (num_examples, true_count, precision))
原文:《TensorFlow Mechanics 101》:https://www.tensorflow.org/get_started/mnist/mechanics