Skip to content

Commit 7cd66b7

Browse files
aloctavodiaJunpeng Lao
authored andcommitted
SMC: work with transformed variables (pymc-devs#2749)
* SMC: work with transformed variables * minor fix * add to release notes
1 parent 75d1ce0 commit 7cd66b7

File tree

3 files changed

+40
-33
lines changed

3 files changed

+40
-33
lines changed

RELEASE-NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- Add test for `model.logp_array` and `model.bijection` (#2724)
2626
- Fixed `sample_ppc` and `sample_ppc_w` to iterate all chains(#2633, #2748)
2727
- Add Bayesian R2 score (for GLMs) `stats.r2_score` (#2696) and test (#2729).
28+
- SMC works with transformed variables (#2749)
2829

2930

3031
## PyMC3 3.2 (October 10, 2017)

pymc3/step_methods/smc.py

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,10 @@
3131

3232
__all__ = ['SMC', 'sample_smc']
3333

34-
EXPERIMENTAL_WARNING = "Warning: SMC is an experimental step method, and not yet"\
35-
" recommended for use in PyMC3!"
34+
EXPERIMENTAL_WARNING = ("Warning: SMC is an experimental step method, and not yet "
35+
"recommended for use in PyMC3!")
3636

37-
proposal_dists = {
38-
'MultivariateNormal': MultivariateNormalProposal,
39-
}
37+
proposal_dists = {'MultivariateNormal': MultivariateNormalProposal}
4038

4139

4240
def choose_proposal(proposal_name, scale=1.):
@@ -117,7 +115,9 @@ def __init__(self, vars=None, out_vars=None, n_chains=100, scaling=1., covarianc
117115
likelihood_name='like', proposal_name='MultivariateNormal', tune=True,
118116
tune_interval=100, coef_variation=1., check_bound=True, model=None,
119117
random_seed=-1):
118+
120119
warnings.warn(EXPERIMENTAL_WARNING)
120+
121121
if random_seed != -1:
122122
nr.seed(random_seed)
123123

@@ -183,8 +183,19 @@ def __init__(self, vars=None, out_vars=None, n_chains=100, scaling=1., covarianc
183183
# create initial population
184184
self.population = []
185185
self.array_population = np.zeros(n_chains)
186-
for _ in range(self.n_chains):
187-
self.population.append(pm.Point({v.name: v.random() for v in vars}, model=model))
186+
187+
init_rnd = {}
188+
for v in vars:
189+
if pm.util.is_transformed_name(v.name):
190+
trans = v.distribution.transform_used.forward
191+
rnd = trans(v.distribution.dist.random(size=self.n_chains))
192+
init_rnd[v.name] = rnd.eval()
193+
else:
194+
init_rnd[v.name] = v.random(size=self.n_chains)
195+
196+
for i in range(self.n_chains):
197+
self.population.append(pm.Point({v.name: init_rnd[v.name][i] for v in vars},
198+
model=model))
188199

189200
self.chain_previous_lpoint = copy.deepcopy(self.population)
190201

@@ -332,15 +343,13 @@ def select_end_points(self, mtrace):
332343

333344
# collect end points of each chain and put into array
334345
for var, slc, shp, _ in self.ordering.vmap:
335-
slc_population = mtrace.get_values(varname=var, burn=n_steps - 1, combine=True)
346+
slc_population = mtrace.get_values(varname=var, burn=n_steps-1, combine=True)
336347
if len(shp) == 0:
337348
array_population[:, slc] = np.atleast_2d(slc_population).T
338349
else:
339350
array_population[:, slc] = slc_population
340351
# get likelihoods
341-
likelihoods = mtrace.get_values(varname=self.likelihood_name,
342-
burn=n_steps - 1,
343-
combine=True)
352+
likelihoods = mtrace.get_values(varname=self.likelihood_name, burn=n_steps-1, combine=True)
344353

345354
# map end array_endpoints to dict points
346355
population = [self.bij.rmap(row) for row in array_population]
@@ -363,7 +372,7 @@ def get_chain_previous_lpoint(self, mtrace):
363372
array_population = np.zeros((self.n_chains, self.lordering.size))
364373
n_steps = len(mtrace)
365374
for _, slc, shp, _, var in self.lordering.vmap:
366-
slc_population = mtrace.get_values(varname=var, burn=n_steps - 1, combine=True)
375+
slc_population = mtrace.get_values(varname=var, burn=n_steps-1, combine=True)
367376
if len(shp) == 0:
368377
array_population[:, slc] = np.atleast_2d(slc_population).T
369378
else:
@@ -414,7 +423,8 @@ def resample(self):
414423

415424

416425
def sample_smc(n_steps, n_chains=100, step=None, start=None, homepath=None, stage=0, n_jobs=1,
417-
tune_interval=10, tune=None, progressbar=False, model=None, random_seed=-1, rm_flag=True):
426+
tune_interval=10, tune=None, progressbar=False, model=None, random_seed=-1,
427+
rm_flag=True):
418428
"""Sequential Monte Carlo sampling
419429
420430
Samples the solution space with n_chains of Metropolis chains, where each
@@ -504,11 +514,11 @@ def sample_smc(n_steps, n_chains=100, step=None, start=None, homepath=None, stag
504514
step.population = start
505515

506516
if not any(step.likelihood_name in var.name for var in model.deterministics):
507-
raise TypeError('Model (deterministic) variables need to contain a variable %s '
508-
'as defined in `step`.' % step.likelihood_name)
517+
raise TypeError('Model (deterministic) variables need to contain a variable {} as defined '
518+
'in `step`.'.format(step.likelihood_name))
509519

510520
step.n_steps = int(n_steps)
511-
521+
512522
stage_handler = atext.TextStage(homepath)
513523

514524
if progressbar and n_jobs > 1:
@@ -539,21 +549,19 @@ def sample_smc(n_steps, n_chains=100, step=None, start=None, homepath=None, stag
539549

540550
# Metropolis sampling intermediate stages
541551
chains = stage_handler.clean_directory(step.stage, chains, rm_flag)
542-
sample_args = {
543-
'draws': draws,
544-
'step': step,
545-
'stage_path': stage_handler.stage_path(step.stage),
546-
'progressbar': progressbar,
547-
'model': model,
548-
'n_jobs': n_jobs,
549-
'chains': chains}
552+
sample_args = {'draws': draws,
553+
'step': step,
554+
'stage_path': stage_handler.stage_path(step.stage),
555+
'progressbar': progressbar,
556+
'model': model,
557+
'n_jobs': n_jobs,
558+
'chains': chains}
550559

551560
_iter_parallel_chains(**sample_args)
552561

553562
mtrace = stage_handler.load_multitrace(step.stage)
554563

555-
step.population, step.array_population, step.likelihoods = step.select_end_points(
556-
mtrace)
564+
step.population, step.array_population, step.likelihoods = step.select_end_points(mtrace)
557565
step.beta, step.old_beta, step.weights, sj = step.calc_beta()
558566
step.sjs *= sj
559567

@@ -602,8 +610,8 @@ def sample_smc(n_steps, n_chains=100, step=None, start=None, homepath=None, stag
602610
model=model)
603611

604612

605-
def _sample(draws, step=None, start=None, trace=None, chain=0, tune=None,
606-
progressbar=True, model=None, random_seed=-1):
613+
def _sample(draws, step=None, start=None, trace=None, chain=0, tune=None, progressbar=True,
614+
model=None, random_seed=-1):
607615

608616
sampling = _iter_sample(draws, step, start, trace, chain,
609617
tune, model, random_seed)

pymc3/tests/test_smc.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ def setup_class(self):
1818
super(TestSMC, self).setup_class()
1919
self.test_folder = mkdtemp(prefix='ATMIP_TEST')
2020

21-
self.n_chains = 1000
22-
self.n_steps = 10
21+
self.n_chains = 100
22+
self.n_steps = 20
2323
self.tune_interval = 25
2424

2525
n = 4
26-
2726
mu1 = np.ones(n) * (1. / 2)
2827
mu2 = -mu1
2928

@@ -49,8 +48,7 @@ def two_gaussians(x):
4948
shape=n,
5049
lower=-2. * np.ones_like(mu1),
5150
upper=2. * np.ones_like(mu1),
52-
testval=-1. * np.ones_like(mu1),
53-
transform=None)
51+
testval=-1. * np.ones_like(mu1))
5452
llk = pm.Potential('muh', two_gaussians(X))
5553

5654
self.step = smc.SMC(

0 commit comments

Comments
 (0)