0
# Advanced Variational Methods
1
2
Containers for advanced variational approximation methods including Pathfinder algorithm and Laplace approximation. These methods provide fast approximate inference alternatives to full MCMC.
3
4
## Capabilities
5
6
### CmdStanPathfinder
7
8
Container for Pathfinder algorithm results, which provides fast variational approximation using multiple optimization paths.
9
10
```python { .api }
11
class CmdStanPathfinder:
12
def draws(self):
13
"""
14
Get approximate posterior draws from Pathfinder.
15
16
Returns:
17
np.ndarray: Posterior draws (draws, parameters)
18
"""
19
20
def stan_variable(self, var):
21
"""
22
Get draws for specific Stan variable.
23
24
Parameters:
25
- var (str): Variable name
26
27
Returns:
28
np.ndarray: Draws for the variable
29
"""
30
31
def stan_variables(self):
32
"""
33
Get all Stan variables as dictionary.
34
35
Returns:
36
dict: Mapping from variable names to draw arrays
37
"""
38
39
def method_variables(self):
40
"""
41
Get Pathfinder diagnostic variables.
42
43
Returns:
44
dict: Diagnostic information from Pathfinder runs
45
"""
46
47
def create_inits(self, seed=None, chains=4):
48
"""
49
Create initial values by sampling from Pathfinder approximation.
50
51
Parameters:
52
- seed (int, optional): Random seed
53
- chains (int): Number of initial value sets to create
54
55
Returns:
56
list or dict: Initial value dictionaries for MCMC chains
57
"""
58
59
def save_csvfiles(self, dir=None):
60
"""
61
Save CSV output files to directory.
62
63
Parameters:
64
- dir (str or PathLike, optional): Target directory
65
66
Returns:
67
None
68
"""
69
```
70
71
**Pathfinder Properties:**
72
73
```python { .api }
74
pathfinder.metadata # InferenceMetadata: Run configuration and timing
75
pathfinder.column_names # Tuple[str, ...]: Parameter names
76
pathfinder.is_resampled # bool: Whether PSIS resampling was used
77
```
78
79
**Pathfinder Usage Examples:**
80
81
```python
82
# Run Pathfinder with multiple paths
83
pf = model.pathfinder(data=data, num_paths=8, draws=2000)
84
85
# Use for approximate inference
86
theta_approx = pf.stan_variable("theta")
87
print(f"Approximate posterior mean: {theta_approx.mean()}")
88
89
# Create initial values for MCMC
90
inits = pf.create_inits(seed=12345, chains=4)
91
mcmc_fit = model.sample(data=data, inits=inits, chains=4)
92
93
# Check diagnostics
94
diagnostics = pf.method_variables()
95
print("Pathfinder diagnostics:", diagnostics.keys())
96
```
97
98
### CmdStanLaplace
99
100
Container for Laplace approximation results, providing multivariate normal approximation around a posterior mode.
101
102
```python { .api }
103
class CmdStanLaplace:
104
def draws(self):
105
"""
106
Get approximate posterior draws from Laplace approximation.
107
108
Returns:
109
np.ndarray: Posterior draws (draws, parameters)
110
"""
111
112
def draws_pd(self, vars=None):
113
"""
114
Get draws as pandas DataFrame.
115
116
Parameters:
117
- vars (list of str, optional): Specific variables to include
118
119
Returns:
120
pd.DataFrame: Draws with parameter names
121
"""
122
123
def draws_xr(self, vars=None):
124
"""
125
Get draws as xarray Dataset.
126
127
Parameters:
128
- vars (list of str, optional): Specific variables to include
129
130
Returns:
131
xr.Dataset: Draws with coordinate labels
132
"""
133
134
def stan_variable(self, var):
135
"""
136
Get draws for specific Stan variable.
137
138
Parameters:
139
- var (str): Variable name
140
141
Returns:
142
np.ndarray: Draws for the variable
143
"""
144
145
def stan_variables(self):
146
"""
147
Get all Stan variables as dictionary.
148
149
Returns:
150
dict: Mapping from variable names to draw arrays
151
"""
152
153
def method_variables(self):
154
"""
155
Get diagnostic variables.
156
157
Returns:
158
dict: Diagnostic information including Jacobian
159
"""
160
161
def save_csvfiles(self, dir=None):
162
"""
163
Save CSV output files to directory.
164
165
Parameters:
166
- dir (str or PathLike, optional): Target directory
167
168
Returns:
169
None
170
"""
171
```
172
173
**Laplace Properties:**
174
175
```python { .api }
176
laplace.metadata # InferenceMetadata: Run configuration and timing
177
laplace.column_names # Tuple[str, ...]: Parameter names
178
laplace.mode # CmdStanMLE: Mode around which approximation is centered
179
```
180
181
**Laplace Usage Examples:**
182
183
```python
184
# First find the mode
185
mle = model.optimize(data=data)
186
187
# Run Laplace approximation around the mode
188
laplace = model.laplace_sample(data=data, mode=mle, draws=1000)
189
190
# Access approximation
191
theta_laplace = laplace.stan_variable("theta")
192
print(f"Laplace approximation mean: {theta_laplace.mean()}")
193
194
# Get mode information
195
mode_params = laplace.mode.optimized_params_dict()
196
print(f"Mode at: {mode_params}")
197
198
# Compare with xarray format
199
draws_xr = laplace.draws_xr()
200
print("Laplace draws structure:", draws_xr)
201
```
202
203
## Advanced Usage Patterns
204
205
### Pathfinder for MCMC Initialization
206
207
```python
208
# Use Pathfinder to generate good initial values
209
pf = model.pathfinder(data=data, num_paths=8)
210
211
# Create multiple initialization strategies
212
inits_list = []
213
for i in range(4): # 4 chains
214
inits_list.append(pf.create_inits(seed=i, chains=1))
215
216
# Run MCMC with Pathfinder initialization
217
mcmc = model.sample(
218
data=data,
219
inits=inits_list,
220
chains=4,
221
iter_warmup=500, # May need less warmup with good inits
222
iter_sampling=1000
223
)
224
```
225
226
### Approximation Quality Assessment
227
228
```python
229
# Compare Pathfinder, Laplace, and MCMC
230
pf = model.pathfinder(data=data, num_paths=4, draws=2000)
231
mle = model.optimize(data=data)
232
laplace = model.laplace_sample(data=data, mode=mle, draws=2000)
233
mcmc = model.sample(data=data, chains=4, iter_sampling=500)
234
235
# Compare posterior means
236
theta_pf = pf.stan_variable("theta").mean()
237
theta_laplace = laplace.stan_variable("theta").mean()
238
theta_mcmc = mcmc.stan_variable("theta").mean(axis=(0,1))
239
240
print(f"Pathfinder mean: {theta_pf}")
241
print(f"Laplace mean: {theta_laplace}")
242
print(f"MCMC mean: {theta_mcmc}")
243
244
# Compare uncertainties
245
print(f"Pathfinder std: {pf.stan_variable('theta').std()}")
246
print(f"Laplace std: {laplace.stan_variable('theta').std()}")
247
print(f"MCMC std: {mcmc.stan_variable('theta').std()}")
248
```
249
250
### Hierarchical Workflow
251
252
```python
253
# Stage 1: Fast approximation with Pathfinder
254
pf = model.pathfinder(data=data, num_paths=8)
255
256
# Stage 2: Refine with Laplace if unimodal
257
mle = model.optimize(data=data, inits=pf.create_inits(chains=1))
258
laplace = model.laplace_sample(data=data, mode=mle, draws=1000)
259
260
# Stage 3: Full MCMC for final inference (if needed)
261
mcmc = model.sample(
262
data=data,
263
inits=laplace.stan_variables(), # Use Laplace mean as init
264
chains=4
265
)
266
267
# Compare computational costs and accuracy
268
print("Pathfinder time:", pf.metadata.time_total)
269
print("Laplace time:", laplace.metadata.time_total)
270
print("MCMC time:", mcmc.metadata.time_total)
271
```
272
273
### Model Selection with Approximations
274
275
```python
276
models = {
277
"simple": CmdStanModel(stan_file="simple.stan"),
278
"complex": CmdStanModel(stan_file="complex.stan")
279
}
280
281
# Fast model comparison using Pathfinder
282
results = {}
283
for name, model in models.items():
284
pf = model.pathfinder(data=data, num_paths=4)
285
286
# Estimate log marginal likelihood (approximate)
287
log_lik = pf.method_variables().get("lp__", np.array([]))
288
if len(log_lik) > 0:
289
results[name] = {
290
"pathfinder": pf,
291
"approx_log_ml": np.mean(log_lik)
292
}
293
294
# Select best model for full analysis
295
best_model = max(results.keys(), key=lambda k: results[k]["approx_log_ml"])
296
print(f"Best model (approximate): {best_model}")
297
298
# Run full MCMC on selected model
299
final_fit = models[best_model].sample(data=data)
300
```