Skip to content

Commit cf62eec

Browse files
committed
Upstream rebase
2 parents d869838 + c4ddd7d commit cf62eec

File tree

4 files changed

+49
-48
lines changed

4 files changed

+49
-48
lines changed

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Learn Bayesian statistics with a book together with PyMC3:
5353
- `PyMC3 port of the book "Doing Bayesian Data Analysis" by John Kruschke <https://github.com/aloctavodia/Doing_bayesian_data_analysis>`__ as well as the `second edition <https://github.com/JWarmenhoven/DBDA-python>`__: Principled introduction to Bayesian data analysis.
5454
- `PyMC3 port of the book "Statistical Rethinking A Bayesian Course with Examples in R and Stan" by Richard McElreath <https://github.com/pymc-devs/resources/tree/master/Rethinking>`__
5555
- `PyMC3 port of the book "Bayesian Cognitive Modeling" by Michael Lee and EJ Wagenmakers <https://github.com/pymc-devs/resources/tree/master/BCM>`__: Focused on using Bayesian statistics in cognitive modeling.
56-
- `Bayesian Analysis with Python by Osvaldo Martin <https://www.packtpub.com/big-data-and-business-intelligence/bayesian-analysis-python>`__ (and `errata <https://github.com/aloctavodia/BAP>`__): Great introductory book.
56+
- `Bayesian Analysis with Python <https://www.packtpub.com/big-data-and-business-intelligence/bayesian-analysis-python-second-edition>`__ (second edition) by Osvaldo Martin: Great introductory book. (`code <https://github.com/aloctavodia/BAP>`__ and errata).
5757

5858
PyMC3 talks
5959
-----------

