流图与会话

TensorFlow 使用数据流图(Dataflow graph,后文以“流图”简称。)表示计算过程,它是依据各个操作之间的依赖关系生成的。这是一个底层的编程模型,你需要先定义数据流图,然后创建一个 TensorFlow 会话以在多个本地或远程的设备上运行流图的各个部分。

tf.estimator.Estimator

为什么要用数据流图?

tf.matmul

TensorFlow 利用数据流模型来执行程序,有如下几个优点:

  • 并行编程 使用显式边来表示操作间的依赖关系,系统就能很容易的识别出可以并行的操作。

  • 分布执行  用显式边来表示操作间传递的值,TensorFlow 可以将你的程序分布到不同机器的不同设备(CPU, GPU 和 TPU)上,并完成必要的设备间通信和协调工作。

  • XLA 概述

  • 保存和恢复

tf.Graph

tf.Graph

  • 流图结构 图的节点和边表明了各个独立操作组合在一起的方式,但并没有说明他们的用法。流图结构很像汇编代码:查看代码能够得到一些有用的信息,但它并不能传达给你所有源代码中的有效信息。

  • tf.train.Optimizer

tf.Graph

tf.Graph

tf.estimator.Estimator

tf.Session

操作的命名

tf.Operation

  • tf.Tensor

  • tf.name_scope

    c_0 = tf.constant(0, name="c")  # => operation named "c"
    
     # 已经被使用过的名称将会变为 "uniquified"。
     c_1 = tf.constant(2, name="c")  # => operation named "c_1"
    
     # 命名空间为在同一上下文环境中创建的所有操作添加一个前缀。
     with tf.name_scope("outer"):
       c_2 = tf.constant(2, name="c")  # => 操作被命名为"outer/c"
    
       # 命名空间像分层文件系统中嵌套的路径。
       with tf.name_scope("inner"):
         c_3 = tf.constant(3, name="c")  # => 操作被命名为 "outer/inner/c"
    
       # 退出命名空间,将返回到前一个前缀名称所表示的命名空间。
       c_4 = tf.constant(4, name="c")  # => 操作被命名为 "outer/c_1"
    
     # 已经被使用过的名称将会变为 "uniquified"。
     with tf.name_scope("inner"):
         c_5 = tf.constant(5, name="c")  # => 操作被命名为 "outer/inner_1/c"
    

图形可视化工具使用命名空间来将操作分组,并减少图形的视觉复杂性。请参阅将流图可视化来获取更多信息。

tf.Operation

  • "<OP_NAME>" 是生成 tensor 的操作名称。
  • "<i>" 是一个整数,表示操作的输出中 tensor 的索引。

在不同设备部署操作

tf.device

tf.device

/job:<JOB_NAME>/task:<TASK_INDEX>/device:<DEVICE_TYPE>:<DEVICE_INDEX>

分别表示:

  • <JOB_NAME> 是一个可以包含字母与数字的字符串,但不能以数字开头。
  • <DEVICE_TYPE> 是一个已注册的设备类型(例如 GPU 或者 CPU)。
  • tf.train.ClusterSpec
  • <DEVICE_INDEX> 是一个非负整数,表示设备的索引,例如,用来区分在同一进程中使用的不同 GPU 设备。

tf.device

# 创建时没有指定任何设备的操作将在“尽可能最好”的设备上运行。
# 例如,如果你有一个 GPU 和一个 CPU 可用,并且该操作具有 GPU
# 实现,则 TensorFlow 将选择该 GPU。
weights = tf.random_normal(...)

with tf.device("/device:CPU:0"):
  #  此上下文中创建的操作会被分配到 CPU 上。
  img = tf.decode_jpeg(tf.read_file("img.jpg"))

with tf.device("/device:GPU:0"):
  # 当前上下文环境中创建的操作会被分配到 GPU 上。
  result = tf.matmul(weights, img)

分布式 TensorFlow

with tf.device("/job:ps/task:0"):
  weights_1 = tf.Variable(tf.truncated_normal([784, 100]))
  biases_1 = tf.Variable(tf.zeroes([100]))

with tf.device("/job:ps/task:1"):
  weights_2 = tf.Variable(tf.truncated_normal([100, 10]))
  biases_2 = tf.Variable(tf.zeroes([10]))

with tf.device("/job:worker"):
  layer_1 = tf.matmul(train_batch, weights_1) + biases_1
  layer_2 = tf.matmul(train_batch, weights_2) + biases_2

tf.Variable

with tf.device(tf.train.replica_device_setter(ps_tasks=3)):
  # tf.Variable  默认情况下以轮询调度的方式部署在 "/job:ps" 的任务列表中
  w_0 = tf.Variable(...)  # placed on "/job:ps/task:0"
  b_0 = tf.Variable(...)  # placed on "/job:ps/task:1"
  w_1 = tf.Variable(...)  # placed on "/job:ps/task:2"
  b_1 = tf.Variable(...)  # placed on "/job:ps/task:0"

  input_data = tf.placeholder(tf.float32)     # 部署 "/job:worker"
  layer_0 = tf.matmul(input_data, w_0) + b_0  # 部署 "/job:worker"
  layer_1 = tf.matmul(layer_0, w_1) + b_1     # 部署 "/job:worker"

