如何从Pytorch的高IO数据集中读取,该数据集从一个时代到另一个时代

时间:2020-02-07 19:31:54

标签: python pytorch

我使用Tensorflow,但我正在为用户编写文档,这些文档通常会在深度学习框架中有所不同

在使用不适合本地文件系统(TB +)的数据集时,我从远程数据存储中采样数据,然后在本地将采样写入Tensorflow标准tfrecords格式。

在训练的第一个时期,我将仅采样一些值,因此,我在其上进行训练的是局部数据的 epoch 很小。在 epoch 2 上,我重新检查采样子流程(现在有更多)生成了哪些数据文件,并针对下一个epoch扩展了本地数据文件集。每个时期重复该过程。这样,我可以建立样本的本地缓存,并在填满本地存储时可以驱逐较旧的样本。局部样本缓存大约在模型最需要方差时(朝训练的后期)增长。

在Python / Tensorflow中,至关重要的是,我不要在Python训练循环过程中反序列化数据,因为Python GIL无法支持数据传输速率(300-600 MB /秒,数据是原始的科学不可压缩的),并且因此,当Python GIL无法快速服务于训练循环时,GPU性能将受到影响。

将样本从子流程(Python多重处理)写入tfrecords文件中,使tensorflow的本机TFRecordsDataset可以在Python之外进行反序列化,因此我们避开了Python GIL问题,我可以使用高IO数据速率。

我想知道我将如何在Pytorch中解决此问题。我正在撰写有关正在使用的采样策略的文章,并想为Tensorflow和PyTorch的用户提供具体建议,但我不了解PyTorch预处理生态系统是否足够详细地编写。

附带说明:唯一支持这些数据传输速率的基于Python的解决方案可能是带有System V共享内存和多处理功能的Python 3.8,但我还没有尝试过支持它还不够(很快就会)。现有的多处理解决方案还不够,因为它们需要在训练循环过程中进行反序列化,从而在反序列化期间以高IO速率锁定GIL。

1 个答案:

答案 0 :(得分:9)

实际上,您可以使用torch.utils.data.DataLoader轻松地反序列化子流程中的数据。通过将num_workers参数设置为1或更大的值,可以使用它们自己的python解释器和GIL生成子进程。

loader = torch.utils.data.DataLoader(your_dataset, num_workers=n, **kwargs)
for epoch in range(epochs):
    for batch_idx, data in enumerate(loader):
         # loader in the main process does not claim GIL at this point

Dataloader需要一个torch.utils.data.Dataset才能获取数据。在您的情况下,实现适当的子类可能不是一件容易的事。如果您需要为每个纪元重新创建一个Dataset实例,则可以执行以下操作。

for epcoh in range(epochs):
    dset = get_new_dataset()
    loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)
    for batch_idx, data in enumerate(loader):
        # Do training

甚至更好

dset = get_new_dataset()
loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)

for epcoh in range(epochs):
    last_batch_idx =  (len(dset)-1) // loader.batch_size
    for batch_idx, data in enumerate(loader):
        # Prepare next loader in advance to avoid blocking
        if batch_idx == last_batch_idx:
            dset = get_new_dataset()
            loader = torch.utils.data.DataLoader(dset, num_workers=n, **kwargs)
        # Do training

请注意,在大多数情况下,受CPU约束的操作受GIL的影响,而不是受I / O约束的操作,即threading将对任何纯粹的I / O繁重的操作都起作用,甚至不需要subprocess。有关更多信息,请参阅此question和此维基百科article