pymc3/distributions/multivariate.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -775,7 +775,7 @@ def WishartBartlett(name, S, nu, is_cholesky=False, return_cholesky=False, testv
775775
-----
776776
This is not a standard Distribution class but follows a similar
777777
interface. Besides the Wishart distribution, it will add RVs
778-
c and z to your model which make up the matrix.
778+
name_c and name_z to your model which make up the matrix.
779779
780780
This distribution is usually a bad idea to use as a prior for multivariate
781781
normal. You should instead use LKJCholeskyCov or LKJCorr.
@@ -797,11 +797,11 @@ def WishartBartlett(name, S, nu, is_cholesky=False, return_cholesky=False, testv
797797
diag_testval = None
798798
tril_testval = None
799799

800-
c = tt.sqrt(ChiSquared('c', nu - np.arange(2, 2 + n_diag), shape=n_diag,
800+
c = tt.sqrt(ChiSquared('%s_c' % name, nu - np.arange(2, 2 + n_diag), shape=n_diag,
801801
testval=diag_testval))
802-
pm._log.info('Added new variable c to model diagonal of Wishart.')
803-
z = Normal('z', 0., 1., shape=n_tril, testval=tril_testval)
804-
pm._log.info('Added new variable z to model off-diagonals of Wishart.')
802+
pm._log.info('Added new variable %s_c to model diagonal of Wishart.' % name)
803+
z = Normal('%s_z' % name, 0., 1., shape=n_tril, testval=tril_testval)
804+
pm._log.info('Added new variable %s_z to model off-diagonals of Wishart.' % name)
805805
# Construct A matrix
806806
A = tt.zeros(S.shape, dtype=np.float32)
807807
A = tt.set_subtensor(A[diag_idx], c)

pymc3/sampling.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from six import integer_types
88
from joblib import Parallel, delayed
9-
from tempfile import mkdtemp
109
import numpy as np
1110
import theano.gradient as tg
1211

@@ -245,7 +244,8 @@ def sample(draws=500, step=None, init='auto', n_init=200000, start=None, trace=N
245244
chains : int
246245
The number of chains to sample. Running independent chains is important for some
247246
convergence statistics and can also reveal multiple modes in the posterior. If `None`,
248-
then set to either `cores` or 2, whichever is larger. For SMC the default value is 100.
247+
then set to either `cores` or 2, whichever is larger. For SMC the number of chains is the
248+
number of draws.
249249
cores : int
250250
The number of chains to run in parallel. If `None`, set to the number of CPUs in the
251251
system, but at most 4 (for 'SMC' defaults to 1). Keep in mind that some chains might
@@ -323,7 +323,6 @@ def sample(draws=500, step=None, init='auto', n_init=200000, start=None, trace=N
323323
if isinstance(step, pm.step_methods.smc.SMC):
324324
if step_kwargs is None:
325325
step_kwargs = {}
326-
test_folder = mkdtemp(prefix='SMC_TEST')
327326
trace = smc.sample_smc(draws=draws,
328327
step=step,
329328
progressbar=progressbar,
@@ -1523,4 +1522,4 @@ def init_nuts(init='auto', chains=1, n_init=500000, model=None,
15231522

15241523
step = pm.NUTS(potential=potential, model=model, **kwargs)
15251524

1526-
return start, step
1525+
return start, step

pymc3/step_methods/smc.py

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import theano
66
import pymc3 as pm
77
from tqdm import tqdm
8-
import warnings
98

109
from .arraystep import metrop_select
1110
from .metropolis import MultivariateNormalProposal
@@ -17,8 +16,6 @@
1716

1817
__all__ = ["SMC", "sample_smc"]
1918

20-
proposal_dists = {"MultivariateNormal": MultivariateNormalProposal}
21-
2219

2320
class SMC:
2421
"""
@@ -27,20 +24,24 @@ class SMC:
2724
Parameters
2825
----------
2926
n_steps : int
30-
The number of steps of a Markov Chain. If `tune == True` `n_steps` will be used for
31-
the first stage, and the number of steps of the other states will be determined
27+
The number of steps of a Markov Chain. If `tune_steps == True` `n_steps` will be used for
28+
the first stage and the number of steps of the other stages will be determined
3229
automatically based on the acceptance rate and `p_acc_rate`.
30+
The number of steps will never be larger than `n_steps`.
3331
scaling : float
3432
Factor applied to the proposal distribution i.e. the step size of the Markov Chain. Only
35-
works if `tune == False` otherwise is determined automatically
33+
works if `tune_scaling == False` otherwise is determined automatically.
3634
p_acc_rate : float
37-
Probability of not accepting a Markov Chain proposal. Used to compute `n_steps` when
38-
`tune == True`. It should be between 0 and 1.
39-
proposal_name :
40-
Type of proposal distribution. Currently the only valid option is `MultivariateNormal`.
35+
Used to compute `n_steps` when `tune_steps == True`. The higher the value of `p_acc_rate`
36+
the higher the number of steps computed automatically. Defaults to 0.99. It should be
37+
between 0 and 1.
38+
tune_scaling : bool
39+
Whether to compute the scaling automatically or not. Defaults to True
40+
tune_steps : bool
41+
Whether to compute the number of steps automatically or not. Defaults to True
4142
threshold : float
4243
Determines the change of beta from stage to stage, i.e.indirectly the number of stages,
43-
the higher the value of threshold the higher the number of stages. Defaults to 0.5.
44+
the higher the value of `threshold` the higher the number of stages. Defaults to 0.5.
4445
It should be between 0 and 1.
4546
model : :class:`pymc3.Model`
4647
Optional model for sampling step. Defaults to None (taken from context).
@@ -63,17 +64,18 @@ def __init__(
6364
self,
6465
n_steps=25,
6566
scaling=1.0,
66-
p_acc_rate=0.01,
67-
tune=True,
68-
proposal_name="MultivariateNormal",
67+
p_acc_rate=0.99,
68+
tune_scaling=True,
69+
tune_steps=True,
6970
threshold=0.5,
7071
):
7172

7273
self.n_steps = n_steps
74+
self.max_steps = n_steps
7375
self.scaling = scaling
74-
self.p_acc_rate = p_acc_rate
75-
self.tune = tune
76-
self.proposal = proposal_dists[proposal_name]
76+
self.p_acc_rate = 1 - p_acc_rate
77+
self.tune_scaling = tune_scaling
78+
self.tune_steps = tune_steps
7779
self.threshold = threshold
7880

7981

@@ -95,15 +97,15 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
9597
random_seed : int
9698
random seed
9799
"""
98-
warnings.warn("Warning: SMC is experimental, hopefully it will be ready for PyMC 3.6")
99100
model = modelcontext(model)
100101

101102
if random_seed != -1:
102103
np.random.seed(random_seed)
103104

104-
beta = 0
105+
beta = 0.
105106
stage = 0
106-
acc_rate = 1
107+
acc_rate = 1.
108+
proposed = draws * step.n_steps
107109
model.marginal_likelihood = 1
108110
variables = inputvars(model.vars)
109111
discrete = np.concatenate([[v.dtype in pm.discrete_types] * (v.dsize or 1) for v in variables])
@@ -128,31 +130,32 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
128130

129131
# compute proposal distribution based on weights
130132
covariance = _calc_covariance(posterior, weights)
131-
proposal = step.proposal(covariance)
132-
133-
# compute scaling and number of Markov chains steps (optional), based on previous
134-
# acceptance rate
135-
if step.tune and stage > 0:
136-
if acc_rate == 0:
137-
acc_rate = 1.0 / step.n_steps
138-
step.scaling = _tune(acc_rate)
139-
step.n_steps = 1 + int(np.log(step.p_acc_rate) / np.log(1 - acc_rate))
133+
proposal = MultivariateNormalProposal(covariance)
134+
135+
# compute scaling (optional) and number of Markov chains steps (optional), based on the
136+
# acceptance rate of the previous stage
137+
if (step.tune_scaling or step.tune_steps) and stage > 0:
138+
if step.tune_scaling:
139+
step.scaling = _tune(acc_rate)
140+
if step.tune_steps:
141+
acc_rate = max(1. / proposed, acc_rate)
142+
step.n_steps = min(
143+
step.max_steps, 1 + int(np.log(step.p_acc_rate) / np.log(1 - acc_rate))
144+
)
140145

141146
pm._log.info(
142-
"Stage: {:d} Beta: {:f} Steps: {:d} Acc: {:f}".format(
143-
stage, beta, step.n_steps, acc_rate
144-
)
147+
"Stage: {:d} Beta: {:f} Steps: {:d}".format(stage, beta, step.n_steps, acc_rate)
145148
)
146149
# Apply Metropolis kernel (mutation)
147-
proposed = 0.0
148-
accepted = 0.0
150+
proposed = draws * step.n_steps
151+
accepted = 0.
149152
priors = np.array([prior_logp(sample) for sample in posterior]).squeeze()
150153
tempered_post = priors + likelihoods * beta
151154
for draw in tqdm(range(draws), disable=not progressbar):
152155
old_tempered_post = tempered_post[draw]
153156
q_old = posterior[draw]
154157
deltas = np.squeeze(proposal(step.n_steps) * step.scaling)
155-
for n_step in range(0, step.n_steps):
158+
for n_step in range(step.n_steps):
156159
delta = deltas[n_step]
157160

158161
if any_discrete:
@@ -170,10 +173,9 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
170173

171174
q_old, accept = metrop_select(new_tempered_post - old_tempered_post, q_new, q_old)
172175
if accept:
173-
accepted += accept
176+
accepted += 1
174177
posterior[draw] = q_old
175178
old_tempered_post = new_tempered_post
176-
proposed += 1.0
177179

178180
acc_rate = accepted / proposed
179181
stage += 1
@@ -258,7 +260,7 @@ def _calc_covariance(posterior, weights):
258260
"""
259261
cov = np.cov(posterior, aweights=weights.ravel(), bias=False, rowvar=0)
260262
if np.isnan(cov).any() or np.isinf(cov).any():
261-
raise ValueError('Sample covariances not valid! Likely "chains" is too small!')
263+
raise ValueError('Sample covariances not valid! Likely "draws" is too small!')
262264
return np.atleast_2d(cov)
263265

264266

0 commit comments

Comments
 (0)