【问题标题】:Can I create a local numpy random seed?我可以创建一个本地 numpy 随机种子吗?
【发布时间】:2018-09-08 09:46:02
【问题描述】:

有一个函数foo,它使用np.random 功能。 我想控制foo 使用的种子,但实际上并没有改变函数本身。 我该怎么做?

基本上我想要这样的东西:

bar() # should have normal seed
with np.random.seed(0): # Doesn't work
    foo()
bar() # should have normal seed

解决方案如 this:

rng = random.Random(42)
number = rng.randint(10, 20)

在这种情况下不起作用,因为我无法访问 foo 的内部工作(或者我错过了什么??)。

【问题讨论】:

  • 我不认为这是重复的,因为 rng = random.Random(42); number = rng.randint(10, 20) 解决方案在这种情况下不起作用,因为我无法访问 foo 的内部工作。
  • 当时我没有正确阅读,抱歉。我的猜测是用种子开始一个新的过程。让我尝试一些东西。

标签: python numpy random scope


【解决方案1】:

我认为这个想法是当给定一个起始种子时,对bar() 的调用应该总是看到相同的随机数序列;不管中间插入了多少对foo()的调用。

我们可以通过从随机状态创建一个随机种子来做到这一点,当临时播种状态完成时,我们使用该随机种子重新播种。这可以包装在上下文管理器中:

import numpy as np

class temporary_seed:
    def __init__(self, seed):
        self.seed = seed
        self.backup = None

    def __enter__(self):
        self.backup = np.random.randint(2**32-1, dtype=np.uint32)
        np.random.seed(self.seed)

    def __exit__(self, *_):
        np.random.seed(self.backup)

让我们试试这个

def bar():
    print('bar:', np.random.randint(10))

def foo():
    print('foo:', np.random.randint(10))

np.random.seed(999)

bar()  # bar: 0
with temporary_seed(42):
    foo()  # foo: 6
    foo()  # foo: 3
bar()  # bar: 9

所以我们得到 bar-sequence [0, 9] 和 foo-sequence [6, 3]。

我们在不重新全局播种的情况下重试:

bar()  # bar: 1
with temporary_seed(42):
    foo()  # foo: 6
    foo()  # foo: 3
bar()  # bar: 2

新的 bar-sequence [1, 2] 和相同的 foo-sequence 再次 [6, 3]。

再次使用相同的全局种子,但 foo 的种子不同:

np.random.seed(999)

bar()  # bar: 0
with temporary_seed(0):
    foo()  # foo: 5
bar()  # bar: 9

这次我们再次得到第一个 bar-sequence [0, 9] 和一个不同的 foo。不错!

那么问题在哪里?通过进入和离开临时种子部分,我们改变了随机状态。我们这样做是确定性的,结果是可重复的,但是如果我们不调用输入temorary_seed,则得到不同的序列:

np.random.seed(999)

bar()  # bar: 0
bar()  # bar: 5

条形序列 [0, 5] 而不是 [0, 9]。如果您可以忍受这种限制,那么这种方法应该可行。

【讨论】:

  • 我不明白self.backup = np.random.randint(2**32-1, dtype=np.uint32)。你能解释一下吗?
  • @Toke Faurby 它创建一个全范围整数随机数,在离开上下文时用作种子。
【解决方案2】:

您可以将全局随机状态保存在一个临时变量中,并在您的函数完成后将其重置:

import contextlib
import numpy as np

@contextlib.contextmanager
def temp_seed(seed):
    state = np.random.get_state()
    np.random.seed(seed)
    try:
        yield
    finally:
        np.random.set_state(state)

演示:

>>> np.random.seed(0)
>>> np.random.randn(3)
array([1.76405235, 0.40015721, 0.97873798])
>>> np.random.randn(3)
array([ 2.2408932 ,  1.86755799, -0.97727788])

>>> np.random.seed(0)
>>> np.random.randn(3)
array([1.76405235, 0.40015721, 0.97873798])
>>> with temp_seed(5):
...     np.random.randn(3)                                                                                        
array([ 0.44122749, -0.33087015,  2.43077119])
>>> np.random.randn(3)
array([ 2.2408932 ,  1.86755799, -0.97727788])

【讨论】:

  • 啊不错..get/set_state :) 这当然有全局状态保持不变的好处。
  • 你可能想要一个 try / finally 在那里,这样即使在使用此上下文管理器的 with 块中引发了异常,随机状态也会得到恢复。
  • @MarkDickinson 已修复。再次感谢。
猜你喜欢
  • 2019-03-15
  • 2014-06-14
  • 2023-03-13
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
相关资源
最近更新 更多