设 random_state 后结果仍不一致,因 Python 随机性来自 NumPy、Python 原生 random、CUDA、CUDNN、DataLoader 等多个独立源头;仅设模型 random_state 只控制其参数初始化,其余环节仍随机。

为什么设了 random_state 还是结果不一致?
因为 Python 的随机性来自多个独立源头:NumPy、Python 内置 random、TensorFlow/PyTorch 的 CUDA 随机数生成器、甚至数据加载顺序(如 DataLoader 的 shuffle)。只给模型传一个 random_state=42,只管得着模型内部的参数初始化逻辑,其他地方照旧“自由发挥”。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 显式设置 NumPy 种子:
np.random.seed(42) - 设置 Python 原生随机种子:
random.seed(42) - 若用 scikit-learn 模型(如
RandomForestClassifier),random_state参数必须传,且值要和上面一致 - 注意:sklearn 0.23+ 版本中,部分模型(如
MLPClassifier)还依赖torch.manual_seed(如果底层用了 PyTorch),需额外处理
PyTorch 训练中如何锁死全部随机源?
PyTorch 不吃 random_state 这一套,它有自己的三套随机数生成器:CPU、CUDA、CUDNN。漏掉任意一个,GPU 上的结果就可能漂移。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 训练前一次性调用以下四行(顺序不能乱):
torch.manual_seed(42) np.random.seed(42) random.seed(42) torch.cuda.manual_seed_all(42)
- 禁用 CUDNN 的非确定性算法:
torch.backends.cudnn.deterministic = True;同时建议设torch.backends.cudnn.benchmark = False(否则会自动选快但不稳定的 kernel) - 若用
DataLoader,务必加worker_init_fn和generator:def worker_init_fn(worker_id): np.random.seed(42 + worker_id) dl = DataLoader(dataset, shuffle=True, worker_init_fn=worker_init_fn, generator=torch.Generator().manual_seed(42))
TensorFlow/Keras 中 tf.random.set_seed 管不管用?
在 TF 2.x 中,tf.random.set_seed(42) 是入口级开关,但它只控制 TensorFlow 自己的随机操作(如 tf.random.normal),不触碰 NumPy 或 Python 的随机状态。而且——它对多线程/多 GPU 场景支持有限。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须配合
os.environ['TF_DETERMINISTIC_OPS'] = '1'(启用确定性算子) - 若用 GPU,还需设
os.environ['TF_CUDNN_DETERMINISTIC'] = '1' - 模型编译前调用
tf.random.set_seed(42),且确保没在别处调用np.random.seed或random.seed—— 否则它们会干扰 TF 的 seed 行为 - 注意:Keras 层的
kernel_initializer='glorot_uniform'默认是随机的,但只要全局 seed 设对,它就会复现;若想彻底保险,可显式写成kernel_initializer=tf.keras.initializers.GlorotUniform(seed=42)
验证是否真的“锁死了”?别只看准确率
准确率或 loss 数值相近 ≠ 随机性被控制住。权重矩阵、梯度更新顺序、甚至 batch 内样本排列都可能不同,只是最终指标碰巧一样。真正验证,得比对中间态。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 训练两个完全相同配置的 run,保存 epoch 1 结束后的模型权重:
model.get_weights()(Keras)或[p.data for p in model.parameters()](PyTorch),用np.allclose对比 - 打印某一层的前 5 个参数,肉眼确认是否逐位一致
- 如果用了早停(early stopping),记得固定 validation 数据划分方式(比如用
train_test_split(..., random_state=42)),否则哪怕模型一致,停在哪一轮也不同 - 最容易被忽略的一点:文件系统读取顺序(如
os.listdir)默认无序,若你按文件名构造 dataset,务必先sorted()—— 否则每次训练喂的数据顺序都可能变


















