dataflow的优势
dataflow是并行计算的通用编程模型。在dataflow中,节点表示计算单位,edge表示计算消耗或产生的数据。例如,在TensorFlow图中,tf.matmul操作将对应于具有两个输入边(要乘以的矩阵)和一个输出边(乘法的结果)的单个节点。
并行:通过使用显式边来表示操作之间的依赖关系,系统很容易识别并行执行的操作。
分布式执行:通过使用显式边来表示在操作之间流动的值,TensorFlow可以跨越连接到不同机器的多个设备(CPU,GPU和TPU)对程序进行分区。TensorFlow在设备之间插入必要的通信和协调。
汇编:TensorFlow的XLA编译器可以使用数据流图中的信息来生成更快的代码,例如通过将相邻操作相互融合在一起。
可移植性:数据流图是模型中代码的语言无关表示。你可以在Python中构建数据流图,将其存储在SavedModel中,并将其还原为C++程序,以实现低延迟推理。
建立一个tf.graph()
大多数TensorFlow程序从数据流图构建阶段开始。 在此阶段,您调用构造新的tf.Operation(node)和tf.Tensor(edge)对象的TensorFlow API函数,并将它们添加到tf.Graph实例。 TensorFlow提供了一个默认图形,它是同一上下文中所有API函数的隐式参数。 例如:
调用tf.constant(42.0)创建一个单独的tf.Operation,产生值42.0,将其添加到默认图形,并返回一个表示常量值的tf.Tensor。
调用tf.matmul(x,y)创建一个单独的tf.Operation,将tf.Tensor对象x和y的值相乘,将其添加到默认图形,并返回一个表示乘法结果的tf.Tensor。
执行v=tf.Variable(0)向图形添加一个tf.Operation,它将存储在tf.Session.run调用之间持续的可写张量值。tf.Variable对象包装此操作,可以像张量一样使用,它将读取存储值的当前值。tf.Variable对象还有一些方法,如assign和assign_add,创建tf.Operation对象,在执行时,更新存储的值。(有关变量的更多信息,请参见Variables。)
调用tf.train.Optimizer.minimize会将运算和张量添加到计算梯度的默认图形上,并返回一个tf.Operation,当运行时,将这些梯度应用于一组变量。
大多数程序仅依赖于使用默认图。但是,更多高级用例处理多个图。高级API(如tf.estimator.Estimator API)代表你管理默认图形,比如可以为训练和评估创建不同的图。
Note:调用TensorFlow API中的大多数函数仅将操作和张量添加到默认图形,但不执行实际计算。而是组合这些函数,直到有一个表示整体计算的tf.Tensor或tf.Operation,例如执行梯度下降的一个步骤,然后将该对象传递给tf.Session来执行计算。 有关详细信息,请参见“执行tf.Session中的graph”一节。
命名操作
tf.Graph对象为其包含的tf.Operation对象定义一个命名空间。TensorFlow会自动为图形中的每个操作选择一个唯一的名称,但给出操作描述性名称可以使程序更易于阅读和调试。 TensorFlow API提供了两种覆盖名称操作:
每个API函数创建一个新的tf.Operation或返回一个新的tf.Tensor接受可选的名称参数。例如,tf.constant(42.0,name=“answer”)创建一个名为“answer”的新tf.Operation,并返回一个名为“answer:0”的tf.Tensor。如果默认图形已经包含一个名为“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.Tensor对象作为参数。 例如,tf.matmul需要两个tf.Tensor对象,并且tf.add_n获取n tf.Tensor对象的列表。 为方便起见,这些函数将接受一个类似张量的对象代替一个tf.Tensor,并使用tf.convert_to_tensor方法将其隐式转换为一个tf.Tensor。类似的包括以下元素:
tf.Tensor
tf.Variable
numpy.ndarray
list(和类似张量的对象的列表)
标量Python类型:bool,float,int,str
Note:默认情况下,TensorFlow将在每次使用相同的类似张量对象时创建一个新的tf.Tensor。 如果张量类物体较大(例如包含一组训练样本的numpy.ndarray),并且多次使用,则可能会耗尽内存。 为了避免这种情况,请手动在张量类对象上调用tf.convert_to_tensor一次,并使用返回的tf.Tensor。
在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。
tf.Session.init 接受三个可选参数:
target:如果此参数为空(默认值),则session将仅使用本地计算机中的设备。 但是,您还可以指定一个grpc:// URL来指定TensorFlow服务器的地址,该服务器将会话访问该服务器所控制的计算机上的所有设备。 有关如何创建TensorFlow服务器的详细信息,请参阅tf.train.Server。例如,在常见的graph之间复制配置中,tf.Session以与客户端相同的过程连接到tf.train.Server。分布式TensorFlow部署指南介绍了其他常见情况。
graph: 默认情况下,新的tf.Session将被绑定到---并且只能在---当前的默认图中运行操作。 如果您在程序中使用多个图(有关详细信息,请参阅使用多个图编程),您可以在构建会话时指定一个显式的tf.Graph。
config: 此参数允许您指定一个控制会话行为的tf.ConfigProto。 例如,一些配置选项包括:
allow_soft_placement: 将其设置为True以启用“soft”设备布局算法,忽略尝试在GPU设备上放置仅CPU操作的tf.device注释,并将其放置在CPU上。
cluster_def:使用分布式TensorFlow时,此选项允许您指定计算中要使用的计算机,并提供作业名称,任务索引和网络地址之间的映射。有关详细信息,请参阅tf.train.ClusterSpec.as_cluster_def。
graph_options.optimizer_options:提供了优化tensorflow执行之前执行该控制图。
gpu_options.allow_growth:将其设置为True以更改GPU内存分配器,以便逐渐增加分配的内存量,而不是在启动时分配大部分内存。
使用tf.Session运行operation
tf.Session.run方法是运行tf.Operation或评估tf.Tensor的主要机制。 您可以将一个或多个tf.Operation或tf.Tensor对象传递给tf.Session.run,并且TensorFlow将执行计算结果所需的操作。
tf.Session.run要求您指定一个取出列表,它确定返回值,并且可以是tf.Operation,tf.Tensor或类似张量的类型,如tf.Variable。这些fetch确定必须执行整个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:
y
# Feeding a value changes the result that is returned when you evaluate.
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.0t, 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还接受一个可选选项参数,使你能够指定有关调用的选项,以及可选的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)
GraphDef和MetaGraphDef
TensorFlow使用数据流图作为应用程序的便携式表示。tf.Graph包含两种相关信息:
graph structure: 图形的节点和边缘,指示单个操作如何组合在一起,但不规定如何使用它们。graph structure就像汇编代码:检查它可以传达一些有用的信息,但它不包含源代码传达的所有有用的上下文。
graph collection:TensorFlow提供了一种用于在tf.Graph中存储元数据集合的通用机制。tf.add_to_collection函数使您能够将list中的object与key(其中tf.GraphKeys定义了一些标准键)相关联,而tf.get_collection可以查找与一个键相关联的所有对象。 TensorFlow库的许多部分使用这个功能:例如,当你创建一个tf.Variable时,默认情况下将其添加到表示“全局变量”和“可训练变量”的集合中。 当您稍后创建一个tf.train.Saver或tf.train.Optimizer时,这些集合中的变量将用作默认参数。
tf.Graph可以保存为两种形式:
tf.GraphDef:这是图形结构的低级表示,包含其所有操作(如tf.NodeDef协议缓冲区)及其间的边界的描述。tf.GraphDef表示主要与低级API(例如tensorflow :: Session C ++ API)一起使用,通常需要额外的上下文(例如特定操作的名称)才能使用它。 tf.Graph.as_graph_def方法将tf.Graph转换为tf.GraphDef。
tf.train.MetaGraphDef:这是一个数据流图的更高级别的表示,其中包括一个tf.GraphDef和有助于理解图形的信息(如图形集合的内容)。tf.train.export_meta_graph函数将tf.Graph转换为tf.train.MetaGraphDef。 tf.train.Saver.save方法还可以写入一个tf.train.MetaGraphDef,它可以与保存的检查点一起使用,以恢复其保存点的训练过程的状态。
在大多数情况下,我们鼓励您使用tf.train.MetaGraphDef而不是tf.GraphDef。 在某些情况下,tf.GraphDef可能是有用的 - 例如,使用tf.import_graph_def或Graph Transform工具等函数执行低级图修改时,但tf.train.MetaGraphDef是一个更好的构建块高级应用程序。例如,SavedModel库使用tf.train.MetaGraphDef来打包tf.Graph和一组经过训练的模型参数,以便于服务。
如果你有一个tf.train.MetaGraphDef,tf.train.import_meta_graph函数将它加载到默认图形中。 调用此功能有两个主要功能:
1.它将从原始图形还原图的内容。 诸如tf.global_variables的APIs和API的默认参数(如tf.train.Optimizer.minimize)的工作方式将与原始图中的操作方式相同。
2.该函数返回一个tf.train.Saver,可用于从检查点恢复与图形关联的状态(训练参数等)。 tf.train.latest_checkpoint函数可以帮助从特定的检查点目录中找到最新的检查点。
如果您有一个tf.GraphDef,tf.import_graph_def函数可以将图形加载到现有的Python tf.Graph对象中。 要使用导入的图形,您必须知道tf.GraphDef中的操作或张量的名称。 tf.import_graph_def函数有两个主要功能可以帮助您使用导入的图形:
1.你可以通过传递可选的input_map参数,将导入的图形中的张量重新粘贴到默认图中的tf.Tensor对象。 例如,input_map使您能够导入在tf.GraphDef中定义的图片段,并将您正在构建的图中的张量静态连接到该片段中的tf.placeholder张量。
2.通过将其名称传递给return_elements列表,可以从导入的图形返回tf.Tensor或tf.Operation对象。
另外,你可以使用tf.device和tf.name_scope来控制导入节点的设备位置和名称。
可视化图
TensorFlow包括可以帮助您了解图形中的代码的工具。图形可视化器是TensorBoard的一个组件,可以在浏览器中直观呈现图形的结构。创建可视化的最简单的方法是在创建tf.summary.FileWriter时传递一个tf.Graph:
# 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()
Note:如果使用tf.estimator.Estimator,则图形(和任何summaries)将自动记录到在创建estimator时指定的model_dir中。
然后,您可以打开tensorboard上的日志,导航到“graph”选项卡,并查看图形结构的高级可视化。 注意,典型的TensorFlow图 - 特别是具有自动计算梯度的训练图 - 具有太多的节点可以立即可视化。 图形可视化器利用名称范围将相关操作分组为“super”节点。 您可以点击任何这些super节点上的橙色“+”按钮来扩展子图。
使用多个图编程
Note:训练模型时,组织代码的常见方法是使用一个图来训练您的模型,以及用单独的图形评估或执行推理一个训练模型。 在许多情况下,推理图将与训练图不同:例如,在每种情况下,像dropout和批batch normalization这样的技术都使用不同的操作。此外,默认情况下,诸如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.as_default上下文管理器来安装不同的tf.Graph作为默认图:
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()
g_2
with g_2.as_default():
# Operations created in this scope will be added to.
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_defaut_graph()
print(g.get_operations())
原文参考Tensorflow官网
https://www.tensorflow.org/programmers_guide/graphs