Skip to content

Commit 9f5f676

Browse files
michaelosthegejunpenglao
authored andcommitted
Change tune method to not act inplace plus more sampler stats (#3732)
* add regression test to demo #3731 * return new array and don't touch original in tune method + see #3731 * add 'accepted' and 'scaling' to (DE)Metropolis sampler stats * use existing model.ndim property for code clarity
1 parent a1a33e3 commit 9f5f676

File tree

2 files changed

+25
-10
lines changed

2 files changed

+25
-10
lines changed

pymc3/step_methods/metropolis.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ class Metropolis(ArrayStepShared):
9393
generates_stats = True
9494
stats_dtypes = [{
9595
'accept': np.float64,
96+
'accepted': np.bool,
9697
'tune': np.bool,
98+
'scaling': np.float64,
9799
}]
98100

99101
def __init__(self, vars=None, S=None, proposal_dist=None, scaling=1.,
@@ -166,7 +168,9 @@ def astep(self, q0):
166168

167169
stats = {
168170
'tune': self.tune,
171+
'scaling': self.scaling,
169172
'accept': np.exp(accept),
173+
'accepted': accepted,
170174
}
171175

172176
return q_new, [stats]
@@ -191,26 +195,24 @@ def tune(scale, acc_rate):
191195
>0.95 x 10
192196
193197
"""
194-
195-
# Switch statement
196198
if acc_rate < 0.001:
197199
# reduce by 90 percent
198-
scale *= 0.1
200+
return scale * 0.1
199201
elif acc_rate < 0.05:
200202
# reduce by 50 percent
201-
scale *= 0.5
203+
return scale * 0.5
202204
elif acc_rate < 0.2:
203205
# reduce by ten percent
204-
scale *= 0.9
206+
return scale * 0.9
205207
elif acc_rate > 0.95:
206208
# increase by factor of ten
207-
scale *= 10.0
209+
return scale * 10.0
208210
elif acc_rate > 0.75:
209211
# increase by double
210-
scale *= 2.0
212+
return scale * 2.0
211213
elif acc_rate > 0.5:
212214
# increase by ten percent
213-
scale *= 1.1
215+
return scale * 1.1
214216

215217
return scale
216218

@@ -531,7 +533,9 @@ class DEMetropolis(PopulationArrayStepShared):
531533
generates_stats = True
532534
stats_dtypes = [{
533535
'accept': np.float64,
536+
'accepted': np.bool,
534537
'tune': np.bool,
538+
'scaling': np.float64,
535539
}]
536540

537541
def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.001,
@@ -544,7 +548,7 @@ def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.0
544548
vars = pm.inputvars(vars)
545549

546550
if S is None:
547-
S = np.ones(sum(v.dsize for v in vars))
551+
S = np.ones(model.ndim)
548552

549553
if proposal_dist is not None:
550554
self.proposal_dist = proposal_dist(S)
@@ -553,7 +557,7 @@ def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.0
553557

554558
self.scaling = np.atleast_1d(scaling).astype('d')
555559
if lamb is None:
556-
lamb = 2.38 / np.sqrt(2 * S.size)
560+
lamb = 2.38 / np.sqrt(2 * model.ndim)
557561
self.lamb = float(lamb)
558562
self.tune = tune
559563
self.tune_interval = tune_interval
@@ -593,7 +597,9 @@ def astep(self, q0):
593597

594598
stats = {
595599
'tune': self.tune,
600+
'scaling': self.scaling,
596601
'accept': np.exp(accept),
602+
'accepted': accepted
597603
}
598604

599605
return q_new, [stats]

pymc3/tests/test_tuning.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
from numpy import inf
3+
from pymc3.step_methods.metropolis import tune
34
from pymc3.tuning import scaling, find_MAP
45
from . import models
56

@@ -32,3 +33,11 @@ def test_mle_jacobian():
3233
map_estimate = find_MAP(method="BFGS", model=model)
3334

3435
np.testing.assert_allclose(map_estimate["mu_i"], truth, rtol=rtol)
36+
37+
38+
def test_tune_not_inplace():
39+
orig_scaling = np.array([0.001, 0.1])
40+
returned_scaling = tune(orig_scaling, acc_rate=0.6)
41+
assert not returned_scaling is orig_scaling
42+
assert np.all(orig_scaling == np.array([0.001, 0.1]))
43+
pass

0 commit comments

Comments
 (0)