Skip to content

Commit 5c3e541

Browse files
authored
replace find_constrained_prior (#694)
1 parent 5501dfd commit 5c3e541

File tree

6 files changed

+3678
-3698
lines changed

6 files changed

+3678
-3698
lines changed

examples/gaussian_processes/HSGP-Advanced.ipynb

Lines changed: 701 additions & 627 deletions
Large diffs are not rendered by default.

examples/gaussian_processes/HSGP-Advanced.myst.md

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ jupytext:
55
format_name: myst
66
format_version: 0.13
77
kernelspec:
8-
display_name: pymc-examples
8+
display_name: pymc
99
language: python
10-
name: pymc-examples
10+
name: python3
1111
---
1212

1313
(hsgp-advanced)=
@@ -44,6 +44,7 @@ A secondary goal of this implementation is flexibility via an accessible impleme
4444
import arviz as az
4545
import matplotlib.pyplot as plt
4646
import numpy as np
47+
import preliz as pz
4748
import pymc as pm
4849
import pytensor.tensor as pt
4950
```
@@ -140,7 +141,9 @@ cov_mu = cov_trend + cov_short
140141
# Define the delta GPs
141142
n_gps = 10
142143
eta_delta_true = 3
143-
ell_delta_true = pm.draw(pm.Lognormal.dist(mu=np.log(ell_mu_short_true), sigma=0.5), draws=n_gps)
144+
ell_delta_true = pm.draw(
145+
pm.Lognormal.dist(mu=np.log(ell_mu_short_true), sigma=0.5), draws=n_gps, random_seed=rng
146+
)
144147
145148
cov_deltas = [
146149
eta_delta_true**2 * pm.gp.cov.Matern52(input_dim=1, ls=ell_i) for ell_i in ell_delta_true
@@ -166,12 +169,14 @@ def generate_gp_samples(x, cov_mu, cov_deltas, noise_dist, rng):
166169
"""
167170
n = len(x)
168171
# One draw from the mean GP
169-
f_mu_true = pm.draw(pm.MvNormal.dist(mu=np.zeros(n), cov=cov_mu(x[:, None])))
172+
f_mu_true = pm.draw(pm.MvNormal.dist(mu=np.zeros(n), cov=cov_mu(x[:, None])), random_seed=rng)
170173
171174
# Draws from the delta GPs
172175
f_deltas = []
173176
for cov_delta in cov_deltas:
174-
f_deltas.append(pm.draw(pm.MvNormal.dist(mu=np.zeros(n), cov=cov_delta(x[:, None]))))
177+
f_deltas.append(
178+
pm.draw(pm.MvNormal.dist(mu=np.zeros(n), cov=cov_delta(x[:, None])), random_seed=rng)
179+
)
175180
f_delta = np.vstack(f_deltas)
176181
177182
# The hierarchical GP
@@ -435,10 +440,9 @@ with pm.Model(coords=coords) as model:
435440
ell_mu_short = pm.Deterministic("ell_mu_short", pt.softplus(log_ell_mu_short))
436441
437442
eta_mu_trend = pm.Gamma("eta_mu_trend", mu=3.5, sigma=1)
438-
ell_mu_trend_params = pm.find_constrained_prior(
439-
pm.InverseGamma, lower=5, upper=12, mass=0.95, init_guess={"mu": 9.0, "sigma": 3.0}
443+
ell_mu_trend = pz.maxent(pz.InverseGamma(), lower=5, upper=12, mass=0.95, plot=False).to_pymc(
444+
"ell_mu_trend"
440445
)
441-
ell_mu_trend = pm.InverseGamma("ell_mu_trend", **ell_mu_trend_params)
442446
443447
## Prior for the offsets
444448
log_ell_delta_offset = pm.ZeroSumNormal("log_ell_delta_offset", dims="gp_ix")
@@ -473,7 +477,7 @@ Now, what do these priors mean? Good question. As always, it's crucial to do **p
473477
474478
```{code-cell} ipython3
475479
with model:
476-
idata = pm.sample_prior_predictive()
480+
idata = pm.sample_prior_predictive(random_seed=rng)
477481
```
478482
479483
```{code-cell} ipython3
@@ -564,7 +568,7 @@ Once we're satisfied with our priors, which is the case here, we can... sample t
564568
565569
```{code-cell} ipython3
566570
with model:
567-
idata.extend(pm.sample(nuts_sampler="numpyro", target_accept=0.9))
571+
idata.extend(pm.sample(nuts_sampler="numpyro", target_accept=0.9, random_seed=rng))
568572
```
569573
570574
```{code-cell} ipython3
@@ -669,6 +673,7 @@ with model:
669673
var_names=["f_mu", "f"],
670674
predictions=True,
671675
compile_kwargs={"mode": "NUMBA"},
676+
random_seed=rng,
672677
),
673678
)
674679
```
@@ -863,7 +868,11 @@ cov_t = pm.gp.cov.Matern52(input_dim=1, ls=ell_t_true)
863868
Kt = cov_t(t[:, None])
864869
865870
K = pt.slinalg.kron(Kx, Kt)
866-
f_true = pm.draw(pm.MvNormal.dist(mu=np.zeros(n_gps * n_t), cov=K)).reshape(n_gps, n_t).T
871+
f_true = (
872+
pm.draw(pm.MvNormal.dist(mu=np.zeros(n_gps * n_t), cov=K), random_seed=rng)
873+
.reshape(n_gps, n_t)
874+
.T
875+
)
867876
868877
# Additive gaussian noise
869878
sigma_noise = 0.5
@@ -947,17 +956,11 @@ with pm.Model() as model:
947956
Xs_x = Xx - xx_center
948957
949958
## covariance on time GP
950-
ell_t_params = pm.find_constrained_prior(
951-
pm.Lognormal, lower=0.5, upper=4.0, mass=0.95, init_guess={"mu": 1.0, "sigma": 1.0}
952-
)
953-
ell_t = pm.Lognormal("ell_t", **ell_t_params)
959+
ell_t = pz.maxent(pz.LogNormal(), lower=0.5, upper=4.0, mass=0.95, plot=False).to_pymc("ell_t")
954960
cov_t = pm.gp.cov.Matern52(1, ls=ell_t)
955961
956962
## covariance on space GP
957-
ell_x_params = pm.find_constrained_prior(
958-
pm.Lognormal, lower=0.5, upper=4.0, mass=0.95, init_guess={"mu": 1.0, "sigma": 1.0}
959-
)
960-
ell_x = pm.Lognormal("ell_x", **ell_x_params)
963+
ell_x = pz.maxent(pz.LogNormal(), lower=0.5, upper=4.0, mass=0.95, plot=False).to_pymc("ell_x")
961964
cov_x = pm.gp.cov.Matern52(1, ls=ell_x)
962965
963966
## Kronecker GP
@@ -981,7 +984,7 @@ pm.model_to_graphviz(model)
981984
982985
```{code-cell} ipython3
983986
with model:
984-
idata = pm.sample_prior_predictive()
987+
idata = pm.sample_prior_predictive(random_seed=rng)
985988
```
986989
987990
```{code-cell} ipython3
@@ -1015,7 +1018,7 @@ axs[1].set(ylim=ylims, title=r"Prior GPs, $\pm 1 \sigma$ posterior intervals");
10151018
10161019
```{code-cell} ipython3
10171020
with model:
1018-
idata.extend(pm.sample(nuts_sampler="numpyro"))
1021+
idata.extend(pm.sample(nuts_sampler="numpyro", random_seed=rng))
10191022
```
10201023
10211024
```{code-cell} ipython3
@@ -1075,6 +1078,7 @@ And isn't this beautiful?? Now go on, and HSGP-on!
10751078
## Authors
10761079
10771080
* Created by [Bill Engels](https://github.com/bwengals), [Alexandre Andorra](https://github.com/AlexAndorra) and [Maxim Kochurov](https://github.com/ferrine) in 2024 ([pymc-examples#668](https://github.com/pymc-devs/pymc-examples/pull/668))
1081+
* Use `pz.maxent` instead of `pm.find_constrained_prior`, and add random seed. [Osvaldo Martin](https://aloctavodia.github.io/). August 2024
10781082
10791083
+++
10801084

examples/gaussian_processes/HSGP-Basic.ipynb

Lines changed: 340 additions & 325 deletions
Large diffs are not rendered by default.

examples/gaussian_processes/HSGP-Basic.myst.md

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ jupytext:
55
format_name: myst
66
format_version: 0.13
77
kernelspec:
8-
display_name: pymc-examples
8+
display_name: preliz
99
language: python
10-
name: pymc-examples
10+
name: python3
1111
---
1212

1313
(hsgp)=
@@ -56,6 +56,7 @@ We'll use simulated data to motivate an overview of the usage of {class}`~pymc.g
5656
import arviz as az
5757
import matplotlib.pyplot as plt
5858
import numpy as np
59+
import preliz as pz
5960
import pymc as pm
6061
import pytensor.tensor as pt
6162
@@ -114,42 +115,21 @@ ax.grid(False)
114115

115116
+++
116117

117-
First we use `pm.find_constrained_prior` to choose our prior for the lengthscale parameter. We use a Lognormal to penalize very small lengthscales while having a heavy right tail. When the signal from the GP is high relative to the noise, we are able to use more informative priors.
118+
First we use `pz.maxent` to choose our prior for the lengthscale parameter, maxent return the maximum entropy prior with the specified `mass` within the interval [`lower`, `upper`].
118119

119-
```{code-cell} ipython3
120-
ell_dist = pm.Lognormal
120+
We use a Lognormal to penalize very small lengthscales while having a heavy right tail. When the signal from the GP is high relative to the noise, we are able to use more informative priors.
121121

122+
```{code-cell} ipython3
122123
lower, upper = 0.5, 5.0
123-
ell_params = pm.find_constrained_prior(
124-
ell_dist, lower=lower, upper=upper, mass=0.9, init_guess={"mu": 1.0, "sigma": 1.0}
124+
ell_dist, ax = pz.maxent(
125+
pz.LogNormal(),
126+
lower=lower,
127+
upper=upper,
128+
mass=0.9,
129+
plot_kwargs={"support": (0, 7), "legend": None},
125130
)
126131
127-
support = np.linspace(0, 7.0, 1000)
128-
logp = pm.logp(ell_dist.dist(**ell_params), support)
129-
p = np.exp(logp.eval())
130-
131-
_, ax = plt.subplots()
132-
133-
bulk_ix = (support >= lower) & (support <= upper)
134-
ax.fill_between(
135-
support[bulk_ix],
136-
np.zeros(sum(bulk_ix)),
137-
p[bulk_ix],
138-
color="slateblue",
139-
alpha=0.3,
140-
edgecolor="none",
141-
label="90% of mass",
142-
)
143-
ax.plot(support, p, color="k", lw=2)
144-
145-
ax.set(
146-
xlabel="x",
147-
ylabel="p(x)",
148-
xlim=[-0.1, 7.0],
149-
ylim=[0.0, 0.6],
150-
title=r"Prior for the lengthscale, $\ell$",
151-
)
152-
ax.legend();
132+
ax.set_title(r"Prior for the lengthscale, $\ell$")
153133
```
154134

155135
There are a few things to note about the model code below:
@@ -158,7 +138,7 @@ There are a few things to note about the model code below:
158138

159139
```{code-cell} ipython3
160140
with pm.Model(coords={"basis_coeffs": np.arange(200), "obs_id": np.arange(len(y_obs))}) as model:
161-
ell = ell_dist("ell", **ell_params)
141+
ell = ell_dist.to_pymc("ell")
162142
eta = pm.Exponential("eta", scale=1.0)
163143
cov_func = eta**2 * pm.gp.cov.Matern52(input_dim=1, ls=ell)
164144
@@ -174,7 +154,7 @@ with pm.Model(coords={"basis_coeffs": np.arange(200), "obs_id": np.arange(len(y_
174154
pm.Normal("y_obs", mu=f, sigma=sigma, observed=y_obs, dims="obs_id")
175155
176156
idata = pm.sample()
177-
idata.extend(pm.sample_posterior_predictive(idata))
157+
idata.extend(pm.sample_posterior_predictive(idata, random_seed=rng))
178158
```
179159

180160
```{code-cell} ipython3
@@ -579,7 +559,7 @@ with pm.Model() as model:
579559
sigma = pm.Exponential("sigma", scale=2.0)
580560
pm.Normal("y_obs", mu=mu, sigma=sigma, observed=y_tr, shape=X_gp.shape[0])
581561
582-
idata = pm.sample_prior_predictive()
562+
idata = pm.sample_prior_predictive(random_seed=rng)
583563
584564
pm.model_to_graphviz(model)
585565
```
@@ -628,7 +608,7 @@ Now, let's sample the model and quickly check the results:
628608
629609
```{code-cell} ipython3
630610
with model:
631-
idata.extend(pm.sample(nuts_sampler="numpyro"))
611+
idata.extend(pm.sample(nuts_sampler="numpyro", random_seed=rng))
632612
```
633613
634614
```{code-cell} ipython3
@@ -663,7 +643,9 @@ with model:
663643
pm.set_data({"X_gp": X[:, :2], "X_fe": X[:, 2]})
664644
665645
idata_thinned = idata.sel(draw=slice(None, None, 10))
666-
idata.extend(pm.sample_posterior_predictive(idata_thinned, var_names=["f", "mu"]))
646+
idata.extend(
647+
pm.sample_posterior_predictive(idata_thinned, var_names=["f", "mu"], random_seed=rng)
648+
)
667649
```
668650
669651
```{code-cell} ipython3
@@ -704,6 +686,7 @@ Sampling diagnostics all look good, and we can see that the underlying GP was in
704686
## Authors
705687
706688
* Created by [Bill Engels](https://github.com/bwengals) and [Alexandre Andorra](https://github.com/AlexAndorra) in 2024 ([pymc-examples#647](https://github.com/pymc-devs/pymc-examples/pull/647))
689+
* Use `pz.maxent` instead of `pm.find_constrained_prior`, and add random seed. [Osvaldo Martin](https://aloctavodia.github.io/). August 2024
707690
708691
+++
709692

examples/time_series/longitudinal_models.ipynb

Lines changed: 2574 additions & 2665 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)