Gaussian Processes
Noise-Free Demonstration
We’ll start with the ‘Noise-free’ gaussian process. The matrix labeling is in keeping with Murphy 2012 and Rasmussen and Williams 2006. See those sources for more detail. Murphy’s original Matlab code can be found here, though the relevant files are housed alongside this code in my original repo (*.m
files) and the supplemental section.
The goal of this code is to plot samples from the prior and posterior predictive of a gaussian process in which y = sin(x)
. It will reproduce figure 15.2 in Murphy 2012 and 2.2 in Rasmussen and Williams 2006.
Data Setup
library(tidyverse)
= 1 # for l, sigma_f, see note at covariance function
l = 1
sigma_f = 1e-8 # see note at K_starstar
k_eps = 5 # number of prior draws
n_prior = 5 # number of posterior predictive draws n_post_pred
Generate noise-less training data.
= c(-4, -3, -2, -1, 1)
X_train = sin(X_train)
y_train = length(X_train)
n_train
= seq(-5, 5, .2)
X_test = length(X_test) n_test
Functions
The mean function. In this case the mean equals 0.
<- function(x) {
gp_mu map_dbl(x, function(x) x = 0)
}
The covariance function. Here it is the squared exponential kernel. l
is the horizontal scale, sigma_f
is the vertical scale.
<- function(x, l = 1, sigma_f = 1){
gp_K * exp( -(1/(2 * l^2)) * as.matrix(dist(x, upper = TRUE, diag = TRUE) ^ 2) )
sigma_f }
Visualize the prior distribution
Data setup for the prior and plot.
= seq(-5, 5, .2)
x_prior
= MASS::mvrnorm(
y_prior n = n_prior,
mu = gp_mu(x_prior),
Sigma = gp_K(x_prior, l = l, sigma_f = sigma_f)
)
= data.frame(
prior_data x = x_prior,
y = t(y_prior),
sd = apply(y_prior, 2, sd)) %>%
pivot_longer(-c(x, sd), names_to = 'variable')
= ggplot(aes(x = x, y = value), data = prior_data) +
g1 geom_line(aes(group = variable), color = '#FF550080', alpha = .5) +
labs(title = 'Prior')
g1
Generate the posterior predictive distribution
Create K
, K*
, and K**
matrices as defined in the texts.
= gp_K(X_train, l = l, sigma_f = sigma_f)
K = gp_K(c(X_train, X_test), l = l, sigma_f = sigma_f) # initial matrix
K_
= K_[1:n_train, (n_train+1):ncol(K_)] # dim = N x N*
K_star = t(K_star) # dim = N* x N
tK_star = K_[(n_train+1):nrow(K_), (n_train+1):ncol(K_)] + # dim = N* x N*
K_starstar * diag(n_test) # the k_eps part is for positive definiteness
k_eps
= solve(K) Kinv
Calculate posterior mean and covariance.
= gp_mu(X_test) + t(K_star) %*% Kinv %*% (y_train - gp_mu(X_train))
post_mu = K_starstar - t(K_star) %*% Kinv %*% K_star
post_K = diag(post_K)
s2 # R = chol(post_K)
# L = t(R) # L is used in alternative formulation below based on gaussSample.m
Generate draws from posterior predictive.
= data.frame(
y_pp t(MASS::mvrnorm(n_post_pred, mu = post_mu, Sigma = post_K))
)
# alternative if using R and L above
# y_pp = data.frame(replicate(n_post_pred, post_mu + L %*% rnorm(post_mu)))
Visualize the Posterior Predictive Distribution
Reshape data for plotting and create the plot.
= data.frame(
pp_data x = X_test,
y = y_pp,
se_lower = post_mu - 2 * sqrt(s2),
se_upper = post_mu + 2 * sqrt(s2)
%>%
) pivot_longer(starts_with('y'), names_to = 'variable')
= ggplot(aes(x = x, y = value), data = pp_data) +
g2 geom_ribbon(aes(ymin = se_lower, ymax = se_upper, group = variable),
fill = 'gray92') +
geom_line(aes(group = variable), color = '#FF550080') +
geom_point(aes(x = X_train, y = y_train), data = data.frame(X_train, y_train)) +
labs(title = 'Posterior Predictive')
g2
Plot prior and posterior predictive together.
library(patchwork)
+ g2 g1
Noisy Demonstration
‘Noisy’ gaussian process demo. The matrix labeling is in keeping with Murphy 2012 and Rasmussen and Williams 2006. See those sources for more detail. Murphy’s original Matlab code can be found here, though the relevant files are housed alongside this code in my original repo (*.m
files).
The goal of this code is to plot samples from the prior and posterior predictive
of a gaussian process in which y = sin(x) + noise
. It will reproduce an example
akin to figure 15.3 in Murphy 2012.
Data Setup
= 1 # for l, sigma_f, sigma_n, see note at covariance function
l = 1
sigma_f = .25
sigma_n = 1e-8 # see note at Kstarstar
k_eps = 5 # number of prior draws
n_prior = 5 # number of posterior predictive draws
n_post_pred
= 15 * (runif(20) - .5)
X_train = length(X_train)
n_train
# kept sine function for comparison to noise free result
= sin(X_train) + rnorm(n = n_train, sd = .1)
y_train
= seq(-7.5, 7.5, length = 200)
X_test = length(X_test) n_test
Functions
The mean function. In this case the mean equals 0.
<- function(x) {
gp_mu map_dbl(x, function(x) x = 0)
}
The covariance function. Here it is the squared exponential kernel. l
is the horizontal scale, sigma_f
is the vertical scale, and, unlike the previous function, sigma_n
the noise.
<- function(
gp_K
x,y = NULL,
l = 1,
sigma_f = 1,
sigma_n = .5
) {
if(!is.null(y)){
* exp( -(1/(2 * l^2)) * as.matrix(dist(x, upper = TRUE, diag = TRUE) ^ 2) ) +
sigma_f *diag(length(x))
sigma_n
}else{
* exp( -(1/(2 * l^2)) * as.matrix(dist(x, upper = TRUE, diag = TRUE) ^ 2) )
sigma_f
} }
Visualize the prior distribution
Data setup.
= seq(-5, 5, .2)
x_prior
= MASS::mvrnorm(
y_prior n = n_prior,
mu = gp_mu(x_prior),
Sigma = gp_K(
x_prior,l = l,
sigma_f = sigma_f,
sigma_n = sigma_n
) )
Plot.
= data.frame(
prior_data x = x_prior,
y = t(y_prior),
sd = apply(y_prior, 2, sd)) %>%
pivot_longer(-c(x, sd), names_to = 'variable')
= ggplot(aes(x = x, y = value), data = prior_data) +
g1 geom_line(aes(group = variable), color = '#FF550080', alpha = .5) +
labs(title = 'Prior')
g1
Generate the posterior predictive distribution
Create Ky, K*, and K** matrices as defined in the texts.
= gp_K(
Ky x = X_train,
y = y_train,
l = l,
sigma_f = sigma_f,
sigma_n = sigma_n
)
# initial matrix
= gp_K(
K_ c(X_train, X_test),
l = l,
sigma_f = sigma_f,
sigma_n = sigma_n
)
= K_[1:n_train, (n_train+1):ncol(K_)] # dim = N x N*
Kstar = t(Kstar) # dim = N* x N
tKstar = K_[(n_train+1):nrow(K_), (n_train+1):ncol(K_)] + # dim = N* x N*
Kstarstar *diag(n_test) # the k_eps part is for positive definiteness
k_eps
= solve(Ky) Kyinv
Calculate posterior mean and covariance.
= gp_mu(X_test) + tKstar %*% Kyinv %*% (y_train - gp_mu(X_train))
post_mu = Kstarstar - tKstar %*% Kyinv %*% Kstar
post_K = diag(post_K)
s2
# R = chol(post_K)
# L = t(R) # L is used in alternative formulation below based on gaussSample.m
Generate draws from posterior predictive.
= data.frame(t(MASS::mvrnorm(n_post_pred, mu = post_mu, Sigma = post_K)))
y_pp
# alternative
# y_pp = data.frame(replicate(n_post_pred, post_mu + L %*% rnorm(post_mu)))
Visualize the Posterior Predictive Distribution
Reshape data for plotting and create the plot.
= data.frame(
pp_data x = X_test,
y = y_pp,
fmean = post_mu,
se_lower = post_mu - 2 * sqrt(s2),
se_upper = post_mu + 2 * sqrt(s2)
%>%
) pivot_longer(starts_with('y'), names_to = 'variable')
= ggplot(aes(x = x, y = value), data = pp_data) +
g2 geom_ribbon(aes(ymin = se_lower, ymax = se_upper, group = variable),
fill = 'gray92') +
geom_line(aes(group = variable), color = '#FF550080') +
geom_point(aes(x = X_train, y = y_train), data = data.frame(X_train, y_train)) +
labs(title = 'Posterior Predictive')
g2
Plot prior and posterior predictive together.
library(patchwork)
+ g2 g1
Source
Original code available at: https://github.com/m-clark/Miscellaneous-R-Code/blob/master/ModelFitting/gp%20Examples/gaussianprocessNoiseFree.R (noise-free)