Tensorflow数据集API是否比队列慢?

时间:2017-11-21 00:32:37

标签: performance tensorflow tensorflow-datasets

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

准备工作相当标准: - 从磁盘读取图像 - 随机/裁剪和翻转 - 洗牌,批量 - 送给模特

总的来说,我看到现在的批处理处理速度提高了15%,但每隔一段时间(或者更确切地说,每当我重新初始化数据框或预期重新洗牌时)批处理都会被长时间(30秒)阻止,这总计很长减慢每个纪元的处理时间。

这种行为似乎与内部哈希有关。如果我在ds.shuffle(buffer_size = N)中减少N,则延迟较短但比例更频繁。删除shuffle会导致延迟,就像buffer_size设置为数据集大小一样。

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

我正在使用TF 1.3。

2 个答案:

答案 0 :(得分:10)

如果使用tf.data.Dataset API并使用队列实施相同管道,则数据集版本的性能应优于基于队列的版本。

但是,为了获得最佳性能,需要遵循一些性能最佳实践。我们在performance guide for tf.data收集了这些内容。以下是主要问题:

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

  • shuffle运算符在开头有一个延迟,而它填充缓冲区。基于队列的管道混合了所有历元的串联,这意味着缓冲区仅填充一次。在数据集管道中,这相当于dataset.repeat(NUM_EPOCHS).shuffle(N)。相比之下,您也可以编写dataset.shuffle(N).repeat(NUM_EPOCHS),但这需要重新开始每个时代的混乱。后一种方法稍微好一点(例如,对于SGD的定义更为正确),但如果您的数据集很大,则差异可能不明显。

    我们正在添加一个融合版本的shuffle-and-repeat,不会产生延迟,每晚构建的TensorFlow将包含相当于dataset.shuffle(N).repeat(NUM_EPOCHS)的自定义tf.contrib.data.shuffle_and_repeat()转换但在每个时代开始时都没有遭受延误。

话虽如此,如果您使用tf.data时的管道明显比队列慢,请提交GitHub issue详细信息,我们就来看看吧! / p>

答案 1 :(得分:0)

建议的事情在过去并不能解决我的问题,但是我想为那些不想了解队列并仍然充分利用TF数据管道的人提供一些建议:< / p>

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)