根本原因是未在每个进程单独初始化DataLoader,而是复用同一实例;DistributedSampler需每进程独立创建并传入,且依赖正确初始化的分布式环境。

为什么 DistributedSampler 一跑就报 RuntimeError: Sampler should have same number of elements as dataset
根本原因是没在每个进程里单独初始化 DataLoader,而是复用了同一个实例。PyTorch 的 DistributedSampler 本身不自动切分数据,它只负责告诉当前进程“你该拿哪一段”,但前提是 DataLoader 的 dataset 长度对每个进程都得是原始长度(不能提前子集化),且 sampler 必须传进去。
- 错误做法:主进程创建一次
DataLoader,然后用torch.distributed.broadcast()试图同步——不行,DataLoader不可序列化广播 - 正确做法:每个进程(rank)各自调用
torch.utils.data.DataLoader(dataset, sampler=DistributedSampler(dataset, shuffle=True)) - 必须设
shuffle=True时传seed给DistributedSampler,否则不同 rank 的打乱顺序不一致,等效于没 shuffle -
DistributedSampler默认会把样本数向上补齐到能被 world_size 整除,所以实际每个 epoch 迭代次数可能略多——这是设计行为,不是 bug
DistributedSampler 的 num_replicas 和 rank 到底谁来传
绝大多数情况下,这两个参数应该由 torch.distributed 自动推导,别手写死。手动指定只在调试或特殊拓扑(比如跨节点部分进程不参与训练)时才需要。
- 不传
num_replicas和rank:它会自动调用dist.get_world_size()和dist.get_rank(),这是最安全的做法 - 如果提前初始化了分布式环境(比如调用了
torch.distributed.init_process_group),就直接用默认构造;否则会报RuntimeError: Default process group is not initialized - 手写
rank=0却在 rank=1 的进程里运行?会导致所有进程都只读前 1/world_size的数据,训练直接崩
和 DataLoader 的 num_workers > 0 一起用,为啥卡住或报 OSError: [Errno 24] Too many open files
根本矛盾在于:每个 worker 进程都会尝试初始化自己的分布式上下文,而默认的 spawn 启动方式不兼容 fork + 多进程通信机制,容易引发句柄泄漏或阻塞。
- 必须设
pin_memory=True,否则 GPU 数据传输会成为瓶颈,分布式优势全抵消 -
num_workers > 0时,强烈建议用spawn启动方式(不是默认的fork),并在子进程里避免重复调用init_process_group - Linux 上可临时加大文件描述符限制:
ulimit -n 65536,但这只是掩盖问题,根源还是 worker 初始化不当 - 更稳妥的做法:先验证
num_workers=0能跑通,再逐步开 worker 并检查日志里有没有NCCL或IB相关 warning
验证 DistributedSampler 是否真正在均匀分数据
最简单的办法不是看 loss 下降,而是直接 inspect 每个 rank 加载的第一个 batch 的 dataset 索引——它必须互斥且覆盖全集。
- 在
DataLoader构造后加一句:print(f"Rank {dist.get_rank()}: first 5 indices = {list(sampler.__iter__())[:5]}") - 注意:
sampler是惰性迭代器,每次__iter__()都生成新序列(尤其开启shuffle后),所以要在每个 epoch 开始前 print - 如果两个 rank 打印出重叠索引(比如都含 0、1),说明
sampler初始化错了,大概率是忘了传shuffle或seed - 别依赖
len(dataloader)做判断——它返回的是采样后的长度(已补齐),不是原始dataset长度
事情说清了就结束。真正麻烦的永远不是 API 调用,而是 rank 之间状态不同步、worker 初始化污染、以及那个默默补齐样本却不说一声的 DistributedSampler。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











