9
9
10
10
from .arraystep import metrop_select
11
11
from .metropolis import MultivariateNormalProposal
12
- from ..theanof import floatX , make_shared_replacements , join_nonshared_inputs
12
+ from ..theanof import floatX , make_shared_replacements , join_nonshared_inputs , inputvars
13
13
from ..model import modelcontext
14
14
from ..backends .ndarray import NDArray
15
15
from ..backends .base import MultiTrace
16
16
17
17
18
- __all__ = [' SMC' , ' sample_smc' ]
18
+ __all__ = [" SMC" , " sample_smc" ]
19
19
20
- proposal_dists = {' MultivariateNormal' : MultivariateNormalProposal }
20
+ proposal_dists = {" MultivariateNormal" : MultivariateNormalProposal }
21
21
22
22
23
- class SMC () :
23
+ class SMC :
24
24
"""
25
25
Sequential Monte Carlo step
26
26
@@ -59,8 +59,15 @@ class SMC():
59
59
%282007%29133:7%28816%29>`__
60
60
"""
61
61
62
- def __init__ (self , n_steps = 5 , scaling = 1. , p_acc_rate = 0.01 , tune = True ,
63
- proposal_name = 'MultivariateNormal' , threshold = 0.5 ):
62
+ def __init__ (
63
+ self ,
64
+ n_steps = 25 ,
65
+ scaling = 1.0 ,
66
+ p_acc_rate = 0.01 ,
67
+ tune = True ,
68
+ proposal_name = "MultivariateNormal" ,
69
+ threshold = 0.5 ,
70
+ ):
64
71
65
72
self .n_steps = n_steps
66
73
self .scaling = scaling
@@ -98,15 +105,15 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
98
105
stage = 0
99
106
acc_rate = 1
100
107
model .marginal_likelihood = 1
101
- variables = model .vars
108
+ variables = inputvars ( model .vars )
102
109
discrete = np .concatenate ([[v .dtype in pm .discrete_types ] * (v .dsize or 1 ) for v in variables ])
103
110
any_discrete = discrete .any ()
104
111
all_discrete = discrete .all ()
105
112
shared = make_shared_replacements (variables , model )
106
113
prior_logp = logp_forw ([model .varlogpt ], variables , shared )
107
114
likelihood_logp = logp_forw ([model .datalogpt ], variables , shared )
108
115
109
- pm ._log .info (' Sample initial stage: ...' )
116
+ pm ._log .info (" Sample initial stage: ..." )
110
117
posterior , var_info = _initial_population (draws , model , variables )
111
118
112
119
while beta < 1 :
@@ -127,15 +134,18 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
127
134
# acceptance rate
128
135
if step .tune and stage > 0 :
129
136
if acc_rate == 0 :
130
- acc_rate = 1. / step .n_steps
137
+ acc_rate = 1.0 / step .n_steps
131
138
step .scaling = _tune (acc_rate )
132
139
step .n_steps = 1 + int (np .log (step .p_acc_rate ) / np .log (1 - acc_rate ))
133
140
134
- pm ._log .info ('Stage: {:d} Beta: {:f} Steps: {:d} Acc: {:f}' .format (stage , beta ,
135
- step .n_steps , acc_rate ))
141
+ pm ._log .info (
142
+ "Stage: {:d} Beta: {:f} Steps: {:d} Acc: {:f}" .format (
143
+ stage , beta , step .n_steps , acc_rate
144
+ )
145
+ )
136
146
# Apply Metropolis kernel (mutation)
137
- proposed = 0.
138
- accepted = 0.
147
+ proposed = 0.0
148
+ accepted = 0.0
139
149
priors = np .array ([prior_logp (sample ) for sample in posterior ]).squeeze ()
140
150
tempered_post = priors + likelihoods * beta
141
151
for draw in tqdm (range (draws ), disable = not progressbar ):
@@ -147,12 +157,12 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
147
157
148
158
if any_discrete :
149
159
if all_discrete :
150
- delta = np .round (delta , 0 ).astype (' int64' )
151
- q_old = q_old .astype (' int64' )
152
- q_new = (q_old + delta ).astype (' int64' )
160
+ delta = np .round (delta , 0 ).astype (" int64" )
161
+ q_old = q_old .astype (" int64" )
162
+ q_new = (q_old + delta ).astype (" int64" )
153
163
else :
154
164
delta [discrete ] = np .round (delta [discrete ], 0 )
155
- q_new = (q_old + delta )
165
+ q_new = floatX (q_old + delta )
156
166
else :
157
167
q_new = floatX (q_old + delta )
158
168
@@ -163,12 +173,12 @@ def sample_smc(draws=5000, step=None, progressbar=False, model=None, random_seed
163
173
accepted += accept
164
174
posterior [draw ] = q_old
165
175
old_tempered_post = new_tempered_post
166
- proposed += 1.
176
+ proposed += 1.0
167
177
168
178
acc_rate = accepted / proposed
169
179
stage += 1
170
180
171
- trace = _posterior_to_trace (posterior , model , var_info )
181
+ trace = _posterior_to_trace (posterior , variables , model , var_info )
172
182
173
183
return trace
174
184
@@ -177,6 +187,7 @@ def _initial_population(draws, model, variables):
177
187
"""
178
188
Create an initial population from the prior
179
189
"""
190
+
180
191
population = []
181
192
var_info = {}
182
193
start = model .test_point
@@ -188,7 +199,7 @@ def _initial_population(draws, model, variables):
188
199
point = pm .Point ({v .name : init_rnd [v .name ][i ] for v in variables }, model = model )
189
200
population .append (model .dict_to_array (point ))
190
201
191
- return np .array (population ), var_info
202
+ return np .array (floatX ( population ) ), var_info
192
203
193
204
194
205
def _calc_beta (beta , likelihoods , threshold = 0.5 ):
@@ -219,11 +230,11 @@ def _calc_beta(beta, likelihoods, threshold=0.5):
219
230
Partial marginal likelihood
220
231
"""
221
232
low_beta = old_beta = beta
222
- up_beta = 2.
233
+ up_beta = 2.0
223
234
rN = int (len (likelihoods ) * threshold )
224
235
225
236
while up_beta - low_beta > 1e-6 :
226
- new_beta = (low_beta + up_beta ) / 2.
237
+ new_beta = (low_beta + up_beta ) / 2.0
227
238
weights_un = np .exp ((new_beta - old_beta ) * (likelihoods - likelihoods .max ()))
228
239
weights = weights_un / np .sum (weights_un )
229
240
ESS = int (1 / np .sum (weights ** 2 ))
@@ -241,11 +252,11 @@ def _calc_beta(beta, likelihoods, threshold=0.5):
241
252
return new_beta , old_beta , weights , np .mean (sj )
242
253
243
254
244
- def _calc_covariance (posterior_array , weights ):
255
+ def _calc_covariance (posterior , weights ):
245
256
"""
246
257
Calculate trace covariance matrix based on importance weights.
247
258
"""
248
- cov = np .cov (np . squeeze ( posterior_array ) , aweights = weights .ravel (), bias = False , rowvar = 0 )
259
+ cov = np .cov (posterior , aweights = weights .ravel (), bias = False , rowvar = 0 )
249
260
if np .isnan (cov ).any () or np .isinf (cov ).any ():
250
261
raise ValueError ('Sample covariances not valid! Likely "chains" is too small!' )
251
262
return np .atleast_2d (cov )
@@ -264,18 +275,18 @@ def _tune(acc_rate):
264
275
-------
265
276
scaling: float
266
277
"""
267
- # a and b after Muto & Beck 2008 .
268
- a = 1. / 9
269
- b = 8. / 9
278
+ # a and b after Muto & Beck 2008.
279
+ a = 1.0 / 9
280
+ b = 8.0 / 9
270
281
return (a + b * acc_rate ) ** 2
271
282
272
283
273
- def _posterior_to_trace (posterior , model , var_info ):
284
+ def _posterior_to_trace (posterior , variables , model , var_info ):
274
285
"""
275
286
Save results into a PyMC3 trace
276
287
"""
277
288
lenght_pos = len (posterior )
278
- varnames = [v .name for v in model . vars ]
289
+ varnames = [v .name for v in variables ]
279
290
280
291
with model :
281
292
strace = NDArray (model )
@@ -285,7 +296,7 @@ def _posterior_to_trace(posterior, model, var_info):
285
296
size = 0
286
297
for var in varnames :
287
298
shape , new_size = var_info [var ]
288
- value .append (posterior [i ][size : size + new_size ].reshape (shape ))
299
+ value .append (posterior [i ][size : size + new_size ].reshape (shape ))
289
300
size += new_size
290
301
strace .record ({k : v for k , v in zip (varnames , value )})
291
302
return MultiTrace ([strace ])
0 commit comments