我使用Tensorflow,但我为用户编写文档,这些文档通常会随着深度学习框架的不同而有所不同。
当使用不适合本地文件系统(TB+)的数据集时,我从远程数据存储中采样数据,并在本地将样本写入Tensorflow标准tfrecords
格式。
在训练的第一个阶段,我只采样了几个值,因此局部数据的时代很小,我对它进行了训练。在第二阶段,我重新检查由我的采样子进程(现在更多)生成的数据文件,并为下一个时代对扩展的本地数据文件集进行培训。重复每一个时代的过程。通过这种方式,我建立了一个本地的样本缓存,并可以在填充本地存储空间时驱逐旧的样本。本地样本缓存在模型需要最大方差时(面向训练的后半部分)增长。
在Python/Tensorflow中,我不对Python训练循环过程中的数据进行反序列化至关重要,因为Python不能支持数据传输速率(300-600 MB/秒,数据是原始的、科学的、不可压缩的),因此,当Python不能快速服务培训循环时,GPU的性能就会受到影响。
从子进程()将示例写入tfrecords
文件允许tensorflow的本机TFRecordsDataset
在Python之外进行反序列化,因此我们避免了Python问题,我可以使用高IO数据速率填充GPU。
我想知道我将如何处理这个问题在毕道尔。我正在撰写关于正在使用的抽样策略的文章,并希望向Tensorflow和PyTorch的用户提供具体的建议,但我对PyTorch预处理生态系统的了解还不够深入。
附带注意:唯一支持这些数据传输速率的纯Python解决方案可能是Python3.8中的系统V共享内存和多处理,但我还没有尝试过,因为对它的支持还不够(很快就会)。现有的多处理解决方案是不够的,因为它们需要在训练循环过程中反序列化,从而在反序列化期间以高IO速率锁定GIL。
发布于 2020-02-17 07:38:24
实际上,您可以使用torch.utils.data.DataLoader
轻松地反序列化子进程中的数据。通过将num_workers
参数设置为1或更大的值,您可以使用自己的python解释器和GILs生成子进程。
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
另外,请注意,在大多数情况下,受GIL影响的是CPU绑定操作,而不是I/O绑定操作,也就是说,threading
将用于任何纯I/O操作,甚至不需要subprocess
。有关更多信息,请参阅本问题和维基百科文章。
https://stackoverflow.com/questions/60119934
复制