我使用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。
答案 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。