[程序员指南4]图表和会话

图表和会话

TensorFlow使用数据流图来表示您的计算,这取决于各个操做之间的相关性。这致使了一个低级编程模型,您首先定义数据流图,而后建立一个TensorFlow 会话,以便跨一组本地和远程设备运行部分图形。html

若是您打算直接使用低级编程模型,本指南将很是有用。更高级别的API(如tf.estimator.EstimatorKeras)会隐藏最终用户的图形和会话细节,可是若是您想了解这些API是如何实现的,本指南也可能颇有用。python

 

为何要数据流图?

 

数据流是并行计算的通用编程模型。在数据流图中,节点表示计算单位,边缘表示计算消耗或产生的数据。例如,在TensorFlow图中,该tf.matmul 操做将对应于具备两个输入边(要被乘法的矩阵)和一个输出边(乘法的结果)的单个节点。算法

数据流在执行程序时能够利用TensorFlow的几个优势:编程

  • 并行。经过使用显式边来表示操做之间的依赖关系,系统很容易识别并行执行的操做。api

  • 分布式执行。经过使用显式边来表示在操做之间流动的值,TensorFlow能够跨越链接到不一样机器的多个设备(CPU,GPU和TPU)对程序进行分区。TensorFlow在设备之间插入必要的通讯和协调。
  • 汇编。TensorFlow的XLA编译器可使用数据流图中的信息来生成更快的代码,例如经过将相邻操做融合在一块儿。
  • 可移植性。数据流图是模型中代码的语言无关表示。您能够在Python中构建数据流图,将其存储在SavedModel中,并在C ++程序中将其还原为低延迟推断。

什么是tf.Graph

tf.Graph包含两种相关信息:数组

  • 图形结构。图形的节点和边缘,指示单个操做如何组合在一块儿,但不规定如何使用它们。图形结构就像汇编代码:检查它能够传达一些有用的信息,但不包含源代码传达的全部有用的上下文。浏览器

  • 图形集合。TensorFlow提供了一种用于存储元数据集合的通用机制tf.Graphtf.add_to_collection功能使您可以将对象列表与键(其中tf.GraphKeys 定义了一些标准键)tf.get_collection相关联,并使您可以查找与键相关联的全部对象。TensorFlow库的许多部分都使用此功能:例如,当您建立时tf.Variable,默认状况下将其添加到表示“全局变量”和“可培训变量”的集合中。当你之后来建立一个tf.train.Saver或者 tf.train.Optimizer,这些集合中的变量被用做默认参数。

建一个 tf.Graph

大多数TensorFlow程序从数据流图构建阶段开始。在此阶段,您调用构造新tf.Operation (节点)和tf.Tensor(边)对象的TensorFlow API函数,并将它们添加到tf.Graph 实例中。TensorFlow提供了一个默认图形,它是同一上下文中全部API函数的隐式参数。例如:缓存

  • 调用tf.constant(42.0)建立一个tf.Operation生成该值的单个42.0,将其添加到默认图形,并返回一个tf.Tensor表示常量的值。服务器

  • 呼叫tf.matmul(x, y)建立一个tf.Operation相乘的值tf.Tensor对象xy,把它添加到默认的图形,并返回一个tf.Tensor表示相乘的结果。网络

  • 执行v = tf.Variable(0)会添加图形tf.Operation,它将存储在tf.Session.run调用之间持续的可写张量值tf.Variable对象包装该操做,而且可使用像的张量,这将读出的存储值的当前值。tf.Variable对象也有例如方法 assignassign_add用于建立tf.Operation对象在被执行时,更新所存储的值。(有关变量的更多信息,请参见变量。)

  • 调用tf.train.Optimizer.minimize将会将运算和张量添加到计算梯度的默认图形上,并返回一个tf.Operation运行时,将这些渐变应用于一组变量。

大多数程序只依赖于默认图形。可是,有关更多高级用例,请参阅处理多个图表高级API(如tf.estimator.EstimatorAPI)表明您管理默认图表,例如 - 能够为培训和评估建立不一样的图表。

注意:调用TensorFlow API中的大多数函数仅将操做和张量添加到默认图形,但执行实际计算。相反,您组合这些函数,直到您有tf.Tensor 或tf.Operation表明总体计算(例如执行梯度降低的一步),而后将该对象传递给a tf.Session执行计算。有关tf.Session详细信息,请参见“执行图中的” 一节。

命名操做

