. distributedDataparallel
Distributed communication package - torch.distributed
pytorch.org/docs/stable/distributed.html#launch-utility
This is the highly recommended way to useDistributedDataParallel, with multiple processes, each of which operates on a single GPU. This is currently the fastest approach to do data parallel training using PyTorch and applies to both single-node(multi-GPU) and multi-node data parallel training. It is proven to be significantly faster thantorch.nn.DataParallelfor single-node multi-GPU data parallel training.
第二种方法就是今天要讲的主题啦,这个函数的主要目的是为了多机多卡加速的,但是单机多卡也是没问题的。相比于之前的Dataparallel,新的函数更加优雅,速度更加快(这一点官方文档里有提到),而且不会出现负载不均衡的问题,唯一的小缺点可能就是配置稍微有点小麻烦。
下面主要介绍一下我的调用过程,我粗略的把他分成三步:
1.初始化
#初始化使用nccl后端(这个),当然还有别的后端,可以查看官方文档,介绍的比较清晰
torch.distributed.init_process_group(backend=“nccl”)
2.使用DistributedSampler
起先我是不太懂为什么要修改dataloader的,只是默默跟着改就完事了。后来看了别的文章才知道,DDP并不会自动shard数据
如果自己写数据流,得根据torch.distributed.get_rank()去shard数据,获取自己应用的一份
如果用Dataset API,则需要在定义Dataloader的时候用DistributedSampler 去shard:
train_dataset = self.dataset(
self.opt.data_path, train_filenames, self.opt.height, self.opt.width,
self.opt.frame_ids, 4, is_train=True, img_ext=img_ext)
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)
train_loader = DataLoader(
train_dataset, self.opt.batch_size, False,
num_workers=self.opt.num_workers, pin_memory=True, drop_last=True,sampler=train_sampler)
另外多说一点,在使用DataLoader时,别忘了设置pip_memory=true,为什么呢?且看下面的解释,
多GPU训练的时候注意机器的内存是否足够(一般为使用显卡显存x2),如果不够,建议关闭pin_memory(锁页内存)选项。
采用DistributedDataParallel多GPUs训练的方式比DataParallel更快一些,如果你的Pytorch编译时有nccl的支持,那么最好使用DistributedDataParallel方式。
关于什么是锁页内存:
pin_memory就是锁页内存,创建DataLoader时,设置pin_memory=True,则意味着生成的Tensor数据最开始是属于内存中的锁页内存,这样将内存的Tensor转义到GPU的显存就会更快一些。
主机中的内存,有两种存在方式,一是锁页,二是不锁页,锁页内存存放的内容在任何情况下都不会与主机的虚拟内存进行交换(注:虚拟内存就是硬盘),而不锁页内存在主机内存不足时,数据会存放在虚拟内存中。显卡中的显存全部是锁页内存,当计算机的内存充足的时候,可以设置pin_memory=True。当系统卡住,或者交换内存使用过多的时候,设置pin_memory=False。因为pin_memory与电脑硬件性能有关,pytorch开发者不能确保每一个炼丹玩家都有高端设备,因此pin_memory默认为False。
总结就一个字,快!!!
3.分布式训练
model=torch.nn.parallel.DistributedDataParallel(model)
到这里你以为就结束了吗??其实并没有,还剩下一点工作需要做,就是在命令行里加上这样一句话,
python -m torch.distributed.launch --nproc_per_node=NUM_GPUS_YOU_HAVE yourscript.py
但是这样做完之后可能还会报错,然后我就找到了torch.distributed.launch这个启动文件,发现我错过了一条很重要的提示,如果需要用这个函数的话,推荐大家先看一下 distributed.launch里面的内容,然后去看官方的文档解释。
In your training program, you must parse the command-line argument:--local_rank=LOCAL_PROCESS_RANK
, which will be provided by this module.If your training program uses GPUs, you should ensure that your code only runs on the GPU device of LOCAL_PROCESS_RANK. This can be done by:Parsing the local_rank argument
就是在外部的命令中制定–local_rank(int),然后就可以顺利的跑下去了。