# !pip install -U regdata
Imports
import regdata as rd
import torch
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib import rc
import wbml.out as out
from wbml.plot import tweak
from stheno import B, GP, EQ, PseudoObsVFE, PseudoObsFITC
from varz.torch import Vars, minimise_l_bfgs_b, parametrised, Positive
import lab.torch
Data preperation
# Define points to predict at.
= B.linspace(0, 10, 100)
x = B.linspace(0, 7, 50_000)
x_obs = B.linspace(0, 10, 20)
x_ind
# Construct a prior.
= GP(EQ().periodic(2 * B.pi))
f
# Sample a true, underlying function and observations.
= B.sin(x)
f_true = B.sin(x_obs) + B.sqrt(0.5) * B.randn(*x_obs.shape) y_obs
Plotting function
def plot(method):
if method == 'VFE':
# Plot result.
="True", style="test")
plt.plot(x, f_true, label
plt.scatter(
x_obs,
y_obs,="Observations",
label="train",
style="tab:green",
c=0.35,
alpha
)
plt.scatter(
x_ind,0],
obs.mu(f.measure)[:, ="Inducing Points",
label="train",
style=20,
s
)="Prediction", style="pred")
plt.plot(x, mean, label="pred")
plt.fill_between(x, lower, upper, style
tweak()
plt.show()else:
# Plot result.
="True", style="test")
plt.plot(x, f_true, label
plt.scatter(
x_obs,
y_obs,="Observations",
label="train",
style="tab:green",
c=0.35,
alpha
)
plt.scatter(
x_ind,
B.dense(f_post(x_ind).mean),="Inducing Points",
label="train",
style=20,
s
)="Prediction", style="pred")
plt.plot(x, mean, label="pred")
plt.fill_between(x, lower, upper, style
tweak()
plt.show()
Sparse regression with Variational Free Energy (VFE) method
# Compute a pseudo-point approximation of the posterior.
= PseudoObsVFE(f(x_ind), (f(x_obs, 0.5), y_obs))
obs
# Compute the ELBO.
"ELBO", obs.elbo(f.measure))
out.kv(
# Compute the approximate posterior.
= f | obs
f_post
# Make predictions with the approximate posterior.
= f_post(x, 0.5).marginal_credible_bounds()
mean, lower, upper 'VFE') plot(
ELBO: -5.345e+04
Sparse Regression with Fully Independent Training Conditional (FITC) mehod
# Compute a pseudo-point approximation of the posterior.
= PseudoObsFITC(f(x_ind), (f(x_obs, 0.5), y_obs))
obs
# Compute the ELBO.
"ELBO", obs.elbo(f.measure))
out.kv(
# Compute the approximate posterior.
= f | obs
f_post
# Make predictions with the approximate posterior.
= f_post(x, 0.5).marginal_credible_bounds()
mean, lower, upper 'FITC') plot(
ELBO: -5.345e+04
Hyperparameter tuning (Noisy Sine data)
def model(vs):
"""Constuct a model with learnable parameters."""
return vs['variance']*GP(EQ().stretch(vs['length_scale']))
123)
torch.manual_seed(
= rd.SineNoisy(scale_X=False, scale_y=False, return_test=True, backend='torch')
dataObj = dataObj.get_data() x_obs, y_obs, x
=2); plt.scatter(x_obs, y_obs, s
VFE
= Vars(torch.float64)
vs ="noise")
vs.positive(name="length_scale");
vs.positive(name="variance");
vs.positive(name=torch.linspace(0.4,0.6,10), shape=(10,), name='x_ind')
vs.positive(initTrue)
vs.requires_grad(
= torch.optim.Adam(vs.get_latent_vars(), lr=0.1)
optimizer = plt.subplots(1,2,figsize=(15,5))
fig, ax = []
losses
def update(i):
optimizer.zero_grad()= model(vs)
gp = PseudoObsVFE(gp(vs['x_ind']), (gp(x_obs, vs['noise']), y_obs))
obs = -obs.elbo(gp.measure)
loss
losses.append(loss.item())
loss.backward()
optimizer.step()
= gp | obs
gp_post = gp_post(x, vs['noise']).marginal_credible_bounds()
mean, lower, upper = B.dense(gp_post(vs['x_ind']).mean)
ind_mean
0].cla();ax[1].cla();
ax[0].scatter(x_obs, y_obs, s=2)
ax[with torch.no_grad():
0].plot()
ax[0].plot(x, B.dense(mean), label='Prediction')
ax[0].fill_between(x.ravel(), lower, upper, alpha=0.2, label='Uncertainty')
ax[0].plot(x, dataObj.f(x), label='True')
ax[0].scatter(vs['x_ind'], ind_mean, label='Inducing points')
ax[0].set_xlabel('X')
ax[0].legend()
ax[
1].plot(losses, label='loss')
ax[1].set_xlabel('Iterations')
ax[1].legend()
ax[
= FuncAnimation(fig, update, range(50))
anim 'animation', html='jshtml')
rc(
plt.close() anim
FITC
= Vars(torch.float64)
vs ="noise")
vs.positive(name="length_scale");
vs.positive(name="variance");
vs.positive(name=torch.linspace(0.4,0.6,10), shape=(10,), name='x_ind')
vs.positive(initTrue)
vs.requires_grad(
= torch.optim.Adam(vs.get_latent_vars(), lr=0.1)
optimizer = plt.subplots(1,2,figsize=(15,5))
fig, ax = []
losses
def update(i):
optimizer.zero_grad()= model(vs)
gp = PseudoObsFITC(gp(vs['x_ind']), (gp(x_obs, vs['noise']), y_obs))
obs = -obs.elbo(gp.measure)
loss
losses.append(loss.item())
loss.backward()
optimizer.step()
= gp | obs
gp_post = gp_post(x, vs['noise']).marginal_credible_bounds()
mean, lower, upper = B.dense(gp_post(vs['x_ind']).mean)
ind_mean
0].cla();ax[1].cla();
ax[0].scatter(x_obs, y_obs, s=2)
ax[with torch.no_grad():
0].plot()
ax[0].plot(x, B.dense(mean), label='Prediction')
ax[0].fill_between(x.ravel(), lower, upper, alpha=0.2, label='Uncertainty')
ax[0].plot(x, dataObj.f(x), label='True')
ax[0].scatter(vs['x_ind'], ind_mean, label='Inducing points')
ax[0].set_xlabel('X')
ax[0].legend()
ax[
1].plot(losses, label='loss')
ax[1].set_xlabel('Iterations')
ax[1].legend()
ax[
= FuncAnimation(fig, update, range(50))
anim 'animation', html='jshtml')
rc(
plt.close() anim