6

我用 Dataset API 方法替换了项目中的 CIFAR-10 预处理管道,导致性能下降约 10-20%。

预处理是相当标准的: - 从磁盘读取图像 - 随机/裁剪和翻转 - 随机播放,批处理 - 输入模型

总的来说,我看到批处理现在快了 15%,但是每隔一段时间(或者,更准确地说,每当我重新初始化数据帧或期望重新洗牌时)批处理被阻塞了很长时间(30 秒),总时间变慢- 每 epoch 处理。

这种行为似乎与内部散列有关。如果我在 ds.shuffle(buffer_size=N) 中减少 N 延迟会更短,但成比例地更频繁。将所有结果中的 shuffle 移除以延迟,就好像 buffer_size 设置为数据集大小一样。

在读取/缓存方面,有人可以解释 Dataset API 的内部逻辑吗?是否有任何理由期望 Dataset API 比手动创建的队列工作得更快?

我正在使用 TF 1.3。

4

2 回答 2

10

如果使用 API 和队列实现相同的管道tf.data.Dataset,Dataset 版本的性能应该优于基于队列的版本。

但是,为了获得最佳性能,需要观察一些性能最佳实践。我们已tf.data. 以下是主要问题:

  • 预取很重要:基于队列的管道默认预取,而数据集管道则不预取。添加dataset.prefetch(1)到管道的末尾将为您提供预取的大部分好处,但您可能需要进一步调整它。

  • shuffle 运算符在开始时有一个延迟,同时它会填充其缓冲区。基于队列的管道对所有 epoch 的串联进行混洗,这意味着缓冲区只被填充一次。在数据集管道中,这相当于dataset.repeat(NUM_EPOCHS).shuffle(N). 相比之下,您也可以编写dataset.shuffle(N).repeat(NUM_EPOCHS),但这需要在每个 epoch 中重新开始洗牌。后一种方法稍微可取(例如,更符合 SGD 的定义),但如果您的数据集很大,则差异可能不会很明显。

    我们正在添加一个不会导致延迟的 shuffle-and-repeat 的融合版本,并且每晚构建的 TensorFlow 将包括tf.contrib.data.shuffle_and_repeat()相当于dataset.shuffle(N).repeat(NUM_EPOCHS)但不会在每个 epoch 开始时遭受延迟的自定义转换。

话虽如此,如果您的管道在使用时tf.data比队列慢得多,请提交GitHub 问题并提供详细信息,我们会看看!

于 2017-12-22T19:10:51.850 回答
0

建议的事情在过去并没有解决我的问题,但我想为那些不想了解队列但仍要充分利用 TF 数据管道的人添加一些建议:

.

files = tf.data.Dataset.list_files(data_dir)
ds = tf.data.TFRecordDataset(files, num_parallel_reads=32)
ds = (ds.shuffle(10000)
    .repeat(EPOCHS)
    .map(parser_fn, num_parallel_calls=64)
    .batch(batch_size)
)
dataset = dataset.prefetch(2)

您必须注意3个主要组成部分:

  • num_parallel_read=32并行化磁盘 IO 操作
  • num_parallel_calls=64并行化对解析器函数的调用
  • prefetch(2)
于 2019-05-27T07:10:43.200 回答