Open WuDiDaBinGe opened 3 years ago
嗯,您的理解是对的。不过不是把dataset分成N份,一般来说是load了同一个dataset,然后通过使用sampler来控制让不同的进程用不同的数据。
嗯,您的理解是对的。不过不是把dataset分成N份,一般来说是load了同一个dataset,然后通过使用sampler来控制让不同的进程用不同的数据。
是的,应该是load了一样数据集并没有切分,取样时返回取样的index,进行index数组切片时,起始位置是进程号,隔N个取,所以每个进程的index列表就不同了。
def __iter__(self):
# deterministically shuffle based on epoch
g = torch.Generator()
g.manual_seed(self.epoch)
if self.shuffle:
indices = torch.randperm(len(self.dataset), generator=g).tolist()
else:
indices = list(range(len(self.dataset)))
# add extra samples to make it evenly divisible
indices += indices[:(self.total_size - len(indices))]
assert len(indices) == self.total_size
# subsample
indices = indices[self.rank:self.total_size:self.num_replicas]
assert len(indices) == self.num_samples
return iter(indices)
还有个疑问请教您?如果重载Dataset是将数据集全部加载到内存中的方式,占用5g。如果用DDP进行单机四卡的训练,四个进程都要加载数据集,那么内存占用会是不是飙升到20g呢?
是的,会变成20G的。这里可以自己编程让每个进程只load自己需要的数据。
是的,会变成20G的。这里可以自己编程让每个进程只load自己需要的数据。
如果将数据集分成四份的话,在每个进程中加载对应的数据集。这样的话是不是直接用SequenceSampler采样而不用DistributedSampler采样了?
嗯,对的。不过fastNLP的DistTrainer之前没有考虑到这种设定,所以当时是默认会自动使用 https://github.com/fastnlp/fastNLP/blob/b127963f213226dc796720193965d86dface07d5/fastNLP/core/dist_trainer.py#L175 分布式的sampler。这里有两个方案可以修改这个行为,第一个是自己复制DistTrainer修改一下这里的逻辑的。第二个方案是写一个Callback,类似于下面这样(大概是这样,可能需要调整一些细节)
class ChangeSamplerCallback(Callback):
def __init__(self):
super().__init__()
def on_train_start():
self.trainer.data_iterator = DataSetIter(dataset=self.trainer.tr_data, batch_size=self.trainer.batch_size_per_gpu, sampler=None,
num_workers=self.trainer.num_data_workers, drop_last=self.trainer.drop_last)
然后把这个callback给每个进程都使用,这样就在训练开始前把数据迭代器换掉了。
嗯,对的。不过fastNLP的DistTrainer之前没有考虑到这种设定,所以当时是默认会自动使用 https://github.com/fastnlp/fastNLP/blob/b127963f213226dc796720193965d86dface07d5/fastNLP/core/dist_trainer.py#L175
分布式的sampler。这里有两个方案可以修改这个行为,第一个是自己复制DistTrainer修改一下这里的逻辑的。第二个方案是写一个Callback,类似于下面这样(大概是这样,可能需要调整一些细节)
class ChangeSamplerCallback(Callback): def __init__(self): super().__init__() def on_train_start(): self.trainer.data_iterator = DataSetIter(dataset=self.trainer.tr_data, batch_size=self.trainer.batch_size_per_gpu, sampler=None, num_workers=self.trainer.num_data_workers, drop_last=self.trainer.drop_last)
然后把这个callback给每个进程都使用,这样就在训练开始前把数据迭代器换掉了。
好的,感谢您的回复
在使用 nn.DistributedDataParallel 时,模型会被复制到所有使用的GPU,通常每个GPU上存有一个模型,并被一个单独的进程控制。这样有N块GPU,就会产生N个进程。当训练一个batch时,这一batch会被分为N份,每个进程会使用batch的一部分进行训练,然后在必要时进行同步,并通过网络传输需要同步的数据。
教程中这段话中“当训练一个batch时,这一batch会被分为N份,每个进程会使用batch的一部分进行训练,然后在必要时进行同步,并通过网络传输需要同步的数据。”我觉得不是这样。谈谈自己的理解:我觉得 pytorch的DDP多卡分发数据的时候应该是将Dataset分成N份,然后每个进程从自己分到的数据中抽取batch size进行训练。
不知道这样理解是不是对的。