TensorFlow:运作方式入门

 mnist.py

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import math

import tensorflow as tf

# The MNIST dataset has 10 classes, representing the digits 0 through 9.
NUM_CLASSES = 10

# The MNIST images are always 28x28 pixels.
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE * IMAGE_SIZE


def inference(images, hidden1_units, hidden2_units):
  """尽可能地构建好图表,满足促使神经网络向前反馈并做出预测的要求.

  Args:
    images: Images placeholder, from inputs().
    hidden1_units: Size of the first hidden layer.
    hidden2_units: Size of the second hidden layer.

  Returns:
    softmax_linear: Output tensor with the computed logits.

  """
  # 每一层都创建于一个唯一的tf.name_scope之下
  # 创建于该作用域之下的所有元素都将带有其前缀
  # 当这些层是在hidden1作用域下生成时
  # 赋予权重变量的独特名称将会是"hidden1/weights"
  with tf.name_scope('hidden1'):
    weights = tf.Variable(
        tf.truncated_normal([IMAGE_PIXELS, hidden1_units],      # 通过tf.truncated_normal函数初始化权重变量
                            stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))),
        name='weights')                                         # 将根据所得到的均值和标准差,生成一个随机分布
    biases = tf.Variable(tf.zeros([hidden1_units]),             # 偏差的起始值都是0,而它们的shape则是其在该层中所接到的(connect to)单元数量
                         name='biases')
    hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)   # 嵌入了隐藏层所需的tf.matmul
  # Hidden 2
  with tf.name_scope('hidden2'):
    weights = tf.Variable(
        tf.truncated_normal([hidden1_units, hidden2_units],
                            stddev=1.0 / math.sqrt(float(hidden1_units))),
        name='weights')
    biases = tf.Variable(tf.zeros([hidden2_units]),
                         name='biases')
    hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
  # Linear
  with tf.name_scope('softmax_linear'):
    weights = tf.Variable(
        tf.truncated_normal([hidden2_units, NUM_CLASSES],
                            stddev=1.0 / math.sqrt(float(hidden2_units))),
        name='weights')
    biases = tf.Variable(tf.zeros([NUM_CLASSES]),
                         name='biases')
    logits = tf.matmul(hidden2, weights) + biases
  return logits


def loss(logits, labels):
  """从logits和labels计算损失函数
    往inference图表中添加生成损失(loss)所需要的操作(ops)
  Args:
    logits: Logits tensor, float - [batch_size, NUM_CLASSES].
    labels: labels_placeholer中的值,将被编码为一个含有1-hot values的Tensor
            如果类标识符为“3”,那么该值就会被转换为: [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
  Returns:
    loss: Loss tensor of type float.
  """
  labels = tf.to_int64(labels)
  return tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)


def training(loss, learning_rate):
  """往损失图表中添加计算并应用梯度(gradients)所需的操作.

  从loss()函数中获取损失Tensor,将其交给tf.scalar_summary.

  Creates an optimizer and applies the gradients to all trainable variables.

  The Op returned by this function is what must be passed to the
  `sess.run()` call to cause the model to train.

  Args:
    loss: Loss tensor, from loss().
    learning_rate: The learning rate to use for gradient descent.

  Returns:
    train_op: The Op for training.
  """
  # 可以向事件文件(events file)中生成汇总值(summary values).
  tf.summary.scalar('loss', loss)
  # 按照所要求的学习效率(learning rate)应用梯度下降法(gradients).
  optimizer = tf.train.GradientDescentOptimizer(learning_rate)
  # 一个变量用于保存全局训练步骤(global training step)的数值
  global_step = tf.Variable(0, name='global_step', trainable=False)
  # 使用minimize()函数更新系统中的三角权重(triangle weights)、增加全局步骤的操作
  # TensorFlow会话(session)诱发一个完整训练步骤所必须运行的操作
  train_op = optimizer.minimize(loss, global_step=global_step)
  return train_op


def evaluation(logits, labels):
  """在预测标签时评估logits的质量

  Args:
    logits: Logits tensor, float - [batch_size, NUM_CLASSES].
    labels: Labels tensor, int32 - [batch_size], with values in the
      range [0, NUM_CLASSES).

  Returns:
     标量int32张量,具有正确预测的示例数(从batch_size开始)
  """
  # 如果在K个最有可能的预测中可以发现真的标签,
  # 那么这个操作就会将模型输出标记为正确。
  # 把K的值设置为1,也就是只有在预测是真的标签时,才判定它是正确的
  correct = tf.nn.in_top_k(logits, labels, 1)
  # 返回真实标签的数量
  return tf.reduce_sum(tf.cast(correct, tf.int32))

