关于random.seed()和np.random.seed()设置失败的解决

按道理说python项目中使用了random和numpy的random,我们在main函数开头设置上:

SEED=42
random.seed(SEED)
np.random.seed(SEED)

再调用函数或者实例化对象就可以根据种子的设定实现随机数据的生成和随机试验的复现。

但是奇怪的是今天我这样设置并没有成功按照种子复现我的实验。问了许多AI,查了大量的文档,甚至使用了更现代、科学、可控的做法——面向对象的随机数生成器(RNG, Random Number Generator),仍然没有解决我的问题。

下午我就对我的代码进行了逐行的排查,发现关键在于“哈希”(Hash)。下面我们一起来看看:

nums = [1,2,5,1,2,3,6,8,6,1]
s = set()
for x in nums:
    if x not in s:
        s.add(x)
res = np.random.choice(list(s))

你会发现就算你设定好了种子,每次的结果还是不一样的。

这是因为这里的s是一个set,python中的 set 是基于哈希表实现的,是一个无序、唯一元素集合。因此,就算对于相同的nums,我们每次得到的s转换成的list都可能是不同的。他可能是:

(1,2,5,3,6,8)
(2,3,5,1,6,8)
(8,6,1,2,3,5)
……

等等,转换成list后,得到的list虽然元素是一样的,但是顺序是不同的,由于np.random.choice()的实现是依赖于索引,得到的res当然不同。

怎么解决呢?很简答,sort()一下就好了!

nums = [1,2,5,1,2,3,6,8,6,1]
s = set()
for x in nums:
    if x not in s:
        s.add(x)
res = np.random.choice(list(s).sort())

 另外,如果你还使用了torch,你可以加几句,也能设定他的种子:

import random
import numpy as np
import torch

def set_seed(seed=42):
    random.seed(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)  # 如果使用GPU
    torch.cuda.manual_seed_all(seed)  # 多GPU时
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

在main函数开头,调用set_seed()即可。

最后,如果你使用的是并行训练/多线程或者是想更加科学的设定随机种子,你可以使用面向对象的随机数生成器(RNG, Random Number Generator),以numpy为例:

import numpy as np


def create_rng(seed: int = 42):
    return np.random.default_rng(seed)
    

def func1(rng):
    print(rng.integers(0, 10))  # 生成 0~9 之间的随机整数
    print(rng.normal(0, 1))     # 生成正态分布随机数


if __name__=='__main__':
    rng = create_rng(42)
    func1(rng)

如果想更了解哈希可以去自行搜索或者看看我后边的文章。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值