tf.Graph对象定义一个命名空间tf.Operation它包含的对象。TensorFlow会自动为图形中的每一个操做选择惟一的名称,但给出操做描述性名称可使程序更容易阅读和调试。TensorFlow API提供了两种覆盖操做名称的方法:

  • 建立新的tf.Operation或返回新的 API函数tf.Tensor接受可选name参数。例如, tf.constant(42.0, name="answer")建立一个新的tf.Operationnamed "answer"并返回一个tf.Tensornamed "answer:0"若是默认图形已经包含一个名为的操做"answer",那么TensorFlow将附加 "_1""_2"等等到名称,以使其惟一。

  • tf.name_scope功能能够为在特定上下文中建立的全部操做添加名称范围前缀。当前名称范围前缀是"/"全部活动tf.name_scope 上下文管理器的名称的不相关列表若是在当前上下文中已经使用了名称范围,则TensorFlow会附加"_1""_2"等等。例如:

c_0 = tf.constant(0, name="c")  # => operation named "c"

# Already-used names will be "uniquified".
c_1 = tf.constant(2, name="c")  # => operation named "c_1"

# Name scopes add a prefix to all operations created in the same context.
with tf.name_scope("outer"):
  c_2 = tf.constant(2, name="c")  # => operation named "outer/c"

  # Name scopes nest like paths in a hierarchical file system.
  with tf.name_scope("inner"):
    c_3 = tf.constant(3, name="c")  # => operation named "outer/inner/c"

  # Exiting a name scope context will return to the previous prefix.
  c_4 = tf.constant(4, name="c")  # => operation named "outer/c_1"

  # Already-used name scopes will be "uniquified".
  with tf.name_scope("inner"):
    c_5 = tf.constant(5, name="c")  # => operation named "outer/inner_1/c"

图形可视化器使用名称范围来对操做进行分组,并减小图形的视觉复杂性。有关详细信息,请参阅可视化图形

 

请注意,tf.Tensor对象是以tf.Operation 产生张量做为输出的隐式命名的张量名称的格式"<OP_NAME>:<i>" 以下:

  • "<OP_NAME>" 是产生它的操做的名称。
  • "<i>" 是表示操做输出中该张量的索引的整数。

将操做放置在不一样的设备上

若是您但愿TensorFlow程序使用多个不一样的设备,该 tf.device功能提供了一种方便的方式来请求在特定上下文中建立的全部操做都放置在同一设备(或设备类型)上。

设备规范具备如下形式:

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

哪里:

  • <JOB_NAME> 是一个不以数字开头的字母数字字符串。
  • <DEVICE_TYPE>是注册的设备类型(如GPUCPU)。
  • <TASK_INDEX>是表示做业中任务的索引的非负整数<JOB_NAME>查看tf.train.ClusterSpec工做和任务的解释。
  • <DEVICE_INDEX> 是表示设备索引的非负整数,例如,区分在同一进程中使用的不一样GPU设备。

您不须要指定设备规范的每一个部分。例如,若是您使用单个GPU进行单机配置,则能够tf.device将一些操做用于CPU和GPU:

# Operations created outside either context will run on the "best possible"
# device. For example, if you have a GPU and a CPU available, and the operation
# has a GPU implementation, TensorFlow will choose the GPU.
weights = tf.random_normal(...)

with tf.device("/device:CPU:0"):
  # Operations created in this context will be pinned to the CPU.
  img = tf.decode_jpeg(tf.read_file("img.jpg"))

with tf.device("/device:GPU:0"):
  # Operations created in this context will be pinned to the GPU.
  result = tf.matmul(weights, img)

若是要在典型的分布式配置中部署TensorFlow ,则能够指定做业名称和任务ID,以将变量放置在参数服务器做业("/job:ps")中的任务上,以及在worker做业("/job:worker"中的任务上的其余操做

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.device为您选择TensorFlow图的各个操做或普遍区域的展现位置提供了很大的灵活性。在许多状况下,有一些简单的启发式工做很好。例如, tf.train.replica_device_setterAPI可用于tf.device进行数据并行分布式培训的操做例如,如下代码片断显示了如何tf.train.replica_device_setter将不一样的布局策略应用于tf.Variable对象和其余操做:

with tf.device(tf.train.replica_device_setter(ps_tasks=3)):
  # tf.Variable objects are, by default, placed on tasks in "/job:ps" in a
  # round-robin fashion.
  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)     # placed on "/job:worker"
  layer_0 = tf.matmul(input_data, w_0) + b_0  # placed on "/job:worker"
  layer_1 = tf.matmul(layer_0, w_1) + b_1     # placed on "/job:worker"

相似Tensor的物体

许多TensorFlow操做将一个或多个tf.Tensor对象做为参数。例如,tf.matmul须要两个tf.Tensor对象,并tf.add_n获取一个n tf.Tensor对象列表为了方便起见,这些函数将接受一个相似张量的对象代替a tf.Tensor,并将其隐式转换为tf.Tensor使用该tf.convert_to_tensor方法。相似Tensor的对象包括如下类型的元素:

