如何检索NumPy随机数生成器的当前种子?

qojgxg4l  于 2022-11-10  发布在  其他
关注(0)|答案(6)|浏览(318)

下面的代码导入NumPy并设置种子。

import numpy as np
np.random.seed(42)

然而,我对播下种子不感兴趣,更感兴趣的是阅读它。random.get_state()似乎不包含种子。documentation没有显示出明显的答案。
假设我没有手动设置,如何检索numpy.random使用的当前种子?
我想使用当前的种子来继续流程的下一次迭代。

u5rb5r59

u5rb5r591#

简短的答案是,你根本不能(至少总体上不能)。
NumPy使用的Mersenne TwisterRNG有219937-1个可能的内部状态,而单个64位整数只有264个可能的值。因此,不可能将每个RNG状态Map到唯一的整数种子。
可以使用np.random.get_statenp.random.set_state直接获取和设置RNG的内部状态。get_state的输出是一个元组,其第二个元素是由32位整数组成的(624,)数组。这个数组有足够多的位来表示RNG的每个可能的内部状态(2624x32>219937-1)。
get_state返回的元组可以像种子一样使用,以创建可重现的随机数序列。例如:

import numpy as np

# randomly initialize the RNG from some platform-dependent source of entropy

np.random.seed(None)

# get the initial state of the RNG

st0 = np.random.get_state()

# draw some random numbers

print(np.random.randint(0, 100, 10))

# [ 8 76 76 33 77 26  3  1 68 21]

# set the state back to what it was originally

np.random.set_state(st0)

# draw again

print(np.random.randint(0, 100, 10))

# [ 8 76 76 33 77 26  3  1 68 21]
x3naxklr

x3naxklr2#

  • 这篇文章旨在澄清Ali_m的正确答案,并对董贾斯汀的建议进行重要更正。*

以下是我的调查结果:
1.使用np.random.seed(X)设置随机种子后,可以使用np.random.get_state()[1][0]重新查找。
1.然而,它对你没有什么用处。
以下代码部分的输出将向您说明为什么这两个语句都是正确的。

语句1-可以使用np.random.get_state()[1][0]找到随机种子。

如果使用np.random.seed(123)设置随机种子,则可以使用state = np.random.get_state()将随机状态作为元组检索。下面是state的详细介绍(我在Spyder中使用变量EXPLORER)。我使用屏幕截图,因为使用print(state)会淹没您的控制台,因为元组的第二个元素中的数组太大。

可以很容易地看到123是包含在第二个元素中的数组中的第一个数字。而使用seed = np.random.get_state()[1][0]得到123。完美?不完全是,因为:

声明2--但是,它对您没有什么用处:

乍一看可能并非如此,因为您可以使用np.random.seed(123),使用seed = np.random.get_state()[1][0]检索相同的数字,使用np.random.seed(444)重置种子,然后(似乎)使用np.random.seed(seed)将其设置回123场景。但那时你已经知道你的随机种子是什么了,所以你就不需要这样做了。下一个代码部分还将显示,您不能使用np.random.get_state()[1][0]获取任意随机状态的第一个数字,并期望重新创建该场景。请注意,您很可能必须完全关闭并重新启动内核(或调用np.random.seed(None))才能看到这一点。
以下代码片段使用np.random.randint()生成5个介于-10和10之间的随机整数,并存储有关该进程的一些信息:

  • 代码片段1*

# 1. Imports

import pandas as pd
import numpy as np

# 2. set random seed

# seedSet = None

seedSet = 123
np.random.seed(seedSet)

# 3. describe random state

state = np.random.get_state()
state5 = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]

# 4. generate random numbers

random = np.random.randint(-10, 10, size = 5)

# 5. organize and present findings

df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)

请注意,名为seedState的列与state下的第一个数字相同。我本可以把它作为一个独立的数字打印出来,但我想把它都放在同一个地方。另请注意,到目前为止,seedSet = 123np.random.seed(seedSet)已被注解掉。因为没有设置随机的种子,所以你的数字将与我的不同。但这在这里并不重要,重要的是你的结果的内在一致性:

  • 输出1:*
