高斯过程回归 (GPR)
首先定义一个输入空间X,定义一个函数f,它将X上的点映射到空间F。
F上的每个点都是一个随机变量,GPR假设F上的点服从高斯过程,即对于任意有限个点f_1, ..., f_n,他们的联合分布都是一个高斯分布。其中均值由均值函数定义,协方差矩阵由协方差函数定义。
GPR还假设了一个一维的高斯噪音\epsilon,它也是服从高斯分布的一维随机变量。f+\epsilon即表示观测到的样本点y,所有样本点的集合称为Y。由于f无法实际观测到,因此我们把f称为隐函数,y称为观测函数。
以上就是GPR的数据生成过程。
那么对于给定一个新的输入x_\ast,如何预测对应的f_\ast或 y_\ast呢?
首先明确我们要求的是f_\ast的后验分布
p(f_\ast | \bm{x}_\ast, \bm{X}, \bm{y}) = \mathcal{N} (\mu, \sigma^2) (1)
其中\mu=\bm{k_\ast}^T (K+\sigma_n^2 I)^{-1} \bm{y}, \sigma^2 = k_{\ast\ast} - \bm{k_\ast}^T (K + \sigma^2 I)^{-1}\bm{k_\ast}。推理过程可以参考GPML的17页。
注意(1)中包含了GPR模型的超参数,我们采用什么原则优化超参数呢?
这里要说一下,GPML书中写道,"The posterior in eq. (2.5) combines the likelihood and the prior, and captures everything we know about the parameters.",也就是说后验包含了我们知道的所有信息,包括先验和数据。
根据GPML的第五章model selection的109页,有三个级别的参数优化策略。第一层是最大化模型隐函数f的后验概率,第二层是最大化模型超参数\theta的后验概率,最后是将模型类型也当做变量,最大化模型H的后验概率。
实际上我们采用的是第二层策略 (5.5),最大化超参数\theta的后验概率。但是由于分母无法计算且是关于\theta的常数,因此最大化分子部分。分子部分是边际似然函数\log p(\bm{y}|X)和超参数先验分布p(\theta)的乘积。
\log p(\bm{y}|X)=-\frac{1}{2}\bm{y}^T(K+\sigma_n^2I)^{-1}\bm{y} - \frac{1}{2}\log|K+\sigma^2I|-\frac{n}{2}\log2\pi (2)
这个策略又叫第二类型最大似然估计(ML-II)。
例子1
import gpflow
import numpy as np
import matplotlib
%matplotlib inline
matplotlib.rcParams['figure.figsize'] = (12, 6)
plt = matplotlib.pyplot
准备数据
N = 12
X = np.random.rand(N,1)
Y = np.sin(12*X) + 0.66*np.cos(25*X) + np.random.randn(N,1)*0.1 + 3
plt.plot(X, Y, 'kx', mew=2)
构建模型
k = gpflow.kernels.Matern52(1, lengthscales=0.3)
m = gpflow.models.GPR(X, Y, kern=k)
m.likelihood.variance = 0.01
k = gpflow.kernels.Matern52(1, lengthscales=0.3)
meanf = gpflow.mean_functions.Linear(1.0, 0.0)
m = gpflow.models.GPR(X, Y, k, meanf)
m.likelihood.variance = 0.01
优化模型
gpflow.train.ScipyOptimizer().minimize(m)
plot(m)
m.as_pandas_table()
在新的点上预测函数值
xx = np.linspace(-0.1, 1.1, 100).reshape(100, 1)
mean, var = m.predict_y(xx)
源代码解读
在执行gpflow.train.ScipyOptimizer().minimize(m)
时发生了什么?
首先模型初始化、计算目标函数。GPR._build_likelihood()
计算的是gaussian log marginal likelihood,所以GPR的目标函数实际上是对数边际似然+对数参数先验,见下面代码:
def build_objective(self):
likelihood = self._build_likelihood()
priors = []
for param in self.parameters:
unconstrained = param.unconstrained_tensor
constrained = param._build_constrained(unconstrained)
priors.append(param._build_prior(unconstrained, constrained))
prior = self._build_prior(priors)
return self._build_objective(likelihood, prior)
def _build_objective(self, likelihood_tensor, prior_tensor):
func = tf.add(likelihood_tensor, prior_tensor, name='nonneg_objective')
return tf.negative(func, name='objective') # 最小化的是负对数似然函数
其次构建tensorflow计算图,然后再利用L-BFGS-B优化目标函数。
在执行m.predict_y(xx)
时发生了什么?
调用GPR._build_predict()
,根据GPML Regression一章的Algorithm2.1计算预测函数值。
例子2
例子1利用最大化\theta的似然函数(也就是f的边际似然函数)来求得\theta,然后通过解析解得到预测函数值。我们也可以用MCMC方法来预测函数值。这里我们要求的是p(\theta | \bm{X}, \bm{y}),也可以写成p(f_\ast | \bm{x}_\ast, \bm{X}, \bm{y}) = \int p(f_\ast | \bm{x}_\ast, \bm{X}, \bm{y}, \theta) p(\theta) ~d\theta。我们用HMC从先验p(\theta)采样N个点,然后用\sum_i^N p(\bm{y} | \bm{X}, \theta) * p(\theta_i)来近似。
代码
设置超参数的先验
m.clear()
m.kern.lengthscales.prior = gpflow.priors.Gamma(1., 1.)
m.kern.variance.prior = gpflow.priors.Gamma(1., 1.)
m.likelihood.variance.prior = gpflow.priors.Gamma(1., 1.)
m.mean_function.A.prior = gpflow.priors.Gaussian(0., 10.)
m.mean_function.b.prior = gpflow.priors.Gaussian(0., 10.)
m.compile()
m.as_pandas_table()
采样
sampler = gpflow.train.HMC()
samples = sampler.sample(m, num_samples=500, epsilon=0.05, lmin=10, lmax=20, logprobs=False)
求平均
#plot the function posterior
xx = np.linspace(-0.1, 1.1, 100)[:,None]
plt.figure(figsize=(12, 6))
for i, s in samples.iloc[::20].iterrows():
f = m.predict_f_samples(xx, 1, initialize=False, feed_dict=m.sample_feed_dict(s))
plt.plot(xx, f[0,:,:], 'C0', lw=2, alpha=0.1)
plt.plot(X, Y, 'kx', mew=2)
_ = plt.xlim(xx.min(), xx.max())
_ = plt.ylim(0, 6)
至此,GPflow中的GPR就讲完了。
参考文献
[1] GPflow-master/doc/source/notebooks/regression.py
[2] Rasmussen, Carl Edward. "Gaussian processes in machine learning." Advanced lectures on machine learning. Springer, Berlin, Heidelberg, 2004. 63-71.