您可使用注册附加的张量类型 tf.register_tensor_conversion_function

注意:默认状况下,TensorFlow将在tf.Tensor每次使用相同的张量对象时建立一个新的若是张量类物体较大(例如 numpy.ndarray包含一组训练样本),而且屡次使用,则可能会耗尽内存。为了不这种状况,请手动调用tf.convert_to_tensor相似张量的对象,并使用返回值 tf.Tensor

在a中执行图形 tf.Session

TensorFlow使用tf.Session该类来表示客户端程序之间的链接 - 一般是Python程序,尽管相似的接口可用于其余语言---和C ++运行时。一个tf.Session对象提供对本地机器中的设备和使用分布式TensorFlow运行时的远程设备的访问。它还缓存有关您的信息, tf.Graph以便您能够屡次有效地运行相同的计算。

建立一个 tf.Session

若是您使用低级TensorFlow API,则能够按照tf.Session 如下方式为当前默认图形建立一个

# Create a default in-process session.
with tf.Session() as sess:
  # ...

# Create a remote session.
with tf.Session("grpc://example.org:2222"):
  # ...

因为tf.Session拥有物理资源(如GPU和网络链接),所以一般将其用做在with 退出块时自动关闭会话的上下文管理器(在块中)。也能够在不使用with块的状况下建立会话,可是tf.Session.close当您完成它以释放资源时,应该显式调用它。

注意:更高级别的API,例如tf.train.MonitoredTrainingSession或 tf.estimator.Estimator将为您建立和管理一个tf.Session这些API接受可选targetconfig参数(直接或做为的一部分tf.estimator.RunConfig,以下所述对象),具备相同的含义。

tf.Session.__init__ 接受三个可选参数:

  • target若是此参数为空(默认值),则会话将仅使用本地计算机中的设备。可是,您还能够指定一个grpc://URL来指定TensorFlow服务器的地址,该服务器将会话访问该服务器所控制的计算机上的全部设备。请参阅 tf.train.Server如何建立TensorFlow服务器的详细信息。例如,在常见的图形间复制 配置中,tf.Session链接到tf.train.Server与客户端相同的进程。分布式TensorFlow 部署指南介绍了其余常见的场景。

  • graph默认状况下,一个新的tf.Session绑定到---而且只能在---当前的默认图中运行。若是您在程序中使用多个图形(有关更多详细信息,请参阅使用多个图形编程),您能够tf.Graph在构建会话时指定一个显式

  • config此参数容许您指定tf.ConfigProto控制会话的行为。例如,一些配置选项包括:

  • allow_soft_placement将其设置True为启用“软”设备布局算法,该算法忽略tf.device尝试在GPU设备上放置仅CPU操做的注释,并将其放置在CPU上。

  • cluster_def当使用分布式TensorFlow时,此选项容许您指定计算中要使用的计算机,并提供做业名称,任务索引和网络地址之间的映射。看 tf.train.ClusterSpec.as_cluster_def详情。

  • graph_options.optimizer_options在执行TensorFlow在图形上执行的优化控制。

  • gpu_options.allow_growth将其设置True为更改GPU内存分配器,以便逐渐增长分配的内存量,而不是在启动时分配大部份内存。

使用tf.Session.run执行操做

tf.Session.run方法是运行tf.Operation 或评估a 的主要机制tf.Tensor你能够经过一个或多个tf.Operation或 tf.Tensor对象tf.Session.run,并TensorFlow将执行所需计算结果的操做。

tf.Session.run要求您指定的列表,它决定了返回值,也能够是一个tf.Operation,一个tf.Tensor,或张样型tf.Variable这些提取肯定必须执行总体的子图tf.Graph才能产生结果:这是包含在提取列表中命名的全部操做的子图,以及其输出用于计算提取值的全部操做。例如,如下代码片断显示了不一样的参数如何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:
  # Run the initializer on `w`.
  sess.run(init_op)

  # Evaluate `output`. `sess.run(output)` will return a NumPy array containing
  # the result of the computation.
  print(sess.run(output))

  # Evaluate `y` and `output`. Note that `y` will only be computed once, and its
  # result used both to return `y_val` and as an input to the `tf.nn.softmax()`
  # op. Both `y_val` and `output_val` will be NumPy arrays.
  y_val, output_val = sess.run([y, output])

tf.Session.run还能够选择一个Feed的字典,它是从tf.Tensor对象(一般是tf.placeholder张量)到值(一般是Python标量,列表或NumPy数组)的映射,将代替执行中的那些张量。例如:

