TensorFlow技术101

来源:互联网 发布:淘宝客服工作目标 编辑:程序博客网 时间:2024/05/29 09:29
TensorFlow技术101
代码:tensorflow/examples/tutorials/mnist/
    本教程的目标是展示如何使用TensorFlow来训练和评估使用(经典)MNIST数据集的手写数字分类的简单前馈神经网络。本教程的目标用户是有兴趣使用TensorFlow的有经验的机器学习用户。
    这些教程不适用于一般的机器学习教学。
    请确保您已按照说明安装TensorFlow。
一、教程文件
    本教程引用了以下文件:
    文件                                         目的
    mnist.py                                  构建完全连接的MNIST模型的代码。
    fully_connected_feed.py    使用Feed字典对建立的MNIST模型与下载的数据集进行训练的主代码。
   只需直接运行fully_connected_feed.py文件即可开始训练:
   python fully_connected_feed.py
二、准备数据
    MNIST是机器学习中的经典问题。问题是要查看手写数字的灰度28x28像素图像,并确定图像代表哪个数字,从零到九的所有数字。

MNIST数字

MNIST Digits

    欲了解更多信息,请参阅Yann LeCun的MNIST页面或Chris Olah的MNIST可视化。
下载
    在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操作,它们将输入的形状(包括batch_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()函数。
三、构建图
    在为数据创建占位符后,根据3阶段模式(inference(),loss()和training())从mnist.py文件构建图形。
    1.inference() - 根据需要构建图表,以便向前运行网络进行预测。
    2.loss() - 向推理图添加产生损失所需的操作。

    3.training() - 向损失图中添加计算和应用渐变所需的操作。


推理(inference)
    inference()函数根据需要构建图形,以返回将包含输出预测的张量。
    它将图像占位符作为输入,并在其上建立一对完全连接的层,其中ReLU激活,随后是一个指定输出逻辑的十个节点线性层。
    每个图层都在唯一的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来初始化,并且给定它们的二维张量的形状,其中第一个dim表示权重连接层中的单位数,第二个dim表示权重连接的图层中的单位。对于名为hidden1的第一个图层,尺寸为[IMAGE_PIXELS,hidden1_units],因为权重会将图像输入连接到hidden1图层。 tf.truncated_normal初始化器生成一个具有给定均值和标准差的随机分布。
    然后用tf.zeros初始化偏置,以确保它们以所有的零值开始,它们的形状就是它们所连接的图层单元的数量。
    图形的三个主要操作 - 两个tf.nn.relu操作包装tf.matmul隐藏层和一个额外的tf.matmul为logits - 然后创建,每个轮流,每个单独的tf.Variable实例连接到每个输入占位符或前一层的输出张量。
    hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
    hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
    logits = tf.matmul(hidden2, weights) + biases
    最后,返回将包含输出的逻辑张量。
loss
    loss()函数通过添加所需的损失操作来进一步构建图表。
    首先,来自labels_placeholder的值被转换为64位整数。然后,添加一个tf.nn.sparse_softmax_cross_entropy_with_logits操作,以自动生成labels_placeholder中的单热标签,并将inference()函数的输出logits与那些单热标签进行比较。
    labels = tf.to_int64(labels)
    cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(
        labels=labels, logits=logits, name='xentropy')
    然后使用tf.reduce_mean来平均整个批量维度(第一维度)的交叉熵值作为总损失。
    loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')
    然后将包含损失值的张量返回。
    注意:交叉熵是信息理论的一个概念,它允许我们描述相信神经网络的预测有多糟糕,因为实际上是真的。欲了解更多信息,请阅读博客文章视觉信息理论(http://colah.github.io/posts/2015-09-Visual-Information/)。
训练
    training()函数添加了通过渐变下降来减少损失所需的操作。
    首先,它从loss()函数中获取损失张量,并将其传递给tf.summary.scalar,与tf.summary.FileWriter(见下文)一起使用时,可以将事件文件中的汇总值生成。在这种情况下,每次写出摘要时都会发出损失的快照值。
    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)
四、训练模型
    构建图形之后,可以在由fully_connected_feed.py中的用户代码控制的循环中迭代地训练和评估该图形。

    在run_training()函数的顶部是一个带有命令的python,它指示所有内置操作将与默认的全局tf.Graph实例相关联。
    with tf.Graph().as_default():
    tf.Graph是可以作为一个组一起执行的ops集合。大多数TensorFlow使用将只需要依靠单个默认图。
    更复杂的使用多个图是可能的,但超出了这个简单的教程的范围。
会话
    一旦所有的构建准备工作完成,并且生成了所有必要的操作,就会创建一个tf.Session来运行该图形。
    sess = tf.Session()
    或者,可以将一个会话生成为一个带有范围的块:
    with tf.Session() as sess:
    会话的空参数表示此代码将附加到(或创建,如果尚未创建)默认本地会话。
    在创建会话之后,立即通过调用tf.Session.run初始化操作初始化所有的tf.Variable实例。
    init = tf.global_variables_initializer()
    sess.run(init)
    tf.Session.run方法将运行与作为参数传递的op相对应的图的完整子集。在这第一个调用中,init op是一个仅包含变量初始值的tf.group。没有其他的图表在这里运行;发生在下面的训练循环中。
训练循环
    用会话初始化变量后,可以开始培训。
    用户代码控制每步的训练,最简单的可以做有用训练的循环是:
    for step in xrange(FLAGS.max_steps):
        sess.run(train_op)
    但是,本教程稍微复杂一些,因为它也必须为每个步骤分割输入数据以匹配先前生成的占位符。
填图
    对于每一步,代码将生成一个饲料字典,该饲料字典将包含该步骤所训练的一组示例,由它们所代表的占位符操作。
    在fill_feed_dict()函数中,查询给定的DataSet的下一个batch_size图像和标签集合,并且匹配占位符的张量被填充,包含下一个图像和标签。
    images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size,
                                                   FLAGS.fake_data)
    然后用占位符作为关键字和代表性的馈送张量作为值生成一个python字典对象。
    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()返回一个包含两个元素的元组。要获取的值列表中的每个张量对应于返回的元组中的一个numpy数组,在这个训练步骤中填充该张量的值。由于train_op是一个没有输出值的操作,返回的元组中的对应元素是None,因此被丢弃。然而,如果训练期间模型发散,则损失张量的值可能变为NaN,因此我们将这个值记录下来。
    假设训练运行良好,没有NaNs,训练循环还会每100步打印一个简单的状态文本,让用户知道训练的状态。
    if step % 100 == 0:
        print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
可视化状态
    为了发布由TensorBoard使用的事件文件,在图构建阶段,所有的摘要(在本例中只有一个)被收集到一个张量中。
    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可以运行在训练文件夹中以显示摘要中的值。

MNIST TensorBoard

MNIST 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()函数相同的logits / labels参数来构建Eval op。
    eval_correct = mnist.evaluation(logits, labels_placeholder)
    如果在K个最可能的预测中可以找到真正的标签,那么evaluation()函数就会简单地生成一个tf.nn.in_top_kop,它可以自动将每个模型输出评分为正确的。在这种情况下,我们将K的值设置为1,只考虑真实标签的预测正确性。
    eval_correct = tf.nn.in_top_k(logits, labels, 1)
评估输出
    然后可以创建一个循环来填充feed_dict,并调用sess.run()来针对eval_correct op来评估给定数据集上的模型。
    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))


本文主要使用谷歌翻译翻译。