最近在折腾一个图像分类项目,单卡跑没问题,但想试试多卡加速。参考官方文档写了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虽然会自动设环境变量,但保险起见显式写一下试试。
八成是rank和device没绑对,试试torch.cuda.set_device(local_rank)放init_process_group前面。
我之前也踩过这个坑,torch.cuda.set_device其实可以不用手动设,torchrun会自动帮你把local_rank对应的device设好,你直接device = f'cuda:{local_rank}'再model.to(device)就行。另外检查下init_process_group里有没有传rank和world_size,虽然torchrun会注入环境变量,但有些版本需要你显式读os.environ['RANK']和WORLD_SIZE传进去,否则NCCL可能找不到正确的设备映射。
我前几天也踩过这个坑,八成不是设备号的问题,而是torch.cuda.set_device跟torchrun自带的环境变量冲突了。你试试把set_device那行去掉,直接用os.environ['LOCAL_RANK']来指定device,因为torchrun已经帮你把CUDA_VISIBLE_DEVICES设好了。另外确认下是不是在init_process_group之前就调用了任何cuda操作,有时候NCCL对初始化顺序特别敏感。我改完这两处就正常了,你可以先跑个最简单的print rank和device看看对不对得上。
这报错八成就是设备号对不上,torch.cuda.set_device其实可以不用手动调,torchrun会自动帮你设好LOCAL_RANK对应的设备。你把那行删了试试,或者改成torch.cuda.set_device(int(os.environ['LOCAL_RANK'])),确保每个进程只用自己那个卡。另外init_process_group里最好显式传一下world_size和rank,别全依赖默认值,有时候环境变量没传全就会出这种幺蛾子。我之前也踩过这坑,改完基本就好了。
我之前也踩过这个坑,大概率是环境变量MASTER_ADDR和MASTER_PORT没手动设,torchrun虽然会自动配,但有时候和NCCL的初始化顺序会打架。你可以试试在init_process_group之前先打印一下rank和device,确认下每个进程拿到的local_rank对不对。另外检查下torch.cuda.set_device是不是放在了init_process_group后面,顺序反了确实容易出这种玄学报错。我之前改成先初始化进程组再设device就好了,你可以试下。
我之前也踩过类似的坑,折腾了一整天才发现是rank和local_rank混用了。你torch.cuda.set_device(local_rank)没问题,但关键是init_process_group里rank和world_size必须从环境变量读,比如os.environ['RANK']和os.environ['WORLD_SIZE'],而不是自己传0或1。torchrun其实会自动设好这些,但你代码里如果硬编码了就可能错位,导致NCCL找不到正确的GPU。另外试试在init_process_group前加一句torch.distributed.barrier(),有时候能暴露初始化顺序问题。还有个小细节,set_device最好在init_process_group之前调用,不然默认设备可能还是cuda:0,两个进程都抢一块卡。我之前还遇到过NCCL版本和驱动不匹配的坑,报错也是invalid usage,你可以顺便升级下nccl或者检查nvidia-smi里的拓扑结构。如果还不行,先降到单卡跑通再逐行对比官方示例,多半是环境变量没传全。
我之前也踩过这个坑,大概率是local_rank和torch.cuda.set_device的配合问题。torchrun会自动设置LOCAL_RANK环境变量,但你的代码里得在init_process_group之后再调set_device,顺序反了就容易设备号错乱。还有个小细节,NCCL对CUDA_VISIBLE_DEVICES很敏感,建议在脚本开头就固定好卡号,用os.environ['CUDA_VISIBLE_DEVICES']指定一下。我当时是加了个dist.barrier()确保所有进程同步完再加载模型,莫名就好了,你可以试试。
八成是环境变量MASTER_ADDR和RANK没设,torchrun其实会自动配,你手动set_device反而干扰了。
你这个报错我上周刚踩过,大概率不是NCCL本身的问题,而是local_rank和实际cuda device没对齐。torchrun会自动设置LOCAL_RANK环境变量,但你要是手动调了set_device,反而会把主进程的设备搞乱,试试直接删掉那行,让DDP自己分配。另外init_process_group里最好显式传一下init_method='env://',不然有时候默认值在子进程里会飘。我之前还把world_size写死成2,换了节点数就崩,后来改成从环境变量读就稳了。你先按这个排查下,如果还报错,把完整的traceback贴出来看看。
大概率是rank和local_rank混用了,torchrun下直接用环境变量就行,别手动set_device。
我之前也踩过这个坑,NCCL报invalid usage八成不是DDP本身的问题,而是环境变量和初始化顺序没对齐。你用了torchrun的话,其实不用手动调torch.cuda.set_device,因为torchrun会自动帮你设置LOCAL_RANK对应的设备,你再手动set一遍反而容易和NCCL的默认通信上下文冲突。我当时的解法是把set_device那行删掉,然后在init_process_group之前先确保torch.cuda.device_count()能被正确看到,并且每个进程只用自己那个rank的卡。另外你检查下有没有设MASTER_ADDR和MASTER_PORT,虽然torchrun会默认填,但如果你代码里手动覆盖了就容易出问题,尤其端口冲突时NCCL会报这种模糊错误。还有个小细节,如果你的数据加载里用了num_workers>0,记得在train脚本里用if name == 'main'包住,否则子进程会递归spawn导致设备上下文混乱。我后来把init_process_group放到了模型实例化之前,并且用dist.barrier()在数据加载前同步一次,就稳定了。你可以试试把set_device那行注释掉,然后打印一下每个进程的rank和cuda:current_device看看是不是对的。如果还不行,可以试试把backend换成gloo跑一次纯CPU的debug,能定位到底是网络问题还是设备映射问题。
检查下init_process_group里有没有传rank和world_size,用torchrun时这俩必须从环境变量读。
八成是环境变量没设全,试试显式传rank=int(os.environ['RANK']),我之前这么搞就好了。
遇到这个报错大概率就是设备号没对齐,torch.cuda.set_device(local_rank)得放在init_process_group之前,而且local_rank要从os.environ['LOCAL_RANK']取,不能自己随便定义。另外torchrun其实会自动设置好环境变量,你代码里如果重复赋值反而容易出问题。我上次是直接把set_device去掉,改成在DDP包装前用device = f'cuda:{rank}'传参,就没再报错了。你也可以试试把init_method显式指定成'env://',有时候默认值会踩坑。
大概率是环境变量缺失,检查一下RANK和WORLD_SIZE有没有传进去,torchrun会自动设的。
我之前也踩过这个坑,问题多半出在torch.cuda.set_device和init_process_group的顺序上。官方推荐的做法是先初始化进程组,再设置device,你试试把这两行换一下顺序,同时确认环境变量LOCAL_RANK是torchrun自动注入的,别手动覆盖。另外NCCL报错有时候是网卡或共享内存的问题,可以加--master_port换个端口,或者设置NCCL_DEBUG=INFO看下具体卡在哪个节点。我之前就在这上面耗了两天,最后发现是容器里共享内存设太小了。
我之前也踩过这个坑,DDP报NCCL错误八成不是环境变量的问题,而是卡号分配逻辑没走对。你用了torchrun的话,其实它会自动帮你设置LOCAL_RANK和RANK这些环境变量,所以代码里不应该再手动调torch.cuda.set_device,直接把local_rank传进去初始化就行,比如torch.cuda.set_device(int(os.environ['LOCAL_RANK']))但注意别重复设置。还有一点,init_process_group的world_size和rank参数最好显式从环境变量里读,别自己写死,不然主进程和子进程容易对不上。另外你的数据加载器里,DistributedSampler有没有按rank做shuffle?如果每个进程拿到的数据一样,也会导致不同步报错。我猜你可能是单卡代码里用了.cuda()或者.to(device),而device是提前写死的,比如cuda:0,这样在多卡下所有进程都往0号卡塞,肯定崩。建议把所有设备相关的地方都改成用local_rank动态获取,包括模型、输入输出。还有个小技巧,跑之前先export NCCL_DEBUG=INFO,能看到具体是哪一步卡住,比盲猜高效很多。
我之前也被这个坑过,八成是local_rank和cuda device没对上。torchrun会自动设置RANK和LOCAL_RANK,你代码里直接torch.cuda.set_device(local_rank)没问题,但要确认下是不是在init_process_group之后才调用的,顺序反了就容易出这种错。另外NCCL报invalid usage有时候是环境变量没传全,试试在启动命令前加export NCCL_DEBUG=INFO看看具体是哪个环节断的。还有个小细节,如果你的数据加载器里用了多进程,记得给每个rank单独设个sampler,不然也会莫名奇妙的。我上次就是漏了这一步,折腾了一下午。
试试把set_device放到init_process_group前面,local_rank得从环境变量里取,别自己设。
八成是rank和device没绑对,试试在init_process_group前先set_device,或者直接用local_rank传参。