如何把单卡训练改为多卡训练

2023/11/01 Pytorch 共 2143 字,约 7 分钟

单机多卡DDP训练的一般流程。一些代码可能仅支持单卡train,这时就需要自己手动修改代码,提高训练效率。

参考: https://medium.com/ching-i/pytorch-%E5%88%86%E6%95%A3%E5%BC%8F%E8%A8%93%E7%B7%B4-distributeddataparallel-%E5%AF%A6%E4%BD%9C%E7%AF%87-35c762cb7e08

大致流程

导入所需的库:

import torch  
import torch.distributed as dist  
from torch.utils.data.distributed import DistributedSampler

设置local_rank argparse参数

parser = argparse.ArgumentParser()  
parser.add_argument("--local_rank", default=0, type=int)  
args = parser.parse_args()

初始化DDP,设置进程通信的后端为nccl,同步所有进程,并获取当前进程组内所有进程数

dist.init_process_group(backend='nccl')
# 同步所有进程
dist.barrier()
# 获取当前进程组内所有进程数
world_size = dist.get_world_size()

将数据集分给每一个进程,避免进程间数据重复

train_sampler = DistributedSampler(train_dataset)  
valid_sampler = DistributedSampler(valid_dataset)

将sampler传入dataloader

train_loader = DataLoader(train_dataset, sampler=train_sampler, batch_size=256, pin_memory=False, prefetch_factor=2, num_workers=4)

valid_loader = DataLoader(valid_dataset, sampler=valid_sampler, batch_size=256, pin_memory=False, prefetch_factor=2, num_workers=4)

假设模型已经load,可以直接使用.to(device)将模型分配至CUDA

device = torch.device("cuda", args.local_rank)  
model = model.to(device)

使用SyncBN优化各自进程中数据集的BN计算

model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)

使用DistributedDataParallel将模型包装起来

model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank], output_device=args.local_rank)

在每次迭代前,通过set_epoch设置random seed,使得每次运行时shuffle每个epoch的数据,并让每个GPU拿到的数据不同

train_sampler.set_epoch(epoch)  
valid_sampler.set_epoch(epoch)

启动分布式训练

# 单机多卡
CUDA_VISIBLE_DEVICES=0,1 python -m torch.distributed.launch --nproc_per_node=2 ddp_example.py

# 单机多卡,但对一个代码执行不同实验,需要指定端口
$ CUDA_VISIBLE_DEVICES=2,3 python -m torch.distributed.launch --nproc_per_node=2 --master_port 9999 ddp_example.py

避免重复输出

参考maskrcnn项目,利用is_main_process()函数判断是否属于主进程。如果是主进程,再对信息进行输出。

对于tqdm进度条, 可以加入disable参数进行控制,使得仅在主进程时输出进度条,例如

with tqdm(enumerate(dataloader), total=len(dataloader), ncols=120, disable=not is_main_process()) as t:

保证tensor运算在同一设备上

有的代码在单卡改多卡时,会报错: **RuntimeError: Expected all tensors to be on the same device, but found at least two devices,**

这是因为原来的单卡代码中,在为tensor指定gpu时,使用的是.cuda(),但为model分配gpu时,使用的是model.to(device),从而导致模型输出的tensor和之前的tensor不在同一张显卡上,二者运算时报错。

最好将报错处的所有tensor的.cuda()改成.to(device),统一运算设备。

文档信息

Search

    Table of Contents