DDP不是DataParallel的升级版,而是基于多进程的全新并行范式;必须用torchrun或spawn启动独立进程,每个进程初始化通信组、绑定GPU、使用DistributedSampler,并在rank0保存模型。

DistributedDataParallel(DDP)不是DataParallel的“升级版”,而是完全不同的并行范式——它必须用多进程启动,不能像DataParallel那样单进程内调用。
为什么不能直接把 DataParallel 替换成 DistributedDataParallel
DataParallel 是单进程多线程模型,所有 GPU 操作都在主进程中完成,靠 Python 的 torch.nn.DataParallel 自动分发 batch;而 DistributedDataParallel 要求每个 GPU 对应一个独立进程,各进程初始化自己的 torch.distributed 后端(如 nccl),再包装模型。直接替换会报错:RuntimeError: Default process group is not initialized 或 Expected to have finished reduction in the prior iteration。
- 必须用
torch.multiprocessing.spawn或torchrun启动多个进程,每个进程绑定一个 GPU - 每个进程都要调用
torch.distributed.init_process_group初始化通信组 - 模型必须先移到对应进程的
device上,再传给DistributedDataParallel -
DataParallel可以只改一行代码就启用,DistributedDataParallel需重构启动逻辑
如何用 torchrun 正确启动 DDP 训练
torchrun 是目前最稳妥的启动方式,自动处理 rank、world_size、master_addr/port 等配置,不用手写 init_process_group 参数。
- 脚本开头必须包含
if __name__ == "__main__":保护,否则 Windows/macOS 多进程会递归启动 - 训练函数里要先解析
torch.distributed.get_rank()和torch.distributed.get_world_size() - 数据加载器要用
torch.utils.data.distributed.DistributedSampler,且设置shuffle=True时需在每个 epoch 调用sampler.set_epoch(epoch) - 示例启动命令:
torchrun --nproc_per_node=4 train.py,此时world_size=4,每个进程的rank是 0~3
model = model.to(device) model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[device])
DistributedDataParallel 下保存和加载模型的注意事项
DDP 包装后的模型 state_dict() 仍和原始模型结构一致,但保存时若在所有进程都调用 torch.save,会导致文件被多次覆盖或损坏;加载时若只在 rank 0 加载再 broadcast,又容易因不同步出错。
立即学习“Python免费学习笔记(深入)”;
- 推荐只在
rank == 0进程保存:if rank == 0: torch.save(model.module.state_dict(), "model.pth") - 加载时所有进程都执行
torch.load,但路径相同、内容一致即可(不依赖 broadcast) - 注意
model.module是原始模型,model.state_dict()会带module.前缀,除非构造 DDP 时设find_unused_parameters=True并接受额外开销 - 如果用
torch.compile+ DDP,必须在 DDP 包装前编译,否则会报CompiledFunction not supported in DDP
常见卡死或 NCCL 错误怎么快速定位
DDP 最典型的失败不是语法错,而是进程间卡在 collective op(如 allreduce)上,表现为训练不动、GPU 显存涨满但利用率 0%。
- 先检查 NCCL 环境变量:
export NCCL_BLOCKING_WAIT=1可让卡住时立刻报错而非静默等待 - 确认所有 GPU 支持 P2P 访问:
nvidia-smi topo -m中看GPU-GPU是否为NV1或NV2,不是则可能需禁用NCCL_P2P_DISABLE=1 - 混合精度训练中,
torch.cuda.amp.GradScaler必须在 DDP 外部创建,且scaler.scale(loss).backward()后直接scaler.step(optimizer),不要跨进程同步 scaler - Windows 不支持 NCCL 后端,必须用
GLOO,性能差很多,且需显式设export MASTER_PORT=29500等
DDP 的复杂性不在 API 调用本身,而在进程边界、通信同步、资源隔离这些隐含约束——漏掉任意一环,都可能跑通但结果错误,或者根本起不来。


















