正确播种numpy随机生成器

epggiuax  于 5个月前  发布在  其他
关注(0)|答案(2)|浏览(73)

对于我的科学实验,我通常使用种子:
第一个月
对于当前的numpy版本,它相当于
rng = np.random.Generator(np.random.default_rng(seed))
当我重复我的实验n次并平均它们的结果时,我通常将seed设置为0n之间的所有数字。
然而,阅读这里和这里的文件,它指出,
种子应该是大的正整数。

我们默认使用从操作系统收集的熵来使用128位整数。这是一个很好的熵量来初始化numpy中的所有生成器。我们不建议使用低于32位的小种子用于一般用途。
然而,在第二个参考文献中,它还指出,
结果本身不会有任何问题;由于SeedSequence所做的处理,即使是0的seed也非常好。
这感觉很矛盾,我想知道,如果小的种子现在完全可以使用,或者应该转向更高的种子。特别是,我想知道,(i)在什么时候(如果有的话)大的种子会对低的种子产生影响,(ii)如果进行科学实验(例如机器学习/算法研究),人们应该更喜欢高的种子还是更低的种子?
附言:这个问题与Random number seed in numpy高度相关,但涉及到现在推荐的Generator。此外,答案似乎不够深入,因为它没有包括关于高种子和低种子的讨论。

rqqzpn5f

rqqzpn5f1#

对正位于您链接的快速启动页面中:
我们建议使用非常大的、唯一的数字,以确保您的种子与其他人的种子不同。这是一个很好的做法,可以确保您的结果在统计上独立于其他人的结果,除非您有意复制他们的结果。
简而言之,这是为了避免通过生成完全相同的数据集来复制其他人的偏见(如果有的话),因为人类更有可能默认选择短数字(01142)而不是非常大的数字。
在您的用例中,这可能并不重要。

nzk0hqpo

nzk0hqpo2#

坦率地说,你必须考虑任何伪RNG的内部结构,并将它们与你想要的进行比较。
有N位状态以及三个功能:

  • state seed 2state(seed)#将seed转换为适当的状态
  • state nextstate(state)#将state前进一步
  • uint 64 state 2 output(state)#从state中提取“随机性”并将其用于例如[0.1)U 01 rv。

就是这样,不多不少,其他的都是有用的附加组件。
您使用的是PCG 64(XLS RR Varian),它具有128位状态,并生成64位输出。
第一个问题是如何从种子填充状态。这里的潜在问题是,您使用的是小值整数,并且在一次调用nextstate()然后调用state 2 output()之后,不会立即发生足够的位斩波/混合。基本上,小整数种子将使状态大部分为零,这可能会影响您的模拟。
解决方案-运行一些1 K-10 K的调用来混合你的RNG。然后保存PCG状态为字典/JSON,并从这里开始,你有你的状态很好地混合。这实际上是最好的方法-模拟代码应该得到状态,而不是种子,作为输入。你在模拟代码之外控制状态。

seed = np.uint64(13579754321)

pcg = np.random.PCG64(seed)
rng = np.random.Generator(pcg)

rng.bytes(64*10000) # mixing/warm-up

state = pcg.state # save/restore state
pcg.state = state

字符串
第二个问题是确保不同模拟的独立采样序列,使得没有重叠,也没有相关性。
建议,使种子大,这样就没有重叠的作品只有机会。为什么离开改变的东西,可以完全控制?
PCG 64有两个功能,这可能会大大帮助-前进和跳跃。前进将移动状态,就像有距离的呼叫数量。内部它是相当快,并在日志(距离)时间工作。
你必须计算或检查一次有多少RNG调用你需要一个模拟,做一些保留,只是使用它。
一些伪代码

def simulation(some parameters, state) -> value:
    pcg = np.random.PCG64(1)
    pcg.state = state
    
    rng = np.random.Generator(pcg)
    ...
    return value


主要功能

def main():

    nof_PCG_calls_per_simulation = 100000000

    pcg = np.random.PCG64(135797531)
    rng = np.random.Generator(pcg)

    rng.bytes(64*10000) # mixing/warm-up

    state = pcg.state

    N = 1000 # number of simulations to run

    s = 0.0
    for k in range(0, N):
        pcg = np.random.PCG64(1)
        pcg.state = state

        simstate = pcg.advance(N*nof_PCG_calls_per_simulation).state

        v = simulation(whatever, simstate)
        s += v

    return (s/N, N)


还有一个很好的PCG方法-- jumps,它在语义上非常接近于advance,它返回新的PCG,并且状态不同,就像生成了2127个数字一样。
这样你就可以确保PCG状态混合良好,并且不同模拟中使用的不同流不会重叠。

相关问题