要完全固定PyTorch训练结果,必须同时设置torch、CUDA、NumPy、Python random种子,禁用cuDNN benchmark并启用deterministic模式,且为DataLoader的每个worker显式初始化随机状态。

PyTorch设置torch.manual_seed()为什么还不固定结果
只调用 torch.manual_seed(42) 是不够的。PyTorch 的随机性来源不止 CPU 张量运算,还包括 CUDA 操作、数据加载、甚至某些算子内部的并行调度。尤其在 GPU 上训练时,不显式控制 CUDA 随机状态,每次运行结果大概率不同。
-
torch.manual_seed()只影响 CPU 和当前默认 CUDA 设备的种子,但不保证所有 CUDA 操作可重现(比如 cuDNN 卷积的非确定性模式) - 若使用多卡,需对每张卡单独设
torch.cuda.manual_seed_all() - 即使单卡,cuDNN 默认启用优化路径(如 autotune),可能选择不同算法导致数值差异
必须同步设置 NumPy 和 Python 内置随机模块
PyTorch 本身不接管 random 或 numpy.random,但很多预处理(如 Albumentations、自定义 Dataset 中的图像扰动)会直接调用它们。漏掉任一模块,数据增强环节就不可复现。
- 调用
random.seed(42)固定 Python 内置 RNG - 调用
np.random.seed(42)(注意:不是numpy.random.default_rng(),后者需单独实例化) - 若用
torch.Generator(如DataLoader的generator参数),也要传入已 seed 的实例,而非依赖全局状态
DataLoader 的 worker_init_fn 和 generator 容易被忽略
当 num_workers > 0 时,每个子进程有独立的随机状态,全局 seed 对它们无效。这是最常被忽视的“伪随机”来源。
- 必须通过
worker_init_fn在每个 worker 内重新设置三类种子:torch、numpy、random - 或者更稳妥地:用
torch.Generator实例传给DataLoader(generator=gen),并确保该gen已用gen.manual_seed(42) -
pin_memory=True不影响随机性,但若和num_workers混用且未初始化 worker,会放大不一致问题
cuDNN 和 determinism 的开关要配对使用
仅设 torch.backends.cudnn.enabled = False 能禁用 cuDNN,但性能暴跌;而只设 deterministic=True 不保证完全可复现,必须两者结合,并接受部分算子降级或报错。
立即学习“Python免费学习笔记(深入)”;
- 加上
torch.backends.cudnn.benchmark = False(否则 autotune 会引入不确定性) - 推荐写法:
torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False
- 注意:某些操作(如
torch.nn.functional.conv2d在特定 padding 模式下)仍可能触发非确定性 fallback,此时需检查 PyTorch 版本是否已修复对应 issue
DataLoader 子进程初始化和 cuDNN 的 benchmark 开关 —— 这两个点没处理好,前面所有 seed 都白设。


















