如何检索 NumPy 随机数生成器的当前种子?
How can I retrieve the current seed of NumPy's random number generator?
下面导入 NumPy 并设置种子。
import numpy as np
np.random.seed(42)
不过,我对播种不感兴趣,更感兴趣的是阅读它。 random.get_state()
好像没有种子。 documentation 没有给出明显的答案。
如果我没有手动设置,如何检索 numpy.random
使用的当前种子?
我想使用当前种子来进行下一次流程迭代。
简短的回答是你根本不能(至少一般情况下不能)。
numpy 使用的 Mersenne Twister RNG 有 219937-1 种可能的内部状态,而单个 64 位整数只有 264 可能的值。因此不可能将每个 RNG 状态映射到唯一的整数种子。
您可以直接使用np.random.get_state
and np.random.set_state
获取和设置RNG的内部状态。 get_state
的输出是一个元组,其第二个元素是一个 (624,)
32 位整数数组。这个数组有足够多的位来表示 RNG 的每个可能的内部状态 (2624 * 32 > 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]
检查 np.random.get_state()
返回的数组的第一个元素,对我来说似乎正是随机种子。
此贡献旨在澄清ali_m的正确答案,并作为对Dong Justin建议的重要修正。
这些是我的发现:
- 使用
np.random.seed(X)
设置随机种子后,您 可以 使用 np.random.get_state()[1][0]
. 再次找到它
- 不过,它对你用处不大。
以下代码部分的输出将向您展示为什么这两个陈述都是正确的。
语句 1 - 您可以使用 np.random.get_state()[1][0]
.
找到随机种子
如果使用 np.random.seed(123)
设置随机种子,则可以使用 state = np.random.get_state()
将随机状态检索为元组。下面是 state
的详细信息(我在 Spyder 中使用变量浏览器)。我正在使用屏幕截图,因为使用 print(state)
会淹没您的控制台,因为元组第二个元素中的数组大小。
您可以轻松地将 123
视为第二个元素中包含的数组中的第一个数字。使用 seed = np.random.get_state()[1][0]
将 给你 123
。完美的?不完全是,因为:
声明 2 - 但是,它对您的用处不大:
起初看起来可能不是这样,因为您可以使用np.random.seed(123)
,使用[=22=检索相同的数字],使用[重置种子=26=],然后(貌似)用 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
下的第一个数字相同。我本可以将其打印为 stand-alone 数字,但我想将其全部保存在同一个地方。另请注意,到目前为止,seedSet = 123
和 np.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
。按照 Dong Justins 回答的逻辑(以及我自己在此编辑之前的回答),您可以使用 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
看出区别了吗? np.random.get_state()[1][0]
对于输出 1 和输出 2 是相同的,但输出的其余部分不同(最重要的是随机数不相同)。因此,正如 ali_m 已经明确指出的那样:
It's therefore impossible to map every RNG state to a unique integer seed.
这个答案补充了其他人遗漏的重要细节。首先,改一下结论:
Original random seeds (set via np.random.seed
) cannot be retrieved after generating numbers, but intermediates (current state) can.
参考@vestland的回答;然而,它可能会误导:生成的数字不同不是因为无法映射状态,而是因为使用了 不完整的编码: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
state1
和 rand1
也是如此。因此,@vestland 的数字不同,因为当不设置种子时,pos = 623
- 而如果我们使用 np.random.seed
,pos = 624
。为什么不方便的差异?没头绪。
总结 np.random.seed(s)
:
get_state()[1][0]
设置后立即:检索 s
完全重新创建状态
get_state()[1][0]
生成数字后:可能会或可能不会检索 s
,但它会 不会 重新创建 current 状态(在 get_state()
)
get_state()[1][0]
生成多个数字后:将不会检索 s
。这是因为 pos
耗尽了它的表示。
get_state()
在任何时候:将完全重新创建 那个点。
最后,行为也可能因 get_state()[3:]
(当然还有 [0]
)而不同。
虽然最上面的答案说的大体上是正确的,因为一般不可能,但实际上是可能的。我会将您重定向到此人的博客:https://kamila.akagi.moe/posts/mersenne-twister/
此人开发了梅森扭曲破解算法来恢复初始种子,并提供了完整的细节和算法。我不是作者,不明白 material 的全部内容,但任何对此感兴趣的人都应该检查一下。
下面导入 NumPy 并设置种子。
import numpy as np
np.random.seed(42)
不过,我对播种不感兴趣,更感兴趣的是阅读它。 random.get_state()
好像没有种子。 documentation 没有给出明显的答案。
如果我没有手动设置,如何检索 numpy.random
使用的当前种子?
我想使用当前种子来进行下一次流程迭代。
简短的回答是你根本不能(至少一般情况下不能)。
numpy 使用的 Mersenne Twister RNG 有 219937-1 种可能的内部状态,而单个 64 位整数只有 264 可能的值。因此不可能将每个 RNG 状态映射到唯一的整数种子。
您可以直接使用np.random.get_state
and np.random.set_state
获取和设置RNG的内部状态。 get_state
的输出是一个元组,其第二个元素是一个 (624,)
32 位整数数组。这个数组有足够多的位来表示 RNG 的每个可能的内部状态 (2624 * 32 > 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]
检查 np.random.get_state()
返回的数组的第一个元素,对我来说似乎正是随机种子。
此贡献旨在澄清ali_m的正确答案,并作为对Dong Justin建议的重要修正。
这些是我的发现:
- 使用
np.random.seed(X)
设置随机种子后,您 可以 使用np.random.get_state()[1][0]
. 再次找到它
- 不过,它对你用处不大。
以下代码部分的输出将向您展示为什么这两个陈述都是正确的。
语句 1 - 您可以使用 np.random.get_state()[1][0]
.
如果使用 np.random.seed(123)
设置随机种子,则可以使用 state = np.random.get_state()
将随机状态检索为元组。下面是 state
的详细信息(我在 Spyder 中使用变量浏览器)。我正在使用屏幕截图,因为使用 print(state)
会淹没您的控制台,因为元组第二个元素中的数组大小。
您可以轻松地将 123
视为第二个元素中包含的数组中的第一个数字。使用 seed = np.random.get_state()[1][0]
将 给你 123
。完美的?不完全是,因为:
声明 2 - 但是,它对您的用处不大:
起初看起来可能不是这样,因为您可以使用np.random.seed(123)
,使用[=22=检索相同的数字],使用[重置种子=26=],然后(貌似)用 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
下的第一个数字相同。我本可以将其打印为 stand-alone 数字,但我想将其全部保存在同一个地方。另请注意,到目前为止,seedSet = 123
和 np.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
。按照 Dong Justins 回答的逻辑(以及我自己在此编辑之前的回答),您可以使用 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
看出区别了吗? np.random.get_state()[1][0]
对于输出 1 和输出 2 是相同的,但输出的其余部分不同(最重要的是随机数不相同)。因此,正如 ali_m 已经明确指出的那样:
It's therefore impossible to map every RNG state to a unique integer seed.
这个答案补充了其他人遗漏的重要细节。首先,改一下结论:
Original random seeds (set via
np.random.seed
) cannot be retrieved after generating numbers, but intermediates (current state) can.
参考@vestland的回答;然而,它可能会误导:生成的数字不同不是因为无法映射状态,而是因为使用了 不完整的编码: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
state1
和 rand1
也是如此。因此,@vestland 的数字不同,因为当不设置种子时,pos = 623
- 而如果我们使用 np.random.seed
,pos = 624
。为什么不方便的差异?没头绪。
总结 np.random.seed(s)
:
get_state()[1][0]
设置后立即:检索s
完全重新创建状态get_state()[1][0]
生成数字后:可能会或可能不会检索s
,但它会 不会 重新创建 current 状态(在get_state()
)get_state()[1][0]
生成多个数字后:将不会检索s
。这是因为pos
耗尽了它的表示。get_state()
在任何时候:将完全重新创建 那个点。
最后,行为也可能因 get_state()[3:]
(当然还有 [0]
)而不同。
虽然最上面的答案说的大体上是正确的,因为一般不可能,但实际上是可能的。我会将您重定向到此人的博客:https://kamila.akagi.moe/posts/mersenne-twister/
此人开发了梅森扭曲破解算法来恢复初始种子,并提供了完整的细节和算法。我不是作者,不明白 material 的全部内容,但任何对此感兴趣的人都应该检查一下。