原帖在两 GPU 的 DDP 构造阶段同步参数失败;附加日志又出现了另一类 system error:
RuntimeError: NCCL error in: /opt/conda/conda-bld/pytorch_1614378083779/work/torch/lib/c10d/ProcessGroupNCCL.cpp:825, unhandled cuda error, NCCL version 2.7.8
NCCL 的最后一句可能遮住首个 rank 的错误
原题在 DDP 初始化参数广播处失败,其他 rank 可能只报告通信中断。因此必须保存各进程第一条 CUDA/NCCL 错误,先查单卡与设备绑定。附加日志来自另一环境的 system error,不能直接作为最初故障的根因。
这条 unhandled cuda error 表示通信内部调用 CUDA 失败,不能把所有 NCCL 2.7.8 报错归成一个已知 bug。先定位最早的 rank 错误,再检查每进程设备与单卡计算。
在每个 worker、初始化 DDP 之前运行:
import os
import torch
print("josh050608")
print("rank/local rank:", os.environ.get("RANK"), os.environ.get("LOCAL_RANK"))
print("visible:", os.environ.get("CUDA_VISIBLE_DEVICES"))
print("count/current:", torch.cuda.device_count(), torch.cuda.current_device())
print("parameter devices:", sorted({
str(p.device) for p in model.parameters()}))
若使用 torchrun,通常按 LOCAL_RANK 绑定本机可见 GPU,再把模型放到该设备,最后构造 DDP:
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
local_rank = int(os.environ["LOCAL_RANK"])
torch.cuda.set_device(local_rank)
dist.init_process_group("nccl")
model = model.to(local_rank)
model = DDP(model, device_ids=[local_rank])
原题使用 mp.spawn 时,应由 worker 参数传入相应本地 rank,而不是假设环境变量一定存在。一个进程不要同时占用另一 rank 指定的 GPU。
单卡运算通过后,用 NCCL_DEBUG=INFO 收集每个 rank 的第一条 WARN,再尝试最小 all_reduce。若日志指向共享内存、socket 或 IB,则按实际系统错误分别排查;不应把附加 A100 环境的 ibv 错误当成最初 TITAN X 故障的已证实原因。
验证 DDP 初始化、小 collective、单个训练 step 依次通过。预编译 torch 的运行不要求本机 nvcc 小版本完全相同,自定义扩展另行核对。
用一条清晰的启动链验证 rank 与模型设备
torchrun 启动时,LOCAL_RANK 是本机可见设备下标;mp.spawn 则由 worker 入参给出。两种启动方式不要混着假设环境变量一定存在。模型迁移完成后,再用对应 device_ids 构造 DDP。
以下纯 Python 配置检查以合成 rank 演示边界,实际运行应替换成各进程真实环境:
def validate_assignment(local_rank, visible_count, parameter_devices):
if not 0 <= local_rank < visible_count:
raise ValueError("本地 rank 超出可见设备范围")
expected = f"cuda:{local_rank}"
if set(parameter_devices) != {
expected}:
raise ValueError(f"模型设备与 rank 不一致,预期 {expected}")
return expected
assert validate_assignment(1, 2, ["cuda:1", "cuda:1"]) == "cuda:1"
try:
validate_assignment(1, 2, ["cuda:0"])
except ValueError as exc:
print("configuration mismatch:", exc)
这段不验证通信,只检查配置约束。真实测试先在每张卡运行基础计算,再做最小 all_reduce,最后构造 DDP 与单步训练。所有 rank 必须参加同一 collective,某个进程提前异常退出会让其他进程的后续错误失去定位价值。
若 NCCL_DEBUG 的首条 WARN 指向 IB、共享内存或 socket,沿对应子系统处理;若首先是 CUDA 非法访问,优先缩小该算子。不要同时降 torch、改驱动、禁用全部通信后端,导致无法判断哪项改变有效。
最终记录“单卡通过、collective 通过、DDP 初始化通过、训练一步通过”各自结果。只让主 rank 打印一条成功信息,不能替其他进程完成验证。
参考:原始求助帖;技术依据:PyTorch 分布式(2.5)、NVIDIA NCCL 排错指南、PyTorch CUDA 语义(2.5)。