可用作 Tensor 的对象

tf.Tensor

tf.register_tensor_conversion_function

tf.Tensor

tf.Session

tf.Graph

tf.Session

tf.Session

# 创建一个默认的进程内的会话。
with tf.Session() as sess:
  # ...

# 创建一个远程会话。
with tf.Session("grpc://example.org:2222"):
  # ...

tf.Session.close

tf.estimator.RunConfig

tf.Session.__init__

tf.Session.run

tf.Session.run

tf.Session.run

x = tf.constant([[37.0, -23.0], [1.0, 4.0]])
w = tf.Variable(tf.random_uniform([2, 2]))
y = tf.matmul(x, w)
output = tf.nn.softmax(y)
init_op = w.initializer

with tf.Session() as sess:
  # 运行 `w` 的初始化操作。
  sess.run(init_op)

  # 对 `output` 求值。`sess.run(output)` 将返回一个包含计算结果的 NumPy 数组。
  print(sess.run(output))

  # 对 `y` 和 `output` 求值。请注意, `y` 只会计算一次,计算结果既作为 `y_val` 的值返回,
  # 又会作为 `tf.nn.softmax()` 操作的输入。`y_val` 和 `output_val` 都是 NumPy 数组。
  y_val, output_val = sess.run([y, output])

tf.placeholder

# 定义一个三个浮点值向量的占位符和一个依赖于它的计算。
x = tf.placeholder(tf.float32, shape=[3])
y = tf.square(x)

with tf.Session() as sess:
  # 提供不同的参数值会求得不同的 `y` 值。
  print(sess.run(y, {x: [1.0, 2.0, 3.0]}))  # => "[1.0, 4.0, 9.0]"
  print(sess.run(y, {x: [0.0, 0.0, 5.0]}))  # => "[0.0, 0.0, 25.0]"

  # 抛出 `tf.errors.InvalidArgumentError`,因为你必须先给 `tf.placeholder()` 赋值,然后才能计算器依赖关系之上的 tensor 。
  sess.run(y)

  # 抛出 `ValueError`,因为 `37.0` 与 `x` 形状不匹配。
  sess.run(y, {x: 37.0})

tf.Session.run

y = tf.matmul([[37.0, -23.0], [1.0, 4.0]], tf.random_uniform([2, 2]))

with tf.Session() as sess:
  # 定义调用 `sess.run()` 的选项。
  options = tf.RunOptions()
  options.output_partition_graphs = True
  options.trace_level = tf.RunOptions.FULL_TRACE

  # 定义一个用于接受返回元数据的容器。
  metadata = tf.RunMetadata()

  sess.run(y, options=options, run_metadata=metadata)

  # 打印出在每个设备上执行的子流图。
  print(metadata.partition_graphs)

  # 打印出每次执行操作的执行时间。
  print(metadata.step_stats)

将流图可视化

tf.Graph

# 构建你的流图
x = tf.constant([[37.0, -23.0], [1.0, 4.0]])
w = tf.Variable(tf.random_uniform([2, 2]))
y = tf.matmul(x, w)
# ...
loss = ...
train_op = tf.train.AdagradOptimizer(0.01).minimize(loss)

with tf.Session() as sess:
  # `sess.graph` 提供了对 `tf.Session` 中流图的访问。
  writer = tf.summary.FileWriter("/tmp/log/...", sess.graph)

  # 执行你的计算...
  for i in range(1000):
    sess.run(train_op)
    # ...

  writer.close()

tf.estimator.Estimator

然后,你可以在 tensorboard 中打开日志,在 “Graph” 页面查看高度可视化的计算图结构。请注意, 一个典型的 TensorFlow 计算图——尤其是自动计算梯度的训练计算图——会由于节点太多而不能立刻全部可视化。计算图使用命名空间来将相关操作归纳到父节点。你可以点解父节点的橙色 "+" 按钮来展开其内部的子图。

要了解更多关于如何使用 TensorBoard 来可视化你的 TensorFlow 应用,请参阅 TensorBoard 指南

使用多个流图编程

tf.Operation

如上所述, TensorFlow 提供了一个“默认流图”,隐式传递给同一上下文中的所有 API 函数。对于许多个应用程序来说,一张流图就足够了。但是,TensorFlow 也提供了操作默认流图的方法,这在更高级的用例中是有用处的。例如:

tf.Graph

g_1 = tf.Graph()
with g_1.as_default():
  # 这作用域中创建的操作会加到  `g_1` 中。
  c = tf.constant("Node in g_1")

  # 这个作用域中创建的会话会运行 `g_1` 中的操作。
  sess_1 = tf.Session()

g_2 = tf.Graph()
with g_2.as_default():
  # 这作用域中创建的操作会加到  `g_2` 中。
  d = tf.constant("Node in g_2")

# 或者,你可以在构建 `tf.Session` 时传递一个流图:
# `sess_2`会运行 `g_2` 中的操作。
sess_2 = tf.Session(graph=g_2)

assert c.graph is g_1
assert sess_1.graph is g_1

assert d.graph is g_2
assert sess_2.graph is g_2

tf.Graph

# 打印默认流图中所有的操作。
g = tf.get_default_graph()
print(g.get_operations())