Spaces:
Sleeping
Sleeping
bhardwajsatyam
commited on
Commit
·
ff977f3
1
Parent(s):
2cc34a0
Added files
Browse files- README.md +4 -4
- app.py +322 -0
- description.md +14 -0
- requirements.txt +8 -0
README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
---
|
2 |
-
title: Blr
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.28.2
|
8 |
app_file: app.py
|
|
|
1 |
---
|
2 |
+
title: Blr Numpyro
|
3 |
+
emoji: 🌍
|
4 |
+
colorFrom: gray
|
5 |
+
colorTo: yellow
|
6 |
sdk: streamlit
|
7 |
sdk_version: 1.28.2
|
8 |
app_file: app.py
|
app.py
ADDED
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import numpyro
|
3 |
+
from numpyro.distributions import Normal, StudentT, Laplace, Uniform
|
4 |
+
from numpyro.infer import MCMC, NUTS, Predictive
|
5 |
+
from jax import random
|
6 |
+
import arviz as az
|
7 |
+
import streamlit as st
|
8 |
+
import matplotlib.pyplot as plt
|
9 |
+
|
10 |
+
import pickle
|
11 |
+
|
12 |
+
plt.style.use("seaborn-v0_8")
|
13 |
+
|
14 |
+
|
15 |
+
def phi(X, degree=2):
|
16 |
+
return np.concatenate([X**i for i in range(1, degree + 1)], axis=1)
|
17 |
+
|
18 |
+
|
19 |
+
st.set_page_config(layout="wide")
|
20 |
+
st.title("Bayesian Linear Regression")
|
21 |
+
st.markdown(
|
22 |
+
"This app shows the effect of changing the prior and the likelihood distributions used in Bayesian Linear Regression. Since they do not always form a conjugate pair, we use ``` numpyro ``` to numerically sample from the posterior distribution using MCMC with the No-U-Turn Sampler (NUTS) algorithm."
|
23 |
+
)
|
24 |
+
|
25 |
+
left, right = st.columns([0.3, 0.7])
|
26 |
+
|
27 |
+
with left:
|
28 |
+
st.write("---")
|
29 |
+
d = st.select_slider(
|
30 |
+
label="Degree of polynomial features", options=np.arange(1, 11), value=1
|
31 |
+
)
|
32 |
+
weight_prior_type = st.selectbox(
|
33 |
+
r"##### Weight prior $p(\theta)$",
|
34 |
+
["Normal", "Laplace", "Uniform"],
|
35 |
+
)
|
36 |
+
|
37 |
+
if weight_prior_type == "Normal":
|
38 |
+
ll, rr = st.columns(2)
|
39 |
+
with ll:
|
40 |
+
mu = st.select_slider(
|
41 |
+
label=r"$\mu$", options=np.arange(-5.0, 6.0), value=0.0
|
42 |
+
)
|
43 |
+
|
44 |
+
with rr:
|
45 |
+
sigma = st.slider(
|
46 |
+
label=r"$\sigma$",
|
47 |
+
min_value=0.1,
|
48 |
+
max_value=10.0,
|
49 |
+
value=1.0,
|
50 |
+
step=0.1,
|
51 |
+
)
|
52 |
+
weight_prior = Normal(mu, sigma)
|
53 |
+
elif weight_prior_type == "Laplace":
|
54 |
+
ll, rr = st.columns(2)
|
55 |
+
with ll:
|
56 |
+
mu = st.slider(
|
57 |
+
label=r"$\mu$", min_value=-5.0, max_value=5.0, value=0.0, step=0.1
|
58 |
+
)
|
59 |
+
with rr:
|
60 |
+
bw = st.slider(
|
61 |
+
label=r"$b$", min_value=0.1, max_value=10.0, value=1.0, step=0.1
|
62 |
+
)
|
63 |
+
weight_prior = Laplace(mu, bw)
|
64 |
+
elif weight_prior_type == "Uniform":
|
65 |
+
ll, rr = st.columns(2)
|
66 |
+
with ll:
|
67 |
+
a = st.slider(
|
68 |
+
label=r"$a$", min_value=-6.0, max_value=5.0, value=-6.0, step=0.1
|
69 |
+
)
|
70 |
+
with rr:
|
71 |
+
b = st.slider(
|
72 |
+
label=r"$b$",
|
73 |
+
min_value=a + 1e-3,
|
74 |
+
max_value=6.0 + 1e-3,
|
75 |
+
value=6.0,
|
76 |
+
step=0.1,
|
77 |
+
)
|
78 |
+
if a >= b:
|
79 |
+
st.error("Lower bound must be less than upper bound")
|
80 |
+
weight_prior = Uniform(a, b)
|
81 |
+
|
82 |
+
same_bias_prior = st.checkbox(r"Same prior on bias $\theta_0$", value=True)
|
83 |
+
|
84 |
+
if not same_bias_prior:
|
85 |
+
bias_prior_type = st.selectbox(
|
86 |
+
r"##### Bias prior $p(\mathcal{b})$",
|
87 |
+
["Normal", "Laplace", "Uniform"],
|
88 |
+
)
|
89 |
+
|
90 |
+
if bias_prior_type == "Normal":
|
91 |
+
ll, rr = st.columns(2)
|
92 |
+
with ll:
|
93 |
+
mu = st.slider(
|
94 |
+
label=r"$\mu$",
|
95 |
+
min_value=-5.0,
|
96 |
+
max_value=5.0,
|
97 |
+
value=0.0,
|
98 |
+
step=0.1,
|
99 |
+
key="bias_mu",
|
100 |
+
)
|
101 |
+
with rr:
|
102 |
+
sigma = st.slider(
|
103 |
+
label=r"$\sigma$",
|
104 |
+
min_value=0.1,
|
105 |
+
max_value=10.0,
|
106 |
+
value=1.0,
|
107 |
+
step=0.1,
|
108 |
+
key="bias_sigma",
|
109 |
+
)
|
110 |
+
bias_prior = Normal(mu, sigma)
|
111 |
+
elif bias_prior_type == "Laplace":
|
112 |
+
ll, rr = st.columns(2)
|
113 |
+
with ll:
|
114 |
+
mu = st.slider(
|
115 |
+
label=r"$\mu$",
|
116 |
+
min_value=-5.0,
|
117 |
+
max_value=5.0,
|
118 |
+
value=0.0,
|
119 |
+
step=0.1,
|
120 |
+
key="bias_mu",
|
121 |
+
)
|
122 |
+
with rr:
|
123 |
+
bw = st.slider(
|
124 |
+
label=r"$b$",
|
125 |
+
min_value=0.1,
|
126 |
+
max_value=10.0,
|
127 |
+
value=1.0,
|
128 |
+
step=0.1,
|
129 |
+
key="bias_bw",
|
130 |
+
)
|
131 |
+
bias_prior = Laplace(mu, bw)
|
132 |
+
elif bias_prior_type == "Uniform":
|
133 |
+
ll, rr = st.columns(2)
|
134 |
+
with ll:
|
135 |
+
a = st.slider(
|
136 |
+
label="Lower bound",
|
137 |
+
min_value=-6.0,
|
138 |
+
max_value=5.0,
|
139 |
+
value=-6.0,
|
140 |
+
step=0.1,
|
141 |
+
key="bias_a",
|
142 |
+
)
|
143 |
+
with rr:
|
144 |
+
b = st.slider(
|
145 |
+
label="Upper bound",
|
146 |
+
min_value=a + 1e-3,
|
147 |
+
max_value=6.0 + 1e-3,
|
148 |
+
value=6.0,
|
149 |
+
step=0.1,
|
150 |
+
key="bias_b",
|
151 |
+
)
|
152 |
+
if a >= b:
|
153 |
+
st.error("Lower bound must be less than upper bound")
|
154 |
+
bias_prior = Uniform(a, b)
|
155 |
+
|
156 |
+
else:
|
157 |
+
bias_prior = weight_prior
|
158 |
+
|
159 |
+
st.write("---")
|
160 |
+
|
161 |
+
ll, rr = st.columns(2)
|
162 |
+
with ll:
|
163 |
+
likelihood_type = st.selectbox(
|
164 |
+
r"##### Likelihood $p(\mathcal{D} | \theta)$",
|
165 |
+
["Normal", "StudentT", "Laplace"],
|
166 |
+
)
|
167 |
+
with rr:
|
168 |
+
noise_sigma = st.slider(
|
169 |
+
label="Aleatoric noise $\sigma$",
|
170 |
+
min_value=0.1,
|
171 |
+
max_value=2.0,
|
172 |
+
value=0.5,
|
173 |
+
step=0.1,
|
174 |
+
)
|
175 |
+
|
176 |
+
if likelihood_type == "StudentT":
|
177 |
+
likelihood_df = st.select_slider(
|
178 |
+
label=r"Degrees of freedom $\nu$",
|
179 |
+
options=list(range(1, 21)),
|
180 |
+
value=3,
|
181 |
+
key="likelihood_df",
|
182 |
+
)
|
183 |
+
|
184 |
+
st.write("---")
|
185 |
+
st.write("##### Sampling parameters")
|
186 |
+
|
187 |
+
ll, rr = st.columns(2)
|
188 |
+
with ll:
|
189 |
+
num_samples = st.slider(
|
190 |
+
label="Number of samples",
|
191 |
+
min_value=500,
|
192 |
+
max_value=10000,
|
193 |
+
value=2000,
|
194 |
+
step=500,
|
195 |
+
)
|
196 |
+
with rr:
|
197 |
+
num_warmup = st.slider(
|
198 |
+
label="Number of warmup steps",
|
199 |
+
min_value=100,
|
200 |
+
max_value=1000,
|
201 |
+
value=500,
|
202 |
+
step=100,
|
203 |
+
)
|
204 |
+
|
205 |
+
st.write("---")
|
206 |
+
st.write("##### Dataset parameters")
|
207 |
+
|
208 |
+
ll, rr = st.columns(2)
|
209 |
+
with ll:
|
210 |
+
dataset_type = st.selectbox("Select Dataset", ["Sin", "Log", "Exp"])
|
211 |
+
with rr:
|
212 |
+
dataset_noise_sigma = st.slider(
|
213 |
+
label="Dataset noise $\sigma$",
|
214 |
+
min_value=0.1,
|
215 |
+
max_value=2.0,
|
216 |
+
value=1.0,
|
217 |
+
step=0.1,
|
218 |
+
)
|
219 |
+
|
220 |
+
|
221 |
+
with right:
|
222 |
+
np.random.seed(42)
|
223 |
+
|
224 |
+
if dataset_type == "Sin":
|
225 |
+
X = np.sort(2 * np.random.rand(100)).reshape(-1, 1)
|
226 |
+
X_lin = np.linspace(0, 2, 100).reshape(-1, 1)
|
227 |
+
y = X * np.sin(2 * np.pi * X) + dataset_noise_sigma * np.random.randn(
|
228 |
+
100
|
229 |
+
).reshape(-1, 1)
|
230 |
+
elif dataset_type == "Log":
|
231 |
+
X = np.sort(2 * np.random.rand(100)).reshape(-1, 1)
|
232 |
+
X_lin = np.linspace(0, 2, 100).reshape(-1, 1)
|
233 |
+
y = np.log(X) + dataset_noise_sigma * np.random.randn(100).reshape(-1, 1)
|
234 |
+
elif dataset_type == "Exp":
|
235 |
+
X = np.sort(2 * np.random.rand(100)).reshape(-1, 1)
|
236 |
+
X_lin = np.linspace(0, 2, 100).reshape(-1, 1)
|
237 |
+
y = np.exp(X) + dataset_noise_sigma * np.random.randn(100).reshape(-1, 1)
|
238 |
+
|
239 |
+
X = phi(X, d)
|
240 |
+
X_lin = phi(X_lin, d)
|
241 |
+
|
242 |
+
def model(X=None, y=None):
|
243 |
+
w = numpyro.sample("w", weight_prior.expand([X.shape[1], 1]))
|
244 |
+
b = numpyro.sample("b", bias_prior.expand([1, 1]))
|
245 |
+
|
246 |
+
y_hat = X @ w + b
|
247 |
+
|
248 |
+
if likelihood_type == "Normal":
|
249 |
+
return numpyro.sample(
|
250 |
+
"y_pred",
|
251 |
+
Normal(y_hat, noise_sigma),
|
252 |
+
obs=y,
|
253 |
+
)
|
254 |
+
elif likelihood_type == "StudentT":
|
255 |
+
return numpyro.sample(
|
256 |
+
"y_pred",
|
257 |
+
StudentT(likelihood_df, y_hat, noise_sigma),
|
258 |
+
obs=y,
|
259 |
+
)
|
260 |
+
elif likelihood_type == "Laplace":
|
261 |
+
return numpyro.sample(
|
262 |
+
"y_pred",
|
263 |
+
Laplace(y_hat, noise_sigma),
|
264 |
+
obs=y,
|
265 |
+
)
|
266 |
+
|
267 |
+
kernel = NUTS(model)
|
268 |
+
mcmc = MCMC(
|
269 |
+
kernel,
|
270 |
+
num_samples=num_samples,
|
271 |
+
num_warmup=num_warmup,
|
272 |
+
)
|
273 |
+
|
274 |
+
rng_key = random.PRNGKey(0)
|
275 |
+
mcmc.run(rng_key, X=X, y=y)
|
276 |
+
|
277 |
+
posterior_samples = mcmc.get_samples()
|
278 |
+
|
279 |
+
rng_key = random.PRNGKey(1)
|
280 |
+
posterior_predictive = Predictive(model, posterior_samples)
|
281 |
+
y_pred = posterior_predictive(rng_key, X=X_lin, y=None)["y_pred"]
|
282 |
+
|
283 |
+
mean = y_pred.mean(0)
|
284 |
+
std = y_pred.std(0)
|
285 |
+
|
286 |
+
fig, ax = plt.subplots(figsize=(6, 4), dpi=300)
|
287 |
+
for i in range(1, 21):
|
288 |
+
ax.fill_between(
|
289 |
+
X_lin[:, 0],
|
290 |
+
(mean - (3 * i / 20) * std).reshape(-1),
|
291 |
+
(mean + (3 * i / 20) * std).reshape(-1),
|
292 |
+
color="C0",
|
293 |
+
alpha=0.05,
|
294 |
+
edgecolor=None,
|
295 |
+
)
|
296 |
+
ax.plot(X_lin[:, 0], mean, "r", label="Mean", linewidth=1)
|
297 |
+
ax.scatter(
|
298 |
+
X[:, 0],
|
299 |
+
y.ravel(),
|
300 |
+
c="k",
|
301 |
+
label="Datapoints",
|
302 |
+
marker="x",
|
303 |
+
s=8,
|
304 |
+
linewidth=0.5,
|
305 |
+
)
|
306 |
+
ax.set_xlabel("x", fontsize=7)
|
307 |
+
ax.set_ylabel("y", fontsize=7)
|
308 |
+
ax.set_title("Posterior Predictive", fontsize=8)
|
309 |
+
ax.tick_params(labelsize=6)
|
310 |
+
ax.legend(fontsize=7)
|
311 |
+
plt.tight_layout()
|
312 |
+
st.pyplot(fig)
|
313 |
+
|
314 |
+
axes = az.plot_trace(mcmc, compact=True)
|
315 |
+
fig = axes.ravel()[0].figure
|
316 |
+
|
317 |
+
plt.tight_layout()
|
318 |
+
st.pyplot(fig)
|
319 |
+
|
320 |
+
|
321 |
+
file = open("description.md", "r")
|
322 |
+
st.markdown(file.read())
|
description.md
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
In Bayesian linear regression, we typically consider the model
|
2 |
+
|
3 |
+
| Prior | Likelihood | Posterior | Posterior Predictive |
|
4 |
+
|:-----------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|:------------------------------------------------------:|
|
5 |
+
| $p(\boldsymbol{\theta}) = \mathcal{N}(\mathbf{m}_0, \mathbf{S}_0)$ | $p(y \| x, \boldsymbol{\theta}) = \mathcal{N}(\boldsymbol{\theta}^T x, \sigma^2)$ | $p(\boldsymbol{\theta} \mid \mathcal{X}, \mathcal{Y})=\mathcal{N}\left(\boldsymbol{\theta} \mid \boldsymbol{m}_N, \boldsymbol{S}_N\right)$ | $p\left(y_* \mid \mathcal{X}, \mathcal{Y}, \boldsymbol{x}_*\right)=\mathcal{N}\left(y_* \mid \boldsymbol{\phi}^{\top}\left(\boldsymbol{x}_*\right) \boldsymbol{m}_N, \boldsymbol{\phi}^{\top}\left(\boldsymbol{x}_*\right) \boldsymbol{S}_N \boldsymbol{\phi}\left(\boldsymbol{x}_*\right)+\sigma^2\right)$ |
|
6 |
+
|
7 |
+
|
8 |
+
where $\mathbf{m}_0$ and $\mathbf{S}_0$ are the mean and covariance of the prior distribution, respectively. $\boldsymbol{m}_N=\boldsymbol{S}_N\left(\boldsymbol{S}_0^{-1} \boldsymbol{m}_0+\sigma^{-2} \boldsymbol{\Phi}^{\top} \boldsymbol{y}\right)$ and $\boldsymbol{S}_N=\left(\boldsymbol{S}_0^{-1}+\sigma^{-2} \boldsymbol{\Phi}^{\top} \boldsymbol{\Phi}\right)^{-1}$ are the mean and covariance of the posterior distribution, respectively.
|
9 |
+
|
10 |
+
In this app, we allow the user to change the prior distribution from a Gaussian to a Laplace distribution or Uniform distribution. Likewise for the Likelihood function. The user can also select from 3 different datasets. Since the distributions don't always form a conjugate pair, we rely on ```numpyro``` library for it's fast implementation of MCMC using the NUTS algorithm.
|
11 |
+
|
12 |
+
References:
|
13 |
+
1. Bayesian regression using numpyro—Numpyro documentation. (n.d.). Retrieved November 15, 2023, from https://num.pyro.ai/en/stable/tutorials/bayesian_regression.html
|
14 |
+
2. Mathematics for machine learning. (n.d.). Mathematics for Machine Learning. Retrieved November 15, 2023, from https://mml-book.com/
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy
|
2 |
+
matplotlib
|
3 |
+
numpyro
|
4 |
+
jax
|
5 |
+
jaxlib
|
6 |
+
arviz
|
7 |
+
tqdm
|
8 |
+
stqdm
|