Example #1
0
def objective(vs, m, x_data, y_data, locs):
    """NLML objective.

    Args:
        vs (:class:`varz.Vars`): Variable container.
        m (int): Number of latent processes.
        x_data (tensor): Time stamps of the observations.
        y_data (tensor): Observations.
        locs (tensor): Spatial locations of observations.

    Returns:
        scalar: Negative log-marginal likelihood.
    """
    y_proj, _, S, noises_obs = project(vs, m, y_data, locs)
    xs, noise_obs, noises_latent = model(vs, m)

    # Add contribution of latent processes.
    lml = 0
    for i, (x, y) in enumerate(zip(xs, y_proj)):
        e_signal = GP((noise_obs / S[i] + noises_latent[i]) * Delta(),
                      graph=x.graph)
        lml += (x + e_signal)(x_data).logpdf(y)

        e_noise = GP(noise_obs / S[i] * Delta(), graph=x.graph)
        lml -= e_noise(x_data).logpdf(y)

    # Add regularisation contribution.
    lml += B.sum(Normal(Diagonal(noises_obs)).logpdf(B.transpose(y_data)))

    # Return negative the evidence, normalised by the number of data points.
    n, p = B.shape(y_data)
    return -lml / (n * p)
Example #2
0
def predict(vs, m, x_data, y_data, locs, x_pred):
    """Make predictions.

    Args:
        vs (:class:`varz.Vars`): Variable container.
        m (int): Number of latent processes.
        x_data (tensor): Time stamps of the observations.
        y_data (tensor): Observations.
        locs (tensor): Spatial locations of observations.
        x_pred (tensor): Time stamps to predict at.

    Returns:
        tuple: Tuple containing the predictions for the latent processes and
            predictions for the observations.
    """
    # Construct model and project data for prediction.
    xs, noise_obs, noises_latent = model(vs, m)
    y_proj, H, S, noises_obs = project(vs, m, y_data, locs)
    L = noise_obs / S + noises_latent

    # Condition latent processes.
    xs_posterior = []
    for x, noise, y in zip(xs, L, y_proj):
        e = GP(noise * Delta(), graph=x.graph)
        xs_posterior.append(x | ((x + e)(x_data), y))
    xs = xs_posterior

    # Extract posterior means and variances of the latent processes.
    x_means, x_vars = zip(*[(x.mean(x_pred)[:, 0], x.kernel.elwise(x_pred)[:,
                                                                           0])
                            for x in xs])

    # Construct predictions for latent processes.
    lat_preds = [
        B.to_numpy(mean, mean - 2 * (var + L[i])**.5,
                   mean + 2 * (var + L[i])**.5)
        for i, (mean, var) in enumerate(zip(x_means, x_vars))
    ]

    # Pull means through mixing matrix.
    x_means = B.stack(*x_means, axis=0)
    y_means = B.matmul(H, x_means)

    # Pull variances through mixing matrix and add noise.
    x_vars = B.stack(*x_vars, axis=0)
    y_vars = B.matmul(H**2, x_vars + noises_latent[:, None]) + noise_obs

    # Construct predictions for observations.
    obs_preds = [(mean, mean - 2 * var**.5, mean + 2 * var**.5)
                 for mean, var in zip(y_means, y_vars)]

    return lat_preds, obs_preds
Example #3
0
def project(vs, m, y_data, locs):
    """Project the data.

    Args:
        vs (:class:`varz.Vars`): Variable container.
        m (int): Number of latent processes.
        y_data (tensor): Observations.
        locs (tensor): Spatial locations of observations.

    Returns:
        tuple: Tuple containing the projected outputs, the mixing matrix,
            S from the mixing matrix, and the observation noises.
    """
    _, noise_obs, noises_latent = model(vs, m)

    # Construct mixing matrix and projection.
    scales = vs.bnd(B.ones(2), name='scales')
    K = dense(Matern52().stretch(scales)(locs))
    U, S, _ = B.svd(K)
    S = S[:m]
    H = U[:, :m] * S[None, :]**.5
    T = B.transpose(U[:, :m]) / S[:, None]**.5

    # Project data and unstack over latent processes.
    y_proj = B.unstack(B.matmul(T, y_data, tr_b=True))

    # Observation noises:
    noises_obs = noise_obs * B.ones(B.dtype(noise_obs), B.shape(y_data)[1])

    return y_proj, H, S, noises_obs
