最近在折腾一个图像分类项目,单卡跑没问题,但想试试多卡加速。参考官方文档写了DistributedDataParallel,结果一跑就报“RuntimeError: NCCL error: invalid usage”。排查了半天,发现好像是我设了torch.cuda.set_device(local_rank)后,主进程和子进程的设备号对不上?我用的启动命令是torchrun --nproc_per_node=2 train.py,代码里也加了init_process_group(backend='nccl')。是不是我多卡初始化顺序有问题,或者环境变量没设全?有没有大佬能帮忙看看常见坑在哪?先谢谢了!
用PyTorch做多卡训练,DDP一直报错找不到设备,求指点
全部回复
共 147 条八成是init_process_group里忘传rank和world_size了,torchrun会自己注入环境变量,得用local_rank做设备映射。
把set_device放到init_process_group后面试试,顺序反了NCCL经常抽风。
遇到过一模一样的坑,八成不是环境变量的问题,是torch.cuda.set_device和DDP内部rank的映射重复了。你试试把set_device去掉,直接用local_rank传给device参数,比如device = f'cuda:{local_rank}',这样更干净。另外检查一下init_process_group里有没有传rank和world_size,如果用torchrun其实会自动注入环境变量,但显式写上能避免一些隐性问题。还有个小细节,确保代码入口用了if __name__ == '__main__':包住训练逻辑,不然多进程会递归启动。我之前就是这破问题卡了两天,改了之后立马跑通。
我之前也遇到过一模一样的报错,折腾了两天才发现是环境变量的问题。你用了torchrun的话,其实它会自动帮你设置LOCAL_RANK和RANK,不需要手动调torch.cuda.set_device,这个调用反而容易把设备搞乱。我当时的做法是删掉set_device,直接依赖torchrun分配,然后在init_process_group之后再用torch.cuda.current_device()确认一下。另外你检查过没有,NCCL那个报错有时候是因为网卡或者共享内存不够,尤其是多机训练的时候,单机双卡的话可以试试加一句os.environ['NCCL_DEBUG']='INFO',这样能看到更详细的卡在哪一步。还有个小坑是init_process_group里world_size和rank如果不写,torchrun会从环境变量读,但如果你手动传了错误的world_size=2,而实际环境里只有一张卡可见,那也会炸。我建议你先用torch.cuda.device_count()打印一下每个进程看到的卡数,确认是不是两张都能看到,有时候是CUDA_VISIBLE_DEVICES没设对,导致两个进程都绑到了同一张卡上。如果以上都排查了还不行,试试把backend换成gloo跑一次,虽然慢但能确认是不是NCCL特有的问题,至少能缩小范围。
DDP报错八成是环境变量缺了RANK和WORLD_SIZE,用torchrun时别手动设device,试试直接删掉set_device那行。
八成是local_rank和CUDA_VISIBLE_DEVICES没对齐,试试先设环境变量再调set_device,顺序换一下应该就好了。
遇到过一模一样的坑,当时差点把键盘砸了。问题大概率不是设备号对不上,而是你漏了local_rank这个环境变量的正确读取方式——torchrun会自动帮你把LOCAL_RANK注入到每个进程里,但如果你代码里直接写torch.cuda.set_device(local_rank),得确保这个local_rank是从os.environ['LOCAL_RANK']取的,而不是从args里硬编码传进来的,否则子进程可能拿到默认的0,俩进程抢一张卡,NCCL直接懵。
另外你那个init_process_group里最好显式指定world_size和rank,虽然torchrun会通过环境变量自动识别,但如果你在代码里其他地方重设了CUDA_VISIBLE_DEVICES,顺序一乱就容易出这种诡异报错。我之前就是先设了set_device再初始化进程组,改成先初始化再设设备就通了。
还有个容易忽略的点,torchrun默认用的是nccl后端,但你要确保所有进程的MASTER_ADDR和MASTER_PORT环境变量是一致的,单机多卡通常没问题,可一旦你脚本里手动改了这些变量,子进程可能拿到不同的端口导致握手失败。
建议你先在init_process_group后面打印一下每个进程的rank和cuda:current_device,确认逻辑上每个进程对应到物理卡号是唯一的。如果还不行,试试把nccl换成gloo先跑通流程,排除是不是驱动或者NCCL版本兼容性问题。另外检查一下PyTorch和CUDA版本,我之前就是升级了PyTorch后NCCL老版本不匹配,回退一版就好了。
NCCL invalid usage 在多卡场景挺常见的,先确认下 torchrun 有没有正确把 LOCAL_RANK 传进去,有时候脚本里硬编码 device 就会和实际分配的对不上。另外 init_process_group 之前最好先 torch.cuda.set_device,顺序反了也容易出这问题。还有个坑是 NCCL 版本和 CUDA 驱动不匹配,报错信息看着像设备问题其实底层是通信库炸了。你可以加个 print 把 rank 和 device 都打出来,跑一次就大概知道是哪步歪了。