使用多个线程制作多个数据碎片可以最大限度地缩短培训时间吗?

时间:2017-11-30 19:03:17

标签: tensorflow

我的主要问题是:我有200 GB的训练tfrecord文件,有200万张图像,28GB用于验证tf.record文件,302900张图像。培训一个时代需要8个小时,培训需要33天。我想通过使用多个线程和分片来提高速度,但我对一些事情感到有些困惑。

tf.data.Dataset API中有shard函数,所以在文档中他们提到了关于分片函数的以下内容:

  

创建一个仅包含此数据集的1 / num_shards的数据集。

     

此数据集运算符在运行分布式培训时非常有用,因为它允许每个工作人员读取唯一的子集。

     

读取单个输入文件时,可以按如下方式跳过元素:

d = tf.data.TFRecordDataset(FLAGS.input_file)
d = d.shard(FLAGS.num_workers, FLAGS.worker_index)
d = d.repeat(FLAGS.num_epochs)
d = d.shuffle(FLAGS.shuffle_buffer_size)
d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads)
  

重要提示:

     

在使用任何随机化运算符(例如shuffle)之前,请务必进行分片。   通常,最好在数据集管道的早期使用分片运算符。 >例如,当从一组TFRecord文件中读取时,在转换之前将分片>数据集输入样本。这样可以避免读取每个工作人员的每个文件。 >以下是完整>管道内的有效分片策略的示例:

d = Dataset.list_files(FLAGS.pattern)
d = d.shard(FLAGS.num_workers, FLAGS.worker_index)
d = d.repeat(FLAGS.num_epochs)
d = d.shuffle(FLAGS.shuffle_buffer_size)
d = d.repeat()
d = d.interleave(tf.data.TFRecordDataset,
             cycle_length=FLAGS.num_readers, block_length=1)

d = d.map(parser_fn, num_parallel_calls=FLAGS.num_map_threads)

这些是我的问题:

1- tf.records文件的数量与分片数量之间是否有任何关系?是碎片数量(工人)取决于你拥有的CPU数量,或者你拥有的tf.records文件的数量?以及如何创建它,只需将分片数设置为特定数字? ,或者我们需要将文件拆分为多个文件,然后设置特定的分片数。请注意参考碎片数量的工人数量

2-创建多个tf.records文件有什么好处?有人说here与你需要以更好的方式改变tf.records有关,但是在tf.Dataset API中存在Shuufle方法,我们不需要这样做,其他人说{{3}它只是将您的数据拆分为较小的部分。我的问题我是否需要将我的tf.records文件拆分为多个文件

3-现在我们来到map函数中的num_threads(在新版本的tensorflwo中的num_paralle_calls)应该与你拥有它的分片数相同。当我搜索时,我发现有人说如果你有10个分片和2个线程,每个线程将需要5个分片。

关于d.interleave函数怎么样,我知道它是如何工作的,就像在here中提到的那样。但我再次错过了连接num_threads,循环长度,例如

5-如果我想使用多个GPU,我应该使用分片吗?如上所述example

作为总结我对(tf.records文件的数量,num_shards(工作人员),循环长度,num_thread(num_parallel_calls)之间的关系感到困惑。为了最大限度地缩短培训时间,创建的最佳情况是什么?两种情况(使用多个GPU,并使用单GPU)

1 个答案:

答案 0 :(得分:4)

我是tf.data开发人员。让我们看看我是否可以帮助回答您的问题。

1)听起来你有一个大文件。要使用多个worker处理它,将它拆分成多个较小的文件是有意义的,这样tf.data输入管道就可以处理不同worker上的不同文件(通过在文件名列表上应用shard函数)。

2)如果你没有将你的单个文件拆分成多个记录,每个工作人员必须读取整个文件,消耗n倍的IO带宽(其中n是workerS的数量)。

3)map转换的线程数与分片数无关。每个分片将由num_parallel_calls在每个工作人员上处理。通常,将num_parallel_calls与工作线程上的可用核心数成比例是合理的。

4)interleave转换的目的是将多个数据集(例如,从不同TFRecord文件读取)组合到单个数据集中。鉴于您的用例,我认为您不需要使用它。

5)如果您想要提供多个GPU,我建议您使用您引用的评论中列出的第一个选项,因为它是最简单的。基于shard的解决方案需要在每个工作线上创建多个管道(每个GPU上都有)。

为了最大限度地缩短培训时间(对于单个或多个GPU,您需要确保输入管道产生的数据比GPU处理数据的速度更快。讨论输入管道的性能调整here