fully_connected_feed.py

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=missing-docstring
import argparse
import os
import sys
import time

from six.moves import xrange  # pylint: disable=redefined-builtin
import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.examples.tutorials.mnist import mnist

# 基本模型参数作为外部标志.
FLAGS = None


def placeholder_inputs(batch_size):
  """ placeholder
  生成两个 placeholder 表示输入的图表.
  定义传入图表中的shape参数,shape参数中包括batch_size值,后续还会将实际的训练用例传入图表

  # 请注意,占位符的形状与完整图像和标签张量的形状相匹配
  # 但第一个维度现在是batch_size
  # 而不是训练或测试数据集的完整大小
  # 传入的整个图像和标签数据集会被切片
  # 以符合每一个操作所设置的batch_size值
  # 占位符操作将会填补以符合这个batch_size值

  Args:
    batch_size: 传入的整个图像和标签数据集会被切片,以符合每一个操作所设置的batch_size值

  Returns:
    images_placeholder: 图像 placeholder.
    labels_placeholder: 标签 placeholder.
  """
  images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,
                                                         mnist.IMAGE_PIXELS))
  labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))
  return images_placeholder, labels_placeholder


def fill_feed_dict(data_set, images_pl, labels_pl):
  """向图表提供反馈.

  执行每一步时,我们的代码会生成一个反馈字典(feed dictionary),
  其中包含对应步骤中训练所要使用的例子,
  这些例子的哈希键就是其所代表的占位符操作。

  Args:
    data_set: fill_feed_dict函数会查询给定的DataSet
    images_pl: 索要下一批次batch_size的图像
    labels_pl: 索要下一批次batch_size的标签

  Returns:
    feed_dict: 这个字典随后作为feed_dict参数,传入sess.run()函数中,为这一步的训练提供输入样例
  """
  # 与占位符相匹配的Tensor则会包含下一批次的图像和标签.
  images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size,
                                                 FLAGS.fake_data)
  # 以占位符为哈希键,创建一个Python字典对象,键值则是其代表的反馈Tensor
  feed_dict = {
      images_pl: images_feed,
      labels_pl: labels_feed,
  }
  return feed_dict


def do_eval(sess,
            eval_correct,
            images_placeholder,
            labels_placeholder,
            data_set):
  """Runs one evaluation against the full epoch of data.

  Args:
    sess: 经过模型训练后的会话
    eval_correct: Tensor返回正确预测的数量
    images_placeholder: 图像 placeholder.
    labels_placeholder: 标签 placeholder.
    data_set: 要评估的图像和标签集,来自input_data.read_data_sets()
  """
  # 并运行一个预测的评估.
  true_count = 0  # 计算正确预测的数量.
  steps_per_epoch = data_set.num_examples // FLAGS.batch_size
  num_examples = steps_per_epoch * FLAGS.batch_size
  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)   # 在调用sess.run()函数时传入eval_correct操作,目的就是用给定的数据集评估模型
  precision = float(true_count) / num_examples                  # true_count变量会累加所有in_top_k操作判定为正确的预测之和
  print('Num examples: %d  Num correct: %d  Precision @ 1: %0.04f' %
        (num_examples, true_count, precision))


