Skip to content

Commit 17bf7a4

Browse files
authored
Use numpy.random's Generator instead of legacy RandomState (#821)
Updated tests to use fixed RNG algorithms where seed is important
1 parent 12499e4 commit 17bf7a4

26 files changed

+94
-87
lines changed

docs/templates/getting-started/minimizing_functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ date-times, you'll be fine.
8484
them as attachments.
8585

8686
**HINT:** If you need to replicate the results of the stochastic search (e.g. for a demonstration),
87-
pass an object of type `np.random.RandomState` into the `fmin` function, using the `rstate` optional parameter.
87+
pass an object of type `np.random.Generator` into the `fmin` function, using the `rstate` optional parameter.
8888

8989
Writing the function above in dictionary-returning style, it
9090
would look like this:

hyperopt/algobase.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ def __init__(self, domain, trials, seed):
223223
n: l for l, n in list(self.domain.vh.vals_by_label().items())
224224
}
225225
self._seed = seed
226-
self.rng = np.random.RandomState(seed)
226+
self.rng = np.random.default_rng(seed)
227227

228228
def __call__(self, new_id):
229-
self.rng.seed(self._seed + new_id)
229+
self.rng = np.random.default_rng(self._seed + new_id)
230230
memo = self.eval_nodes(
231231
memo={self.domain.s_new_ids: [new_id], self.domain.s_rng: self.rng}
232232
)
@@ -246,7 +246,7 @@ def on_node(self, memo, node):
246246

247247
def batch(self, new_ids):
248248
new_ids = list(new_ids)
249-
self.rng.seed([self._seed] + new_ids)
249+
self.rng = np.random.default_rng([self._seed] + new_ids)
250250
memo = self.eval_nodes(
251251
memo={self.domain.s_new_ids: new_ids, self.domain.s_rng: self.rng}
252252
)

hyperopt/atpe.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ def __init__(self):
698698
def recommendNextParameters(
699699
self, hyperparameterSpace, results, currentTrials, lockedValues=None
700700
):
701-
rstate = numpy.random.RandomState(seed=int(random.randint(1, 2 ** 32 - 1)))
701+
rstate = numpy.random.default_rng(seed=int(random.randint(1, 2 ** 32 - 1)))
702702

703703
params = {"param": {}}
704704

hyperopt/criteria.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def EI_gaussian_empirical(mean, var, thresh, rng, N):
1919
2020
(estimated empirically)
2121
"""
22-
return EI_empirical(rng.randn(N) * np.sqrt(var) + mean, thresh)
22+
return EI_empirical(rng.standard_normal(N) * np.sqrt(var) + mean, thresh)
2323

2424

2525
def EI_gaussian(mean, var, thresh):

hyperopt/fmin.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ def get_n_unfinished():
276276
# `new_trials`. This is the core of `run`, all the rest is just
277277
# processes orchestration
278278
new_trials = algo(
279-
new_ids, self.domain, trials, self.rstate.randint(2 ** 31 - 1)
279+
new_ids, self.domain, trials, self.rstate.integers(2 ** 31 - 1)
280280
)
281281
assert len(new_ids) >= len(new_trials)
282282

@@ -441,11 +441,11 @@ def fmin(
441441
a trials object, then that trials object will be affected by
442442
side-effect of this call.
443443
444-
rstate : numpy.RandomState, default numpy.random or `$HYPEROPT_FMIN_SEED`
444+
rstate : numpy.random.Generator, default numpy.random or `$HYPEROPT_FMIN_SEED`
445445
Each call to `algo` requires a seed value, which should be different
446446
on each call. This object is used to draw these seeds via `randint`.
447447
The default rstate is
448-
`numpy.random.RandomState(int(env['HYPEROPT_FMIN_SEED']))`
448+
`numpy.random.default_rng(int(env['HYPEROPT_FMIN_SEED']))`
449449
if the `HYPEROPT_FMIN_SEED` environment variable is set to a non-empty
450450
string, otherwise np.random is used in whatever state it is in.
451451
@@ -513,9 +513,9 @@ def fmin(
513513
if rstate is None:
514514
env_rseed = os.environ.get("HYPEROPT_FMIN_SEED", "")
515515
if env_rseed:
516-
rstate = np.random.RandomState(int(env_rseed))
516+
rstate = np.random.default_rng(int(env_rseed))
517517
else:
518-
rstate = np.random.RandomState()
518+
rstate = np.random.default_rng()
519519

520520
validate_timeout(timeout)
521521
validate_loss_threshold(loss_threshold)

hyperopt/ipy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def fmin(self, fn, space, **kw):
136136

137137
if idles:
138138
new_ids = self.new_trial_ids(len(idles))
139-
new_trials = algo(new_ids, domain, self, rstate.randint(2 ** 31 - 1))
139+
new_trials = algo(new_ids, domain, self, rstate.integers(2 ** 31 - 1))
140140
if len(new_trials) == 0:
141141
break
142142
assert len(idles) >= len(new_trials)

hyperopt/mix.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ def suggest(new_ids, domain, trials, seed, p_suggest):
2525
sum(probabilities) must be [close to] 1.0
2626
2727
"""
28-
rng = np.random.RandomState(seed)
28+
rng = np.random.default_rng(seed)
2929
ps, suggests = list(zip(*p_suggest))
3030
assert len(ps) == len(suggests) == len(p_suggest)
3131
if not np.isclose(sum(ps), 1.0):
3232
raise ValueError("Probabilities should sum to 1", ps)
3333
idx = rng.multinomial(n=1, pvals=ps).argmax()
34-
return suggests[idx](new_ids, domain, trials, seed=rng.randint(2 ** 31))
34+
return suggests[idx](new_ids, domain, trials, seed=rng.integers(2 ** 31))

