Python:使用上下文管理器临时更改随机种子的危险?

Bon*_*vie 6 python random numpy contextmanager random-seed

当使用随机数生成器在Python代码中重现性时,推荐的方法似乎是构造单独的RandomState对象.不幸的是,像scipy.stats这样的基本软件包不能(据我所知)设置为使用特定的RandomState,而只使用numpy.random的当前状态.我目前的解决方法是使用上下文管理器来保存RNG的状态,然后在退出时重置它,如下所示:

class FixedSeed:
    def __init__(self, seed):
        self.seed = seed
        self.state = None

    def __enter__(self):
        self.state = rng.get_state()
        np.random.seed(self.seed)

    def __exit__(self, exc_type, exc_value, traceback):
        np.random.set_state(self.state)
Run Code Online (Sandbox Code Playgroud)

文档中有很多关于以任何方式更改状态的警告 - 上述方法一般是安全的吗?(从某种意义上说,更改是上下文的本地更改,而我的其余代码将不受影响)

msw*_*msw 4

numpy文档声称:

set_state 和 get_state 不需要处理 NumPy 中的任何随机分布。如果手动改变内部状态,用户应该确切地知道他/她在做什么。

这听起来确实很可怕。在公共、有记录的界面上对此警告的可能解释是“确切地知道”意味着“知道随意重新播种 PRNG 会严重降低随机性”。但您知道您希望非常具体地针对您的上下文时期减少随机性。

为了支持这个猜想,我查看了numpy/test_random.py其中包含如下代码:

class TestSeed(TestCase):
    def test_scalar(self):
        s = np.random.RandomState(0)
        assert_equal(s.randint(1000), 684)
        s = np.random.RandomState(4294967295)
        assert_equal(s.randint(1000), 419)
Run Code Online (Sandbox Code Playgroud)

因为他们确实需要确定性结果。请注意,他们创建了一个实例np.random.RandomState,但我在代码中找不到任何set_state()会破坏任何内容的指示。

如果有疑问,请编写一个测试套件

  1. 将默认 RNG 设置为固定值
  2. 检查默认 RNG 每次都返回相同的预期值
  3. 使用你的上下文管理器
  4. 确认生成了新的值序列
  5. 确认 (1) 中的原始种子 RNG 继续发出其预期序列