tfrecords 文件是否有最佳元素数量?

Is there an optimal number of elements for a tfrecords file?

这是对这些 SO 问题的跟进

What is the need to do sharding of TFRecords files?

以及本教程中的这段话

For this small dataset we will just create one TFRecords file for the training-set and another for the test-set. But if your dataset is very large then you can split it into several TFRecords files called shards. This will also improve the random shuffling, because the Dataset API only shuffles from a smaller buffer of e.g. 1024 elements loaded into RAM. So if you have e.g. 100 TFRecords files, then the randomization will be much better than for a single TFRecords file.

https://github.com/Hvass-Labs/TensorFlow-Tutorials/blob/master/18_TFRecords_Dataset_API.ipynb

所以有一个最佳的文件大小,但我想知道,是否有一个最佳的元素数量?既然是元素本身被分配到 GPU 核心?

您是否尝试优化:

1 初始数据随机化? 2 跨训练批次 and/or 时期的数据随机化? 3 training/validation 吞吐量(即 gpu 利用率)?

当数据最初保存到分片文件中时,应处理初始数据随机化。这可能具有挑战性,假设您无法将数据读入内存。一种方法是将所有唯一数据 ID 读入内存,将它们打乱顺序,进行 train/validate/test 拆分,然后以随机顺序将实际数据写入文件分片。现在你的数据最初是 shuffled/split/sharded.

初始数据随机化将使训练期间更容易保持随机化。但是,我仍然会说 'best practice' 重新洗牌文件名并重新洗牌数据内存缓冲区作为 train/validate 数据流的一部分。通常,您将使用多个 threads/processes 设置输入流。第一步是通过重新洗牌文件名来随机化文件输入流。这可以像这样完成:

train_files = tf.data.Dataset.list_files('{}/d*.tfr'.format(train_dir),
                                            shuffle=True)

现在,如果您的初始数据写入已经随机化,您 'could' 在进入下一个文件之前从一个文件中读取整个数据,但这仍然会影响整个训练过程中的重新随机化,所以通常,您会交错读取文件,从每个文件中读取一定数量的记录。这也提高了吞吐量,假设您正在使用多个文件读取进程(您应该这样做,以最大化 gpu 吞吐量)。

blocksize  = 1000     # samples read from one file before switching files
train_data  = train_files.interleave(interleaveFiles,
              block_length=blocksize,
              num_parallel_calls=tf.data.experimental.AUTOTUNE)

在这里,我们从每个文件中读取 1000 个样本,然后再继续下一个。同样,为了在每个时期(可能重要也可能不重要)重新洗牌训练数据,我们重新洗牌内存中的数据,根据机器上可用的内容和我们的数据项的大小设置内存缓冲区(注意- 在为 gpu 格式化数据之前)。

buffersize = 1000000  # samples read before shuffling in memory
train_data  = train_data.shuffle(buffersize,
                                 reshuffle_each_iteration=True)
train_data  = train_data.repeat()

repeat() 调用只是为了让训练期间的数据集为'wrap around'。这可能重要也可能不重要,具体取决于您如何设置训练过程。

要优化吞吐量,您可以做两件事:

1 更改数据输入流中的操作顺序。通常,如果您提前进行随机化操作,它们可以对 'low weight' 实体(如文件名)进行操作,而不是对张量进行操作。 2 使用预取让您的 cpu 在 gpu 计算期间处理流数据

train_data  = train_data.map(mapData,
                  num_parallel_calls=tf.data.experimental.AUTOTUNE)
train_data  = train_data.padded_batch(batchsize)
train_data  = train_data.prefetch(10)

因此,映射和批处理最后发生(这通常是最大化 gpu 吞吐量的首选,但它可能取决于其他因素,例如数据大小(预和 post-张量),以及您的计算成本地图功能是)。

最后,您可以调整预取大小以最大化 gpu 吞吐量,受系统内存和内存速度的限制。

那么,这一切如何影响每个分片文件中的 'optimal' 数据项数量?

显然,如果您的 data/file 大小大于您的块大小,块大小变得无关紧要,您不妨完整地阅读每个文件。通常,如果您要使用此范例,您需要 blocksize << data/file。我用 10 倍;所以如果我的块大小是 1000,我在文件中有大约 10,000 个数据项。这可能不是最优的,但到目前为止,我可以在我的特定硬件上使用这种方法保持 >90% 的 gpu 使用率。如果您想针对您的硬件进行调整,您可以从大约 10 倍的某个位置开始,然后根据您具体要优化的内容进行调整。

如果您有大量文件,您可能 运行 难以维持良好的文件读取流,但在现代系统上,您应该能够获得 100,000 个或更多文件并且仍然没问题。移动大量文件可能很困难,但通常比拥有非常少的非常大的文件更容易,因此对文件大小有一些(广泛的)限制可能会影响最终得到的数据量 items/file。一般来说,我认为拥有大约 100 个文件对于大型数据集来说是理想的。这样您就可以轻松地通过网络有效地流式传输文件(同样,这将取决于您的网络)。如果数据集很小,你会有 10 到 50 个文件,这对于流式传输来说很好,具体取决于文件大小(我通常尝试达到 100-300MB/文件,这对于在 LAN 或 WAN 中移动东西很有效).

所以,我认为文件大小和文件数量对您的流程的限制比数据数量 items/file 强得多,只要您有适当数量的数据 items/file ,给定您的文件读取块大小。同样,您可以对文件进行超分片(1 个数据 item/file?),并将整个文件读入内存,而无需使用文件分块。这可能行得通,并且洗牌文件名而不是数据项肯定是轻量级的。但您也可能最终拥有数百万个文件!

要真正优化,您需要在特定机器上设置端到端训练系统,然后对其进行调整以查看最适合您的特定数据、网络和硬件的方法。只要您的数据有效地随机化并且您的数据文件易于 store/use/share,您只想优化 gpu 吞吐量。如果重新排序数据输入流和预取不能让你到达那里,我会感到惊讶。