np.random.seed()仅影响旧式函数,对generator api无效;应改用np.random.default_rng(seed)创建独立生成器,多进程需为各进程分配不同种子,且pytorch/tensorflow等需单独设种。

np.random.seed() 为什么有时不生效
它只影响 np.random 模块下的老式函数(比如 np.random.rand()、np.random.randn()),对新引入的 Generator API 完全无效。如果你用了 np.random.default_rng(),调 np.random.seed() 就像往咖啡里撒盐——看起来在操作,其实没起作用。
常见错误现象:np.random.seed(42) 后,np.random.default_rng().random() 还是每次结果不同;或者在多线程/多进程里反复调用 seed(),但子进程不受影响。
- 使用场景:快速脚本、教学示例、旧项目维护
- 参数差异:
np.random.seed()接整数,None表示用系统时间,不能传字符串或数组 - 注意:Python 的
random.seed()和 NumPy 的np.random.seed()是两套独立状态,互不影响
用 np.random.Generator + seed 更可靠
NumPy 1.17+ 推荐用 Generator,它把随机数生成逻辑和种子解耦,更可控也更符合现代用法。关键不是“设种子”,而是“用带种子的生成器”。
实操建议:
- 别再全局调
np.random.seed(),改用rng = np.random.default_rng(42) - 所有随机操作都走
rng实例,比如rng.random()、rng.normal()、rng.choice() - 如果需要多个隔离的随机流(比如模型不同层初始化),直接创建多个
default_rng(seed),种子不同即可,无需担心干扰
示例:
rng_a = np.random.default_rng(123) rng_b = np.random.default_rng(456) print(rng_a.integers(0, 10)) # 总是 2 print(rng_b.integers(0, 10)) # 总是 8
多进程下 np.random.seed() 失效的根本原因
子进程启动时会复制父进程内存,但 np.random 的内部状态不是深拷贝,且各进程默认用相同系统时间初始化——所以看似设了种子,实际每个进程都在用自己那一份未初始化的随机状态。
正确做法是:每个子进程显式创建自己的 Generator,并传入**不同但可推导的种子**(比如主进程 seed + 进程 ID)。
- 错误写法:
np.random.seed(42)放在multiprocessing.Process外,然后进子进程直接调np.random.rand() - 推荐写法:子进程中执行
rng = np.random.default_rng(seed_base + rank),其中rank是进程编号 - 性能影响:
default_rng()创建开销极小,不用复用或缓存实例
PyTorch / TensorFlow 里 NumPy 种子不管用
PyTorch 自己管 torch.manual_seed(),TensorFlow 用 tf.random.set_seed(),它们和 NumPy 的随机数生成器完全无关。你设了 np.random.seed(42),但模型权重初始化走的是 PyTorch 的 RNG,结果照样不可复现。
要真正复现实验,必须三者都设:
-
np.random.seed(42)或更好:np.random.default_rng(42) -
torch.manual_seed(42)(还建议加torch.cuda.manual_seed_all(42)) -
tf.random.set_seed(42)(TF 2.x) - 额外提醒:Python 自身的
random模块也要设random.seed(42),尤其当用到random.shuffle()或采样逻辑时
最容易被忽略的是:某些库(比如 scikit-learn)内部可能混合调用 np.random 和 random,光设一个根本不够。种子得像安全带一样,系全了才管用。










