必须分别设置random、numpy、pytorch(cpu/gpu)、tensorflow等各库种子,并配置pythonhashseed、禁用cudnn.benchmark、启用确定性算法才能确保强复现。

random.seed() 和 numpy.random.seed() 必须分开调用
Python 标准库的 random 和 NumPy 的 np.random 是两套完全独立的随机数生成器,各自维护自己的内部状态。只调用 random.seed(42) 不会影响 np.random.rand() 的输出,反之亦然。
常见错误是只设一个种子,结果训练时数据打乱(random.shuffle())可复现,但权重初始化(np.random.randn())却每次不同。
- 必须显式调用两者:
random.seed(seed)+np.random.seed(seed) - 建议在程序最开始、任何随机操作之前执行
- 避免在函数内重复设置——会覆盖外层已设的种子状态
PyTorch CPU/GPU 种子不能只靠 torch.manual_seed()
torch.manual_seed() 只控制 CPU 上的随机行为;如果代码中调用了 .cuda() 或使用了 torch.cuda.* 函数,GPU 随机数生成器仍处于未初始化状态,结果不可复现。
典型现象:同一段代码,在 CPU 上运行结果稳定,换到 GPU 就每次 loss 曲线都漂移。
- CPU 场景:只需
torch.manual_seed(seed) - GPU 场景:必须补全
torch.cuda.manual_seed(seed)和torch.cuda.manual_seed_all(seed)(后者确保多卡一致) - 注意:这些函数不返回值,调用后无反馈,容易误以为“没生效”
TensorFlow 2.x 用 tf.random.set_seed() 而非全局变量
TensorFlow 2.x 已弃用旧版的 tf.set_random_seed(),改用 tf.random.set_seed() 作为统一入口。它同时影响 tf.random.uniform()、tf.keras.initializers.RandomNormal 等所有基于 tf.random 的操作。
容易被忽略的是:该函数只设置“图内随机种子”,不控制 Python 层或 NumPy 层——所以仍需单独处理 random 和 np.random。
- 不要混用
tf.set_random_seed()(TF 1.x 风格),它在 TF 2.x 中无效 - 若使用
tf.data.Dataset.shuffle(buffer_size, seed=...),seed参数优先级高于全局tf.random.set_seed() - 对
tf.keras.layers.Dropout等层,是否复现还取决于训练时是否启用training=True,这点和种子无关
真正统一的初始化函数要覆盖 os.environ 和 deterministic 模式
仅设几个 *seed() 函数,还不足以在 PyTorch GPU 场景下做到强复现。浮点运算顺序、CUDA 卷积优化(cudnn.benchmark)、哈希随机性都会引入微小差异。
最常被跳过的三步是:os.environ['PYTHONHASHSEED']、禁用 cudnn benchmark、强制确定性算法。
- 加这行:
os.environ['PYTHONHASHSEED'] = str(seed),否则字典/集合迭代顺序可能变 - 加这行:
torch.backends.cudnn.benchmark = False,否则第一次运行会缓存最优卷积实现,后续再跑可能选不同路径 - 加这行:
torch.use_deterministic_algorithms(True),让 PyTorch 报错而非静默使用非确定性算子(如index_add_) - 注意:开启
use_deterministic_algorithms后,部分算子会直接报RuntimeError,这不是 bug,是框架在提醒你该换实现方式
os.environ['PYTHONHASHSEED'] 或忘了关 cudnn.benchmark,就可能在第 100 个 epoch 才出现梯度微小偏差——这种延迟暴露的问题最难 debug。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











