83

以下导入 NumPy 并设置种子。

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

但是,我对设置种子不感兴趣,而对阅读它更感兴趣。random.get_state()似乎没有种子。该文档没有显示明显的答案。

numpy.random假设我没有手动设置它,我如何检索 使用的当前种子?

我想使用当前的种子来延续流程的下一次迭代。

4

5 回答 5

98

简短的回答是你根本不能(至少一般来说不能)。

numpy 使用的Mersenne Twister RNG 有 2 19937 -1 个可能的内部状态,而单个 64 位整数只有 2 64 个可能值。因此,不可能将每个 RNG 状态映射到唯一的整数种子。

可以np.random.get_state使用和直接获取和设置 RNG 的内部状态np.random.set_state。的输出get_state是一个元组,其第二个元素是一个(624,)32 位整数数组。这个数组有足够多的位来表示 RNG 的每个可能的内部状态 (2 624 * 32 > 2 19937 -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]
于 2015-08-24T00:06:06.373 回答
33

此贡献旨在澄清 ali_m 的正确答案,并作为对 Dong Justin 建议的重要更正。


这些是我的发现:

  1. 使用设置随机种子后,np.random.seed(X)可以使用 再次找到它np.random.get_state()[1][0]
  2. 但是,它对您几乎没有用处。

以下代码部分的输出将向您展示为什么这两个语句都是正确的。


声明 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),用 检索相同的数字,用seed = np.random.get_state()[1][0]重置种子np.random.seed(444),然后(似乎)123用 将其设置回场景np.random.seed(seed)。但是你之前已经知道你的随机种子什么,所以你不需要那样做。下一个代码部分还将显示您不能使用任何随机状态的第一个数字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

看到不同?np.random.get_state()[1][0]输出 1 和输出 2 相同,但输出的其余部分不同(最重要的是随机数不相同)。因此,正如 ali_m 已经明确指出的那样:

因此,不可能将每个 RNG 状态映射到唯一的整数种子。

于 2018-04-10T09:00:40.140 回答
2

这个答案补充了其他人错过的重要细节。首先,重新表述结论:

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

请参阅@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,但不会重新创建当前状态(at get_state()
  • get_state()[1][0]生成许多​​数字后:不会检索s. 这是因为pos用尽了它的代表性。
  • get_state()在任何时候:将完全重新创建该点

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

于 2020-08-10T13:21:04.620 回答
2

检查由返回的数组的第一个元素,np.random.get_state()对我来说似乎正是随机种子。

于 2018-03-01T15:37:25.757 回答
1

虽然最佳答案所说的通常是正确的,但一般来说这是不可能的,实际上是可能的。我会将您重定向到此人的博客:https ://kamila.akagi.moe/posts/mersenne-twister/

此人开发了一种梅森捻线机破解算法来恢复初始种子,并提供了完整的细节和算法。我不是作者,也不完全理解材料是什么,但是任何有兴趣这样做的人都应该检查一下。

于 2021-09-06T13:42:32.793 回答