# Define a placeholder that expects a vector of three floating-point values,
# and a computation that depends on it.
x = tf.placeholder(tf.float32, shape=[3])
y = tf.square(x)

with tf.Session() as sess:
  # Feeding a value changes the result that is returned when you evaluate `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]"

  # Raises `tf.errors.InvalidArgumentError`, because you must feed a value for
  # a `tf.placeholder()` when evaluating a tensor that depends on it.
  sess.run(y)

  # Raises `ValueError`, because the shape of `37.0` does not match the shape
  # of placeholder `x`.
  sess.run(y, {x: 37.0})

tf.Session.run还接受一个可选options参数,使您可以指定关于调用的选项,以及可选run_metadata参数,使您可以收集有关执行的元数据。例如,您能够一块儿使用这些选项来收集有关执行的跟踪信息:

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

with tf.Session() as sess:
  # Define options for the `sess.run()` call.
  options = tf.RunOptions()
  options.output_partition_graphs = True
  options.trace_level = tf.RunOptions.FULL_TRACE

  # Define a container for the returned metadata.
  metadata = tf.RunMetadata()

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

  # Print the subgraphs that executed on each device.
  print(metadata.partition_graphs)

  # Print the timings of each operation that executed.
  print(metadata.step_stats)

可视化图形

TensorFlow包括能够帮助您了解图形中的代码的工具。曲线图可视化是在视觉上呈现您图的结构在浏览器TensorBoard的组分。建立可视化的最简单方法是在建立可视化tf.Graph时 传递tf.summary.FileWriter

# Build your 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` provides access to the graph used in a `tf.Session`.
  writer = tf.summary.FileWriter("/tmp/log/...", sess.graph)

  # Perform your computation...
  for i in range(1000):
    sess.run(train_op)
    # ...

  writer.close()

注意:若是使用a tf.estimator.Estimator,则图形(和任何摘要)将自动记录到model_dir建立估计器时指定的图形

而后,您能够打开登陆tensorboard,导航到“图形”选项卡,并查看图形结构的高级可视化。请注意,典型的TensorFlow图 - 特别是具备自动计算梯度的训练图 - 具备太多的节点能够当即可视化。图形可视化器利用名称范围将相关操做分组为“超级”节点。您能够点击任何这些超级节点上的橙色“+”按钮,将子图扩展到里面。

有关使用TensorBoard可视化TensorFlow应用程序的更多信息,请参阅TensorBoard教程

用多个图表编程

注意:训练模型时,组织代码的常见方式是使用一个图形来训练模型,以及用于评估或执行训练模型推理的单独图形。在许多状况下,推理图将与训练图不一样:例如,在各类状况下,技术(如退出和批量归一化)都使用不一样的操做。此外,默认实用程序tf.train.Saver使用tf.Variable对象的名称(其名称基于底层tf.Operation)来标识保存的检查点中的每一个变量。编程时,您可使用彻底独立的Python进程构建和执行图形,也能够在同一过程当中使用多个图形。本节介绍如何在同一过程当中使用多个图。

如上所述,TensorFlow提供了在相同上下文中隐式传递给全部API函数的“默认图”。对于许多应用程序,单个图形就足够了。可是,TensorFlow还提供了操做默认图形的方法,这在更先进的用例中可使用。例如:

  • tf.Graph定义tf.Operation对象的命名空间:单个图中的每一个操做必须具备惟一的名称。若是已经使用了请求的名称,TensorFlow将经过附加"_1""_2"等等将其命名为“惟一” 使用多个显式建立的图形能够更好地控制每一个操做的名称。

  • 默认图形存储有关每一个tf.Operation和 tf.Tensor以前添加的信息若是您的程序建立大量未链接的子图,使用其余子图可能会更有效 tf.Graph,以便无关的状态能够被垃圾回收

您能够tf.Graph使用tf.Graph.as_default上下文管理器安装不一样的默认图形 

g_1 = tf.Graph()
with g_1.as_default():
  # Operations created in this scope will be added to `g_1`.
  c = tf.constant("Node in g_1")

  # Sessions created in this scope will run operations from `g_1`.
  sess_1 = tf.Session()

g_2 = tf.Graph()
with g_2.as_default():
  # Operations created in this scope will be added to `g_2`.
  d = tf.constant("Node in g_2")

# Alternatively, you can pass a graph when constructing a `tf.Session`:
# `sess_2` will run operations from `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.get_default_graph,返回一个tf.Graph对象:

# Print all of the operations in the default graph.
g = tf.get_default_graph()
print(g.get_operations())
相关文章
相关标签/搜索