开始前,会这些就够了
- 能阅读 Python 函数和列表
- 知道程序可以按顺序生成随机数
你照着教程把 seed 写成 17,重新运行,结果一致。后来加了一段随机挑选展示内容的代码,实验结果却变了。种子没有消失,改变的是程序从同一串数字里取走了哪些位置。
训练程序也会用随机数,例如决定初始参数或打乱样本顺序。先用一个不训练模型的小例子,分清“重放一串随机数”与“重放整个实验”之间还隔着哪些条件。
相同起点,还要按相同顺序往前走
普通伪随机生成器根据内部状态算出下一个数,同时推进自己的状态。种子(seed)用来初始化这份状态。可以把它想成一台按固定规则吐数字的机器:同样起点、同样取法,才会走过同样的过程。
同一个生成器被两段代码共用时,任意一段多取一次,另一段接下来拿到的位置就可能改变。固定种子没有冻结调用次数,也没有给每个用途自动分配独立的一串数字。
只多取一次,看看后两项怎样移动
代码每次都为任务新建 Random(17),先取一个数,再取两个。第三行在中间额外取走一个数;第四行让额外用途改用自己的 Random(91)。输出保留六位小数,原始数值没有先取整。
比较结果时,要看第三行后两项对应原序列的什么位置。第四行恢复的是任务这条随机流不受额外调用影响;这不证明两条流在统计上独立,更没有测试模型训练或 GPU 的可复现性。
import random
def draw(extra_call=False, separate_stream=False):
task_rng = random.Random(17)
other_rng = random.Random(91) if separate_stream else task_rng
values = [task_rng.random()]
if extra_call:
other_rng.random()
values.extend(task_rng.random() for _ in range(2))
return values
def show(values):
return ', '.join(f'{value:.6f}' for value in values)
if __name__ == '__main__':
print('original:', show(draw()))
print('same setup:', show(draw()))
print('shared extra call:', show(draw(extra_call=True)))
print('separate extra call:', show(draw(True, True)))怎样运行:保存为 seed_streams.py,用 Python 3.10 或更新版本运行:python seed_streams.py。仅用标准库,不联网,不训练模型。
运行后对照结果
original: 0.521984, 0.806691, 0.960495
same setup: 0.521984, 0.806691, 0.960495
shared extra call: 0.521984, 0.960495, 0.289625
separate extra call: 0.521984, 0.806691, 0.960495训练结果还经过了别的环节
真实项目里,Python、训练框架和数据加载进程可能各用各的随机来源。只设置 Python 的一个种子,不会自动设置所有库的生成器。即使随机数相同,换了输入内容或处理顺序,后面的计算也可能不同。
PyTorch 官方还区分了随机来源与运算实现:某些运算需要另选确定性的实现。文档明确不保证跨版本、跨平台,或 CPU 与 GPU 之间的结果完全一致。“不保证”也不等于一定不同;要在准备支持的环境中实际核对。
先说明你想重现到什么程度
调试时,你可能希望同一环境重跑后每个数都相同;比较算法时,你也可能关心换几组随机条件后,结论是否仍站得住。这是不同的检查。把同一次固定结果重放十遍,不能当作十次新的随机实验来估计波动。
留下一份能照做的记录:代码版本、数据版本与顺序、各处种子、库版本、设备,以及判定一致的方法。Python 对兼容播种方式下的 random() 序列有再现性约定,但不能据此推断所有随机接口、所有版本和整个训练程序都有同样保证。
记住这三点
- 种子控制指定生成器的初始状态;调用顺序改变,任务取到的数字也可能改变。
- 隔离随机流可以减少不同用途互相干扰,完整实验仍需记录数据、代码与环境。
- 先定义一致的标准,再实际复跑;逐项相同与多次实验结论稳定是两种检查。
别把例子用过头
- 本例只执行 Python 标准库随机数调用,没有训练模型或验证 GPU、跨版本、跨平台结果。
- 重新从种子开始与恢复中途状态不是同一操作;断点续训还要恢复模型、优化器和数据进度等状态。
- 可重放的 random 不适合生成登录令牌等保密值;这类用途应使用 secrets 等安全随机接口。
自己试一小步
如果展示模块一次要抽取五个数字,怎样确认它没有改变任务拿到的三项?
- 把额外用途改成连续取五次,先记录你对共用生成器结果的预测。
- 分别运行共用和分开生成器的版本,比较完整返回列表,而不只比较格式化后的文字。
- 写下本次使用的 Python 版本、种子、调用次数,以及你实际验证的一致范围。
做到这些,就算完成
- 能否指出额外调用推进的是哪一个生成器?
- 是否区分了本机示例重放与真实模型跨设备复现?
- 记录是否足以让另一个人按同样步骤复查?
查原始资料
想确认一个细节,先看这份资料对应的部分,不必从头读完所有文档。
- Python:random 的状态与再现性约定 (新标签页)↗
Random 实例各自持有状态,seed 初始化状态,getstate
/setstate保存与恢复状态,以及random()的兼容播种再现性约定。 - PyTorch 2.14:Reproducibility (新标签页)↗
跨版本/平台
/CPU与 GPU 不保证完全重现;不同随机来源、确定性运算与数据加载进程需要分别考虑。 - Python:secrets 的适用范围 (新标签页)↗
安全凭据应采用密码学安全随机来源,模拟用途的默认 random 不适合该目的。
找一份资料继续练
先选一项,按下面的范围继续学;不必从头读完整门课程。
PyTorch:相同随机种子为何还不够 (新标签页)↗
读开头限制,记录种子、随机库、调用顺序、框架版本和设备,区分固定环境与跨环境承诺。
查看学习准备与访问说明 →