random seedSet   seedState       state
0       2    None  1558056443  1558056443
1      -1    None  1558056443  1808451632
2       4    None  1558056443   730968006
3      -4    None  1558056443  3568749506
4      -6    None  1558056443  3809593045

在这种情况下,seed = np.random.get_state()[1][0]等于1558056443。按照董贾斯丁回答的逻辑(以及我在这次编辑之前的回答),您可以用np.random.seed(1558056443)设置随机种子,并获得相同的随机状态。下一个片段将显示您不能

片段2


# 1. Imports

import pandas as pd
import numpy as np

# 2. set random seed

# seedSet = None

seedSet = 1558056443
np.random.seed(seedSet)

# 3. describe random state

# state = np.random.get_state()

state = np.random.get_state()[1][:5]
seedState = np.random.get_state()[1][0]

# 4. generate random numbers

random = np.random.randint(-10, 10, size = 5)

# 5. organize and present findings

df = pd.DataFrame.from_dict({'seedSet':seedSet, 'seedState':seedState, 'state':state, 'random':random})
print(df)
  • 输出2:*
random     seedSet   seedState       state
0       8  1558056443  1558056443  1558056443
1       3  1558056443  1558056443  1391218083
2       7  1558056443  1558056443  2754892524
3      -8  1558056443  1558056443  1971852777
4       4  1558056443  1558056443  2881604748

看到区别了吗?输出1和输出2的np.random.get_state()[1][0]相同,但输出的其余部分不同(最重要的是,随机数不相同)。因此,正如阿里已经明确表示的那样:
因此,不可能将每个RNG状态Map到唯一的整数种子。

csbfibhn

csbfibhn3#

检查np.random.get_state()返回的数组的第一个元素,在我看来它就是随机种子。

sulc1iza

sulc1iza4#

这一回答补充了其他人忽略的重要细节。首先,重新表述一下结论:

原始随机种子(通过np.random.seed设置)在生成数字后无法取回,但中间体(当前状态)可以取回。

请参考@Vestland的答案;然而,它可能会误导:生成的数字不同并不是因为无法Map状态,而是因为使用了不完整的编码get_state()[1]。完整的表示包括pos = get_state()[2]。要说明以下情况:

import numpy as np

state0 = np.random.get_state()
rand0  = np.random.randint(0, 10, 1)
state1 = np.random.get_state()
rand1  = np.random.randint(0, 10, 1)

assert all(s0 == s1 for s0, s1 in zip(state0[1], state1[1]))

我们生成了一个数字,但get_state()[1]保持不变。但是:

np.random.set_state(state0)
assert np.random.randint(0, 10, 1) == rand0

对于state1rand1也是如此。因此,@Vestland的数字不同,因为当不设置种子时,pos = 623-而如果我们使用np.random.seedpos = 624。为什么会有这样不方便的差异呢?毫无头绪。
np.random.seed(s)上总结如下:

  • get_state()[1][0]设置后立即:检索准确重新创建状态的s
  • 生成数字后的get_state()[1][0]:可能检索也可能不检索s,但它将重新创建当前状态(在get_state())
  • 生成多个数字后的get_state()[1][0]:不会检索s。这是因为pos用尽了它的表示。
  • get_state() at any point:将准确地重新创建该点

最后,行为也可能因get_state()[3:](当然还有[0])而不同。

zwghvu4y

zwghvu4y5#

虽然最上面的答案大体上是正确的,因为这在总体上是不可能的,但实际上它是可能的。我会将你重定向到这个人的博客:https://kamila.akagi.moe/posts/mersenne-twister/
这个人开发了一种Mersenne Twister破解算法来恢复初始种子,并提供了详细的细节和算法。我不是作者,我不了解这些材料的全部内容,但任何有兴趣做这件事的人都应该检查一下。

nr9pn0ug

nr9pn0ug6#

了解随机种子的一个简单解决方案是随机生成一个种子,然后对随机数生成器进行种子生成。类似于以下内容:

import numpy as np
seed = int(np.random.rand() * (2**32 - 1))
np.random.seed(seed)

相关问题