Skip to content Skip to sidebar Skip to footer

Can I Create A Local Numpy Random Seed?

There is a function, foo, that uses the np.random functionality. I want to control the seed that foo uses, but without actually changing the function itself. How do I do this? Esse

Solution 1:

You could keep the global random state in a temporary variable and reset it once your function is done:

import contextlib
import numpy as np

@contextlib.contextmanagerdeftemp_seed(seed):
    state = np.random.get_state()
    np.random.seed(seed)
    try:
        yieldfinally:
        np.random.set_state(state)

Demo:

>>>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])

Solution 2:

I assume the idea is that calls to bar() should when given a starting seed always see the same sequence of random numbers; regardless of how many calls to foo()are inserted in-between.

We can do this by creating a random seed from the random state that we use to re-seed when the temporary seeded state is done. This can be wrapped in a context manager:

import numpy as np

classtemporary_seed:
    def__init__(self, seed):
        self.seed = seed
        self.backup = Nonedef__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)

Let's try this with

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: 6foo()  # foo: 3bar()  # bar: 9

So we get bar-sequence [0, 9] and foo-sequence [6, 3].

We try again without re-seeding globally:

bar()  # bar: 1withtemporary_seed(42):
    foo()  # foo: 6
    foo()  # foo: 3
bar()  # bar: 2

New bar-sequence [1, 2] and same foo-sequence again [6, 3].

Once again with same global seed, but a different seed for foo:

np.random.seed(999)

bar()  # bar: 0withtemporary_seed(0):
    foo()  # foo: 5
bar()  # bar: 9

This time we get the first bar-sequence again [0, 9] and a different foo. Nice!

So where is the catch? By entering and leaving the temorary seed part we change the random state. We do so deterministically and the results are repeatable, but if we get a different sequence if we don't call enter temorary_seed:

np.random.seed(999)

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

bar-sequence [0, 5] instead of [0, 9]. If you can live with that limitation this approach should work.

Post a Comment for "Can I Create A Local Numpy Random Seed?"