Example #4
0
def model(vs, m):
    """Construct model.

    Args:
        vs (:class:`varz.Vars`): Variable container.
        m (int): Number of latent processes.

    Returns:
        tuple: Tuple containing a list of the latent processes, the
            observation noise, and the noises on the latent processes.
    """
    g = Graph()

    # Observation noise:
    noise_obs = vs.bnd(0.1, name='noise_obs')

    def make_latent_process(i):
        # Long-term trend:
        variance = vs.bnd(0.9, name=f'{i}/long_term/var')
        scale = vs.bnd(2 * 30, name=f'{i}/long_term/scale')
        kernel = variance * EQ().stretch(scale)

        # Short-term trend:
        variance = vs.bnd(0.1, name=f'{i}/short_term/var')
        scale = vs.bnd(20, name=f'{i}/short_term/scale')
        kernel += variance * Matern12().stretch(scale)

        return GP(kernel, graph=g)

    # Latent processes:
    xs = [make_latent_process(i) for i in range(m)]

    # Latent noises:
    noises_latent = vs.bnd(0.1 * B.ones(m), name='noises_latent')

    return xs, noise_obs, noises_latent
import matplotlib.pyplot as plt
from wbml.plot import tweak

from stheno import B, Measure, GP, EQ, Delta

# Define points to predict at.
x = B.linspace(0, 10, 100)
x_obs = B.linspace(0, 10, 20)

# Constuct a prior:
prior = Measure()
w = lambda x: B.exp(-(x**2) / 0.5)  # Window
b = [(w * GP(EQ(), measure=prior)).shift(xi)
     for xi in x_obs]  # Weighted basis funs
f = sum(b)  # Latent function
e = GP(Delta(), measure=prior)  # Noise
y = f + 0.2 * e  # Observation model

# Sample a true, underlying function and observations.
f_true, y_obs = prior.sample(f(x), y(x_obs))

# Condition on the observations to make predictions.
post = prior | (y(x_obs), y_obs)

# Plot result.
for i, bi in enumerate(b):
    mean, lower, upper = post(bi(x)).marginals()
    kw_args = {"label": "Basis functions"} if i == 0 else {}
    plt.plot(x, mean, style="pred2", **kw_args)
plt.plot(x, f_true, label="True", style="test")
plt.scatter(x_obs, y_obs, label="Observations", style="train", s=20)
import matplotlib.pyplot as plt
from wbml.plot import tweak

from stheno import Measure, GP, EQ, RQ, Linear, Delta, Exp, B

B.epsilon = 1e-10

# Define points to predict at.
x = B.linspace(0, 10, 200)
x_obs = B.linspace(0, 7, 50)

# Construct a latent function consisting of four different components.
prior = Measure()
f_smooth = GP(EQ(), measure=prior)
f_wiggly = GP(RQ(1e-1).stretch(0.5), measure=prior)
f_periodic = GP(EQ().periodic(1.0), measure=prior)
f_linear = GP(Linear(), measure=prior)

f = f_smooth + f_wiggly + f_periodic + 0.2 * f_linear

# Let the observation noise consist of a bit of exponential noise.
e_indep = GP(Delta(), measure=prior)
e_exp = GP(Exp(), measure=prior)

e = e_indep + 0.3 * e_exp

# Sum the latent function and observation noise to get a model for the observations.
y = f + 0.5 * e