hyperopt/pyll/stochastic.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def implicit_stochastic(f):
2424

2525
@scope.define
2626
def rng_from_seed(seed):
27-
return np.random.RandomState(seed)
27+
return np.random.default_rng(seed)
2828

2929

3030
# -- UNIFORM
@@ -95,9 +95,9 @@ def qlognormal(mu, sigma, q, rng=None, size=()):
9595
def randint(low, high=None, rng=None, size=()):
9696
"""
9797
See np.random.randint documentation.
98-
rng = random number generator, typically equals np.random.mtrand.RandomState
98+
rng = random number generator, typically equals np.random.Generator
9999
"""
100-
return rng.randint(low, high, size)
100+
return rng.integers(low, high, size)
101101

102102

103103
@implicit_stochastic
@@ -107,7 +107,7 @@ def randint_via_categorical(p, rng=None, size=()):
107107
Only used in tpe because of the chaotic API based on names.
108108
# ideally we would just use randint above, but to use priors this is a wrapper of
109109
categorical
110-
rng = random number generator, typically equals np.random.mtrand.RandomState
110+
rng = random number generator, typically equals np.random.Generator
111111
"""
112112

113113
return scope.categorical(p, rng, size)
@@ -177,7 +177,7 @@ def recursive_set_rng_kwarg(expr, rng=None):
177177
uniform(0, 1) -> uniform(0, 1, rng=rng)
178178
"""
179179
if rng is None:
180-
rng = np.random.RandomState()
180+
rng = np.random.default_rng()
181181
lrng = as_apply(rng)
182182
for node in dfs(expr):
183183
if node.name in implicit_stochastic_symbols:
@@ -195,14 +195,14 @@ def sample(expr, rng=None, **kwargs):
195195
Parameters:
196196
expr - a pyll expression to be evaluated
197197
198-
rng - a np.random.RandomState instance
199-
default: `np.random.RandomState()`
198+
rng - a np.random.Generator instance
199+
default: `np.random.default_rng()`
200200
201201
**kwargs - optional arguments passed along to
202202
`hyperopt.pyll.rec_eval`
203203
204204
"""
205205
if rng is None:
206-
rng = np.random.RandomState()
206+
rng = np.random.default_rng()
207207
foo = recursive_set_rng_kwarg(clone(as_apply(expr)), as_apply(rng))
208208
return rec_eval(foo, **kwargs)

hyperopt/pyll/tests/test_stochastic.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
def test_recursive_set_rng_kwarg():
88
uniform = scope.uniform
99
a = as_apply([uniform(0, 1), uniform(2, 3)])
10-
rng = np.random.RandomState(234)
10+
rng = np.random.default_rng(234)
1111
recursive_set_rng_kwarg(a, rng)
1212
print(a)
1313
val_a = rec_eval(a)
@@ -46,16 +46,16 @@ def test_lnorm():
4646
def test_sample_deterministic():
4747
aa = as_apply([0, 1])
4848
print(aa)
49-
dd = sample(aa, np.random.RandomState(3))
49+
dd = sample(aa, np.random.default_rng(3))
5050
assert dd == (0, 1)
5151

5252

5353
def test_repeatable():
5454
u = scope.uniform(0, 1)
5555
aa = as_apply(dict(u=u, n=scope.normal(5, 0.1), l=[0, 1, scope.one_of(2, 3), u]))
56-
dd1 = sample(aa, np.random.RandomState(3))
57-
dd2 = sample(aa, np.random.RandomState(3))
58-
dd3 = sample(aa, np.random.RandomState(4))
56+
dd1 = sample(aa, np.random.default_rng(3))
57+
dd2 = sample(aa, np.random.default_rng(3))
58+
dd3 = sample(aa, np.random.default_rng(4))
5959
assert dd1 == dd2
6060
assert dd1 != dd3
6161

@@ -64,7 +64,7 @@ def test_sample():
6464
u = scope.uniform(0, 1)
6565
aa = as_apply(dict(u=u, n=scope.normal(5, 0.1), l=[0, 1, scope.one_of(2, 3), u]))
6666
print(aa)
67-
dd = sample(aa, np.random.RandomState(3))
67+
dd = sample(aa, np.random.default_rng(3))
6868
assert 0 < dd["u"] < 1
6969
assert 4 < dd["n"] < 6
7070
assert dd["u"] == dd["l"][3]

hyperopt/rand.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
def suggest(new_ids, domain, trials, seed):
15-
rng = np.random.RandomState(seed)
15+
rng = np.random.default_rng(seed)
1616
rval = []
1717
for ii, new_id in enumerate(new_ids):
1818
# -- sample new specs, idxs, vals
@@ -28,7 +28,7 @@ def suggest(new_ids, domain, trials, seed):
2828

2929
def suggest_batch(new_ids, domain, trials, seed):
3030

31-
rng = np.random.RandomState(seed)
31+
rng = np.random.default_rng(seed)
3232
# -- sample new specs, idxs, vals
3333
idxs, vals = pyll.rec_eval(
3434
domain.s_idxs_vals, memo={domain.s_new_ids: new_ids, domain.s_rng: rng}

0 commit comments

Comments
 (0)