我有一个TensorFlow深度学习工作流程,其中我有一个相当简单的数据读取和使用常规NumPy构建的输送管道;但是我看到TensorFlow提供了大量用于加载数据和构建数据管道的函数。我想知道这些目标是什么情景。似乎有两个:
似乎使用"reading" as opposed to "feeding"的好处(例如tf.train.shuffle_batch
之类的功能,甚至像tf.one_hot
之类的简单助手)都适用于前者,而{{{}}的大部分文档都适用于np.array
。 3}},似乎只针对后者。
在我的情况下,我使用标准Python可以轻松读取的文件,并且可以一次性有效地加载到内存中,只需使用TypeError
s就可以正常工作,而另一个方法似乎过于复杂(阅读管道;实际上非常慢,在我已经厌倦的程度上)或不适当的("高级" API,因为我主要使用& #34;低级" API)。
我的结论是正确的,因为我已经使用了TensorFlow(不是低级学习API)并且NumPy阵列的供应满足了我的需求,没有充分的理由去讨论任何一种替代方法吗?可以公平地说这些方法的预定目标与我的不同吗?
或者是否有另一种分类法可以更好地考虑各种TensorFlow数据加载惯用语以及它们适用的场景?
答案 0 :(得分:2)
雅罗斯拉夫已经告诉过你关于feeding,queues并触及数据集的信息。只是我自己的一些想法:
feed_dict
为您提供了一种快速的方法。有性能缺点,这就是为什么有队列新推出Datasets(由于某种原因,官方网站没有链接,可能会添加TF 1.3)解决了许多问题。它们非常易于使用(请查看页面末尾的示例),代码非常简单和简短。这是一个例子:
def parser(record):
# parse the record with tf.parse_single_example
iterator = tf.contrib.data.TFRecordDataset(
glob.glob("data/tfrecords/training_shard_*.tfrecord")
).map(parser).batch(batch_size).shuffle(shuffle_num).repeat(repeat_num).make_initializable_iterator()
next_element = iterator.get_next()
...
with tf.Session() as sess:
sess.run(iterator.initializer)
for i in xrange(100000):
sess.run(next_element)
这几行能够用队列替换X4行。使其工作比队列更容易(几乎和feed_dict一样简单)。所以现在我的意见是,队列已经没有位置了。使用feed_dict或数据集。
答案 1 :(得分:1)
将数据作为numpy数组提供是官方API的一部分,因此依赖它是合适的。官方卷积MNIST example将数据作为numpy数组提供,并且移动到队列没有速度优势。这是第一个添加到TensorFlow的数据加载习惯用法。
Python运行时具有GIL和其他功能,使其在多核环境中表现不佳,并且成为需要摄取大量数据的瓶颈。这可以通过将Python位(即打开文件)移动到本机TensorFlow操作中来解决,因此这些操作可以由并行TensorFlow运行时调度,而不是由Python运行时调度。
此管道方法将所有操作移至TensorFlow操作,通过“队列”阶段解耦,并使用Python线程发出session.run
调用以填充队列。这是添加到TensorFlow的第二个数据加载习惯。
这删除了很多Python位,但对于高性能应用程序,其余的Python部分仍然是瓶颈(即示例here和here),所以为了解决这些问题,下一代引入了ops(StageOp / Dataset),这消除了对额外Python线程的需求。这是最新推出的数据加载习惯。
作为一个具体的例子,要在ImageNet上的64个GPU上重现官方60倍速加速,你必须使用最新一代输入加载,但对于不那么密集的任务,你可以使用第二代或第一代习语。