4.4 FAQ
此文档对关于TensorFlow的一些常见问题提供了答案,如果这里没有你问题的答案,你可能会在社区资源中找到它。
内容
常见问题
建立 TensorFlow graph
为什么c = tf.matmul(a, b)
不立即执行矩阵相乘?
在 TensorFlow 的 Python API 中, a
, b
, and c
都是 Tensor
对象. 一个 Tensor
对象是一个操作(operation)结果的字符别名,它实际上并不储存操作(operation)输出结果的值。 TensorFlow 鼓励用户去建立复杂的表达式(如整个神经网络及其梯度)来形成 data flow graph 。 然后你可以将整个 data flow graph 的计算过程交给一个 TensorFlow 的 Session
, 此 Session
可以运行整个计算过程,比起操作(operations)一条一条的执行效率高的多。
设备是如何命名的?
对CPU设备而言,支持的设备名是"/device:CPU:0"
(或 "/cup:0"
),对第 i 个 GPU 设备是"/device:GPU:i"
(或 "/gpu:i"
)
如何在指定的设备上运行操作(operations)?
在 with tf.device(name):
context 中创建操作(operation),这样可以在指定的设备上运行操作(operation)。 关于 TensorFlow 怎样将操作(operations)分配给设备的细节,参看 TensorFlow使用 GPU ; 使用多 GPU 的示范实例参看 CIFAR-10 教程。
可用的 tensor 有哪些不同的类型?
TensorFlow 支持许多种不同的数据类型和 tensor shape ,更多细节请参看 ranks, shapes, and type reference
运行 TensorFlow 计算过程。
请详细解释 feeding 和 placeholders?
Feeding 是 TensorFlow Session API 的一种机制,它允许你在运行时用不同的值替换一个或多个 tensor 的值。 Session.run()
的参数 feed_dict
是一个字典, 它将 Tensor
对象映射为 numpy 的数组(和一些其他类型)。 在执行 step 时,这些数组就是 tensor 的值。
你常会碰到某些 tensor 总是有值的,比如 inputs。 tf.placeholder()
操作(operation)允许你定义一种必须提供值的 tensor ,你也可以随意限定它们的 shape。关于如何使用 placelolders 和 feeding 为神经网络提供训练数据的例子,请参看初学者的 MNIST 教程
Session.run()
和 Tensor.eval()
有什么区别?
如果 t
是一个 Tensor
对象, t.eval()
就是 sess.run(t)
(sess
是当前默认 session)的简写。 以下两段小程序是等效的:
# 使用 `Session.run()`.
sess = tf.Session()
c = tf.constant(5.0)
print sess.run(c)
# 使用 `Tensor.eval()`.
c = tf.constant(5.0)
with tf.Session():
print c.eval()
在第二个例子中, session 的作用就象 context manager , context manager 在 with
块的生存期,将 session 作为默认的 session。对简单应用的情形(如单元测试),context manager 的方法可以得到更简洁的代码; 如果你的代码要处理多个 graph 和 session ,更直白的方式可能是显式调用 Session.run()
。
Sessions 有生存期吗? 调用时产生的 tensors 呢?
Session 能够占有资源,例如 variables,queues, 和 readers; 这些资源会使用相当大量的内存。 当调用Session.close()
关闭 session 后,这些资源(和相关的内存)就被释放了。
作为调用 Session.run()
过程的一部分所创建的 tensors, 会在调用时或调用结束前释放。
我可以在多个计算机上运行分布式的训练吗?
最初的 TensorFlow 开源版本支持单一计算机内的多设备(CPUs 和 GPUs)。 我们也正在致力于一个分布式的版本:如果你有兴趣,请告知我们,这样我们可以做相应的调整。
运行时会并行计算图的执行的各个部分(parts of graph execution)吗?
TensorFlow 运行时会在许多不同的层面(dimensions)并行图的执行(graph execution):
- 在一个CPU中用多核或是一个GPU中用多线程来并行许多单独的操作(operation)。
- 在 TensorFlow graph 中各个独立的节点可以在多个设备上并行,这样就提供了加速的可能。CIFAR-10 用多 GPU 训练.
- Session API 允许并行执行多并发的 steps (如 调用 Session.run())。 如果单一的 step 不使用你计算机中所有的资源,这种方法可以使运行时有更高的吞吐量。
TensorFlow 支持哪些客户端编程语言?
TensorFlow 被设计成为支持多种客户端语言。当前支持最好的客户端语言是 Python。 C++ 客户端 API 提供了启动 graph 和运行 steps 的接口; 我们还有一个 用 C++ 建立 graph 的 API,此 API 是实验性的。
从社区的利益出发,我们想要支持更多的客户端语言。 TensorFlow 有一个 基于 C 的客户端 API,它使得用许多不同的语言创建客户端变得很容易。我们请大家在新语言绑定上做出努力。
TensorFlow 会利用我计算机上所有可用的设备(GPUs 和 CPUs)吗?
TensorFlow 支持多 GPU 和 CPU。 有关 TensorFlow 如何将操作(operations)分配到设备的细节请参看 TensorFlow 如何使用 GPUs 的文档,有关使用多 GPU 的示范实例请参看 CIFAR-10 教程
请注意, TensorFlow 只使用计算能力(compute capability)大于 3.5 的 GPU 设备。
当使用一个 reader 或 一个 queue 时,为什么 Session.run()
会挂起?
reader 类和 queue 类提供特殊的操作(operations),这些操作(operations)在有可用的输入(对有界队列则是空闲空间)前会 阻塞 。使用这些操作(operations)你可以创建复杂的输入流水线(input pipelines) ,不过,这会使 TensorFlow 的计算过程更复杂。有关如何使用这些操作(operations)的更多信息请参看 how-to 文档中的使用 QueueRunner
对象来控制 queues 和 readers。
Variables
参看 Variables 和 变量作用域 的 how-to 文档,还有关于变量的 API 文档
变量的生存期是?
在某一 session 中,当你一开始运行 tf.Variable.initializer
操作(operation)时,变量就会被创建。此 session 关闭后
它就被摧毁(destroyed)了。
并发读取或存入变量时会是什么情况?
变量可以进行并发的读和写操作(operation)。由于变量是并发(concurrently)更新的, 所以从一个变量中读出的值可能会改变。在不互斥的条件下,对一个变量的并发的许多赋值操作(operation)是默认允许运行的。在对一个变量赋值时,如果想要加锁,可以将 use_locking=True
传递给 Variable.assign()
。
Tensor shapes
在 Python 中我怎么判断一个 tensor 的 shape ?
在 TensorFlow 中,一个 tensor 具备静态和动态两种 shape 。静态的 shape 可以用 tf.Tensor.get_shape()
方法读出:这种 shape 是由此 tensor 在创建时使用的操作(operations)推导得出的,可能是 partially complete 的。如果静态 shape 没有完整定义(not fully defined)的话,则一个 tensor 的动态 shape 可通过求 tf.shape(t)
的值得到。
x.set_shape()
和 x = tf.reshape(x)
有什么区别?
tf.Tensor.set_shape()
方法(method)会更新(updates)一个 Tensor
对象的静态 shape ,当静态 shape 信息不能够直接推导得出的时候,此方法常用来提供额外的 shape 信息。它不改变此 tensor 动态 shape 的信息。
tf.reshape()
操作(operation)会以不同的动态 shape 创建一个新的 tensor。
我怎么创建这样一个 graph ,它在批次大小可变(variable batch sizes)的情形下也可以正常运作?
如果能够创建一个 graph ,在批次大小可变(variable batch sizes)的情形下也可以正常运作将会是十分有用的,例如可以使用相同的代码完成(小)批量训练((mini-)batch training)和单例推导(single-instance inference)。这样生成的 graph 可以保存起来当作协议缓存(protocol buffer),也可以导入至其他的程序。
创建一个可变大小的 graph 时,要记住最重要的事情是不要将批次大小(batch size)编码成为 Python 常数,而是用一个字符性(symbolic)的 Tensor
来表示。下面的提示可能会有用:
用
batch_size = tf.shape(input)[0]
从一个叫input
的Tensor
提取批次的维度(batch dimention),再将其存入一个名为batch_size
的Tensor
。用
tf.reduce_mean()
而不是tf.reduce_sum(...) / batch_size
。如果你使用 placeholders for feeding input,你就可以用
tf.placeholder(..., shape=[None, ...])
通过创建 placeholder 来具体指定一个可变的批次维度(variable batch dimention)。shape 的None
元素与可变大小的维度(a variable-sized dimension)相对应。
TensorBoard
我怎样视觉化一个 TensorFlow graph ?
参看 graph 的视觉化教程.
向 TensorBoard 发送数据的最简单的方法是什么?
给你的 TensorFlow graph 增加 summary 操作(ops),接着用 SummaryWriter
将这些 summaries 写入一个 log directory。然后用以下命令启动 TensorBoard 。
`python tensorflow/tensorboard/tensorboard.py --logdir=path/to/log-directory`
更多细节请参看 Summaries 和 TensorBoard 教程。
扩展 TensorFlow
参看有关向 TensorFlow 添加新操作(oprations) 的 how-to 文档。
我的数据是自定义格式,要怎样用 TensorFlow 来读取它?
有两种主要的操作(operation)来处理自定义格式的数据。
较简单的方法:用 Python 编写一段分词的代码(parsing code),将数据转换成为 numpy array,然后用此数据把一个 [tf.placeholder()
] (../api_docs/python/io_ops.md#placeholder) 传送给一个 tensor 。更多的细节参见 使用 placeholders 进行输入 的相关文档。这个方法比较容易实现,不过分词的部分会成为性能的瓶颈。
更高效的方法是添加一个用 C++ 编写的操作(op),用这个操作(operation)来对你的数据格式进行分词(parse)。 新数据格式处理指南中有更多相关步骤的信息。
我如何定义操作(operation)使得它能够接受可变数量的输入?
TensorFlow 的操作(operation)注册机制允许你定义几种输入:单独的 tensor,一列相同类型的 tensors (例如把一个可变长列表中的 tensors 相加), 一列不同类型的 tensors (例如将一个 tuple 中的 tensors 入队(enqueue))。有关怎样定义这些不同的输入类型的更多细节,请参看添加具有一列输入或输出的操作(op)的相关文档。
其他问题
TensorFlow 能使用 Python 3 吗?
我们只用 Python 2.7 进行了测试。我们了解对 Python 3 的兼容性来说,还需要有一些修改,欢迎大家朝这个方向多努力。
TensorFlow 的代码风格有什么规则?
TensorFlow Python API 遵循 PEP8 惯例。 * 特别的,我们使用 CamelCase
格式作为类名, snake_case
格式作为方程名, 方法名, 和属性名。我们也遵循 Google Python style guide。
TensorFlow C++ 代码遵循 Google C++ style guide。
(* 有一条例外: 我们使用 2 空格缩进而不是 4 空格缩进)
原文:Frequently Asked Questions 翻译:Terence Cooper 校对:Wiki