各种TensorFlow数据加载习惯用法适用的场景是什么?

时间:2017-07-29 20:09:59

标签: python numpy tensorflow deep-learning api-design

我有一个TensorFlow深度学习工作流程,其中我有一个相当简单的数据读取和使用常规NumPy构建的输送管道;但是我看到TensorFlow提供了大量用于加载数据和构建数据管道的函数。我想知道这些目标是什么情景。似乎有两个:

  1. 学习涉及非常大的真实世界数据集,
  2. 使用high-level TensorFlow API建立的网络。
  3. 似乎使用"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数据加载惯用语以及它们适用的场景?

2 个答案:

答案 0 :(得分:2)

雅罗斯拉夫已经告诉过你关于feedingqueues并触及数据集的信息。只是我自己的一些想法:

  • 如果您只是想学习TF或想要快速尝试各种模型,feed_dict为您提供了一种快速的方法。有性能缺点,这就是为什么有队列
  • 队列允许您指定绕过python的TF操作 - > native_TF - > python循环和GIL。队列的一个大问题是它们很难使用(在能够正确使用我的数据之前,我总是很努力)。许多其他人都在苦苦挣扎,你可以看到一些examples of problems here

新推出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部分仍然是瓶颈(即示例herehere),所以为了解决这些问题,下一代引入了ops(StageOp / Dataset),这消除了对额外Python线程的需求。这是最新推出的数据加载习惯。

作为一个具体的例子,要在ImageNet上的64个GPU上重现官方60倍速加速,你必须使用最新一代输入加载,但对于不那么密集的任务,你可以使用第二代或第一代习语。