def run_training():
  """循环地迭代式训练和评估"""
  # 得到一系列的图和标签为了训练, 验证, 和
  # 测试 on MNIST.
  data_sets = input_data.read_data_sets(FLAGS.input_data_dir, FLAGS.fake_data)

  # 一个Python语言中的with命令
  # 这个命令表明所有已经构建的操作都要与默认的tf.Graph全局实例关联起来
  # tf.Graph实例是一系列可以作为整体执行的操作
  with tf.Graph().as_default():
    # 生成标签和图像的占位符.
    images_placeholder, labels_placeholder = placeholder_inputs(
        FLAGS.batch_size)

    # 构建好图表,满足促使神经网络向前反馈并做出预测的要求
    logits = mnist.inference(images_placeholder,
                             FLAGS.hidden1,
                             FLAGS.hidden2)

    # 往inference图表中添加生成损失(loss)所需要的操作(ops)
    loss = mnist.loss(logits, labels_placeholder)

    # 往损失图表中添加计算并应用梯度(gradients)所需的操作
    train_op = mnist.training(loss, FLAGS.learning_rate)

    # 传入的logits和标签参数要与loss函数的一致。这样做事为了先构建Eval操作
    eval_correct = mnist.evaluation(logits, labels_placeholder)

    # 为了释放TensorBoard所使用的事件文件(events file)
    # 所有的即时数据(在这里只有一个)都要在图表构建阶段合并至一个操作(op)中
    summary = tf.summary.merge_all()

    # 添加变量初始化操作Op.
    init = tf.global_variables_initializer()

    # 为了得到可以用来后续恢复模型以进一步训练或评估的检查点文件(checkpoint file)
    saver = tf.train.Saver()

    # 创建一个tf.Session,用于运行图表.
    sess = tf.Session()

    # 实例化一个tf.train.SummaryWriter
    # 用于写入包含了图表本身和即时数据具体值的事件文件
    summary_writer = tf.summary.FileWriter(FLAGS.log_dir, sess.graph)

    # 通过调用各自初始化操作中的sess.run()函数进行初始化

    # 在初次调用时,init操作只包含了变量初始化程序tf.group。
    # 图表的其他部分不会在这里,而是在下面的训练循环运行
    sess.run(init)

    # 训练的每一步都是通过用户代码控制,而能实现有效训练的最简单循环就是:.
    for step in xrange(FLAGS.max_steps):
      start_time = time.time()

      # 使用此特定训练步骤的实际图像集和标签填充反馈字典
      feed_dict = fill_feed_dict(data_sets.train,
                                 images_placeholder,
                                 labels_placeholder)

      # 运行模型的一个步骤。 返回值是来自`train_op`(被丢弃)和`loss` Op的激活。
      # 要检查Ops或变量的值,可以将它们包含在传递给sess.run()的列表中,
      # 并且将在调用的元组中返回值tensors。
      _, loss_value = sess.run([train_op, loss],
                               feed_dict=feed_dict)

      duration = time.time() - start_time

      # 打印一行简单的状态文本,告知用户当前的训练状态
      if step % 100 == 0:
        # 打印状态.
        print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
        # 每次运行summary_op时,都会往事件文件中写入最新的即时数据
        # 函数的输出会传入事件文件读写器(writer)的add_summary()函数
        summary_str = sess.run(summary, feed_dict=feed_dict)
        summary_writer.add_summary(summary_str, step)
        summary_writer.flush()  # 事件文件写入完毕之后,可以就训练文件夹打开一个TensorBoard,查看即时数据的情况

      # 在训练循环中,将定期调用saver.save()方法
      # 向训练文件夹中写入包含了当前所有可训练变量值得检查点文件
      if (step + 1) % 1000 == 0 or (step + 1) == FLAGS.max_steps:
        checkpoint_file = os.path.join(FLAGS.log_dir, 'model.ckpt')
        saver.save(sess, checkpoint_file, global_step=step)
        # 每隔一千个训练步骤,我们的代码会尝试使用训练数据集与测试数据集,对模型进行评估
        # 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)


def main(_):
  if tf.gfile.Exists(FLAGS.log_dir):
    tf.gfile.DeleteRecursively(FLAGS.log_dir)
  tf.gfile.MakeDirs(FLAGS.log_dir)
  run_training()


if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--learning_rate',
      type=float,
      default=0.01,
      help='Initial learning rate.'
  )
  parser.add_argument(
      '--max_steps',
      type=int,
      default=2000,
      help='Number of steps to run trainer.'
  )
  parser.add_argument(
      '--hidden1',
      type=int,
      default=128,
      help='Number of units in hidden layer 1.'
  )
  parser.add_argument(
      '--hidden2',
      type=int,
      default=32,
      help='Number of units in hidden layer 2.'
  )
  parser.add_argument(
      '--batch_size',
      type=int,
      default=100,
      help='Batch size.  Must divide evenly into the dataset sizes.'
  )
  parser.add_argument(
      '--input_data_dir',
      type=str,
      default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                           'tensorflow/mnist/input_data'),
      help='Directory to put the input data.'
  )
  parser.add_argument(
      '--log_dir',
      type=str,
      default=os.path.join(os.getenv('TEST_TMPDIR', '/tmp'),
                           'tensorflow/mnist/logs/fully_connected_feed'),
      help='Directory to put the log data.'
  )
  parser.add_argument(
      '--fake_data',
      default=False,
      help='If true, uses fake data for unit testing.',
      action='store_true'
  )

  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

测试结果:

Training Data Eval:
Num examples: 55000  Num correct: 49370  Precision @ 1: 0.8976
Validation Data Eval:
Num examples: 5000  Num correct: 4515  Precision @ 1: 0.9030
Test Data Eval:
Num examples: 10000  Num correct: 9036  Precision @ 1: 0.9036

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值