直接套用 distributeddataparallel 报错是因为未初始化默认进程组,必须用 torchrun 启动并调用 torch.distributed.init_process_group(backend="nccl"),且 device 设置、ddp 包裹顺序、distributedsampler 使用及 checkpoint 保存加载均需严格遵循分布式规范。

为什么直接套用 DistributedDataParallel 会报错 RuntimeError: Default process group is not initialized
因为 DistributedDataParallel 不是开箱即用的“多卡开关”,它依赖底层的分布式进程组。没调用 torch.distributed.init_process_group,或者初始化方式和启动方式不匹配(比如用 python train.py 而不是 torchrun),就会崩在这里。
正确做法是统一用 torchrun 启动,并在代码里显式初始化——但注意:如果用了 torchrun,init_process_group 的 rank 和 world_size 会被自动注入环境变量,不需要手动传参。
- 必须用
torchrun --nproc_per_node=2 train.py启动,不能直接python train.py - 代码中调用
torch.distributed.init_process_group(backend="nccl")即可,不用指定rank/world_size(torchrun已设好) - 确保所有 GPU 设备可见且未被占用:
os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"不能写在init_process_group之后,否则子进程可能看不到设备
DistributedDataParallel 包裹模型时,为什么 model.cuda() 和 model.to(device) 行为不同?
因为 DistributedDataParallel 内部会把模型复制到当前进程绑定的 GPU 上,所以必须先确定 device,再包裹,顺序错了会出 CUDA error 或显存分配失败。
典型错误写法:model = DDP(model.cuda()) —— 这会让所有进程都把模型搬到 GPU 0,而不是各自对应的 GPU。
- 正确顺序:先获取本进程对应 device(
torch.device(f"cuda:{torch.distributed.get_rank()}")),再model.to(device),最后DDP(model) - 不要用
model.cuda(),它默认用cuda:0,跨进程时失效 - 如果用了
torchrun,get_rank()就是当前进程的 GPU 索引,无需额外映射
数据加载器怎么避免各卡重复读同一份数据?
普通 DataLoader 不知道分布式上下文,每张卡都会从头读完整个数据集。必须配合 DistributedSampler 切分数据,否则训练等效于单卡跑 N 遍。
DistributedSampler 本身不加载数据,只提供索引切片;它需要显式传给 DataLoader 的 sampler 参数,并设置 shuffle=True(否则每个 epoch 数据顺序固定)。
- 构造 sampler 时传
num_replicas=torch.distributed.get_world_size()和rank=torch.distributed.get_rank() -
DataLoader中必须设shuffle=False(如果用了DistributedSampler),否则会双重 shuffle - 验证/测试阶段也要用
DistributedSampler,否则指标不可比(各卡 batch 数不一致)
保存和加载 checkpoint 时,为什么只让 rank 0 保存、所有 rank 加载?
因为所有进程的模型参数在同步后是一致的,重复保存只是浪费 IO 和磁盘空间;但加载时如果只有 rank 0 加载,其他 rank 的模型仍是随机初始化状态,会直接训练失败。
常见误区是“只在 rank 0 save”,却忘了所有 rank 都要 load —— 这会导致非 rank 0 进程的模型没更新,梯度计算全错。
- 保存:仅
if torch.distributed.get_rank() == 0:执行torch.save(...) - 加载:所有 rank 都执行
torch.load(...),且路径一致(推荐用绝对路径或共享文件系统) - 加载后记得调用
model.load_state_dict(...),别漏掉这步 - 如果用
DDP包裹过的模型,保存的是model.module.state_dict(),不是model.state_dict()
torch.cuda.synchronize()、手动修改某张卡的参数、或混用 torch.nn.DataParallel——都会让训练发散。最稳的做法,就是全程跟着 torchrun + DDP + DistributedSampler 这个组合走,少自己造轮子。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











