PyTorch多GPU下使用nn.DataParallel训练设置随机种子无法复现问题
问题根因
- 核心原因是
nn.DataParallel采用单进程多线程的运行模式,每个GPU对应独立的工作线程。Python原生random库和numpy的随机种子是进程级生效的,仅作用于主线程,新启动的工作线程不会继承主进程的随机种子,会默认使用系统随机源初始化自身的随机状态,导致多卡运行时随机行为不可控。 - 其次PyTorch本身的CPU随机数生成器为线程本地存储,你在主线程调用的
torch.manual_seed仅会设置当前已存在线程的种子,nn.DataParallel启动的新工作线程也不会自动继承该配置。 - 若你使用了带
num_workers>0的DataLoader加载数据,多进程加载的每个子进程也会独立初始化随机状态,进一步放大随机性。
修复方案
- 方案1:替换
nn.DataParallel为官方更推荐的nn.parallel.DistributedDataParallel(DDP)。DDP采用单卡单进程的架构,你只需要在每个进程初始化阶段调用一次set_seed即可,完全规避多线程带来的种子失效问题,同时训练效率也远高于DataParallel。 - 方案2:若必须使用DataParallel,需补充两处配置:
- 自定义DataLoader的
worker_init_fn,给每个数据加载子进程单独设置种子:
初始化DataLoader时传入该函数,同时固定shuffle的随机生成器:def worker_init_fn(worker_id): worker_seed = seed + worker_id set_seed(worker_seed)g = torch.Generator() g.manual_seed(seed) train_loader = DataLoader( train_dataset, batch_size=batch_size, shuffle=True, worker_init_fn=worker_init_fn, generator=g, num_workers=num_workers )- 尽量将代码中所有
random、numpy的随机调用替换为PyTorch自带的随机算子,PyTorch的CUDA随机状态通过你已配置的torch.cuda.manual_seed_all可全局生效,跨线程一致性更强。
- 自定义DataLoader的
内容的提问来源于stack exchange,提问作者doing
相关产品推荐
相关产品推荐