# Sample a true, underlying function and observations.
(
Example #7
0
import matplotlib.pyplot as plt
import wbml.out as out
from wbml.plot import tweak

from stheno import B, GP, EQ, PseudoObs

# Define points to predict at.
x = B.linspace(0, 10, 100)
x_obs = B.linspace(0, 7, 50_000)
x_ind = B.linspace(0, 10, 20)

# Construct a prior.
f = GP(EQ().periodic(2 * B.pi))

# Sample a true, underlying function and observations.
f_true = B.sin(x)
y_obs = B.sin(x_obs) + B.sqrt(0.5) * B.randn(*x_obs.shape)

# Compute a pseudo-point approximation of the posterior.
obs = PseudoObs(f(x_ind), (f(x_obs, 0.5), y_obs))

# Compute the ELBO.
out.kv("ELBO", obs.elbo(f.measure))

# Compute the approximate posterior.
f_post = f | obs

# Make predictions with the approximate posterior.
mean, lower, upper = f_post(x).marginal_credible_bounds()

# Plot result.
Example #8
0
import matplotlib.pyplot as plt
from wbml.plot import tweak

from stheno import B, Measure, GP, EQ

# Define points to predict at.
x = B.linspace(0, 10, 100)
x_obs = B.linspace(0, 10, 20)

with Measure() as prior:
    w = lambda x: B.exp(-(x**2) / 0.5)  # Basis function
    b = [(w * GP(EQ())).shift(xi) for xi in x_obs]  # Weighted basis functions
    f = sum(b)

# Sample a true, underlying function and observations.
f_true, y_obs = prior.sample(f(x), f(x_obs, 0.2))

# Condition on the observations to make predictions.
post = prior | (f(x_obs, 0.2), y_obs)

# Plot result.
for i, bi in enumerate(b):
    mean, lower, upper = post(bi(x)).marginal_credible_bounds()
    kw_args = {"label": "Basis functions"} if i == 0 else {}
    plt.plot(x, mean, style="pred2", **kw_args)
plt.plot(x, f_true, label="True", style="test")
plt.scatter(x_obs, y_obs, label="Observations", style="train", s=20)
mean, lower, upper = post(f(x)).marginal_credible_bounds()
plt.plot(x, mean, label="Prediction", style="pred")
plt.fill_between(x, lower, upper, style="pred")
tweak()
        self.ps = ps

    def __add__(self, other):
        return VGP([f + g for f, g in zip(self.ps, other.ps)])

    def lmatmul(self, A):
        m, n = A.shape
        ps = [0 for _ in range(m)]
        for i in range(m):
            for j in range(n):
                ps[i] += A[i, j] * self.ps[j]
        return VGP(ps)


# Define points to predict at.
x = B.linspace(0, 10, 100)
x_obs = B.linspace(0, 10, 10)

# Model parameters:
m = 2
p = 4
H = B.randn(p, m)

# Construct latent functions.
prior = Measure()
us = VGP([GP(EQ(), measure=prior) for _ in range(m)])
fs = us.lmatmul(H)

# Construct noise.
e = VGP([GP(0.5 * Delta(), measure=prior) for _ in range(p)])
Example #10
0
import matplotlib.pyplot as plt
from wbml.plot import tweak

from stheno import B, Measure, GP, EQ

# Define points to predict at.
x = B.linspace(0, 10, 100)

# Construct a prior.
prior = Measure()
f1 = GP(3, EQ(), measure=prior)
f2 = GP(3, EQ(), measure=prior)

# Compute the approximate product.
f_prod = f1 * f2

# Sample two functions.
s1, s2 = prior.sample(f1(x), f2(x))

# Predict.
post = prior | ((f1(x), s1), (f2(x), s2))
mean, lower, upper = post(f_prod(x)).marginals()

# Plot result.
plt.plot(x, s1, label="Sample 1", style="train")
plt.plot(x, s2, label="Sample 2", style="train", ls="--")
plt.plot(x, s1 * s2, label="True product", style="test")
plt.plot(x, mean, label="Approximate posterior", style="pred")
plt.fill_between(x, lower, upper, style="pred")
tweak()
import matplotlib.pyplot as plt
from wbml.plot import tweak

from stheno import B, GP, EQ

# Define points to predict at.
x = B.linspace(0, 10, 100)
x_obs = B.linspace(0, 7, 20)

# Construct a prior.
f = GP(EQ().periodic(5.0))

# Sample a true, underlying function and noisy observations.
f_true, y_obs = f.measure.sample(f(x), f(x_obs, 0.5))

# Now condition on the observations to make predictions.
f_post = f | (f(x_obs, 0.5), y_obs)
mean, lower, upper = f_post(x).marginal_credible_bounds()

# Plot result.
plt.plot(x, f_true, label="True", style="test")
plt.scatter(x_obs, y_obs, label="Observations", style="train", s=20)
plt.plot(x, mean, label="Prediction", style="pred")
plt.fill_between(x, lower, upper, style="pred")
tweak()
plt.savefig("readme_example1_simple_regression.png")
plt.show()