Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't tune DEMetropolis by default #3743

Merged
merged 2 commits into from
Dec 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New features
- use [fastprogress](https://github.com/fastai/fastprogress) instead of tqdm [#3693](https://github.com/pymc-devs/pymc3/pull/3693)
- `DEMetropolis` can now tune both `lambda` and `scaling` parameters, but by default neither of them are tuned. See [#3743](https://github.com/pymc-devs/pymc3/pull/3743) for more info.

## PyMC3 3.8 (November 29 2019)

Expand Down
19 changes: 12 additions & 7 deletions pymc3/step_methods/metropolis.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,8 @@ class DEMetropolis(PopulationArrayStepShared):
S (and n). Defaults to Uniform(-S,+S).
scaling : scalar or array
Initial scale factor for epsilon. Defaults to 0.001
tune : bool
Flag for tuning the scaling. Defaults to True.
tune : str
Which hyperparameter to tune. Defaults to None, but can also be 'scaling' or 'lambda'.
michaelosthege marked this conversation as resolved.
Show resolved Hide resolved
tune_interval : int
The frequency of tuning. Defaults to 100 iterations.
model : PyMC Model
Expand All @@ -536,10 +536,11 @@ class DEMetropolis(PopulationArrayStepShared):
'accepted': np.bool,
'tune': np.bool,
'scaling': np.float64,
'lambda': np.float64,
}]

def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.001,
tune=True, tune_interval=100, model=None, mode=None, **kwargs):
tune=None, tune_interval=100, model=None, mode=None, **kwargs):

model = pm.modelcontext(model)

Expand All @@ -549,7 +550,7 @@ def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.0

if S is None:
S = np.ones(model.ndim)

if proposal_dist is not None:
self.proposal_dist = proposal_dist(S)
else:
Expand All @@ -559,6 +560,8 @@ def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.0
if lamb is None:
lamb = 2.38 / np.sqrt(2 * model.ndim)
self.lamb = float(lamb)
if not tune in {None, 'scaling', 'lambda'}:
raise ValueError('The parameter "tune" must be one of {None, scaling, lambda}')
self.tune = tune
self.tune_interval = tune_interval
self.steps_until_tune = tune_interval
Expand All @@ -572,9 +575,10 @@ def __init__(self, vars=None, S=None, proposal_dist=None, lamb=None, scaling=0.0

def astep(self, q0):
if not self.steps_until_tune and self.tune:
# Tune scaling parameter
self.scaling = tune(
self.scaling, self.accepted / float(self.tune_interval))
if self.tune == 'scaling':
self.scaling = tune(self.scaling, self.accepted / float(self.tune_interval))
elif self.tune == 'lambda':
self.lamb = tune(self.lamb, self.accepted / float(self.tune_interval))
# Reset counter
self.steps_until_tune = self.tune_interval
self.accepted = 0
Expand All @@ -598,6 +602,7 @@ def astep(self, q0):
stats = {
'tune': self.tune,
'scaling': self.scaling,
'lambda': self.lamb,
'accept': np.exp(accept),
'accepted': accepted
}
Expand Down
18 changes: 18 additions & 0 deletions pymc3/tests/test_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,24 @@ def test_demcmc_warning_on_small_populations(self):
)
pass

def test_demcmc_tune_parameter(self):
"""Tests that validity of the tune setting is checked"""
with Model() as model:
Normal("n", mu=0, sigma=1, shape=(2,3))

step = DEMetropolis()
assert step.tune is None

step = DEMetropolis(tune='scaling')
assert step.tune == 'scaling'

step = DEMetropolis(tune='lambda')
assert step.tune == 'lambda'

with pytest.raises(ValueError):
DEMetropolis(tune='foo')
pass

def test_nonparallelized_chains_are_random(self):
with Model() as model:
x = Normal("x", 0, 1)
Expand Down