高斯过程(一)

我们来考虑一个简单的线性回归问题:

  • 假设我们需要建模的函数为f:RRf:R\rightarrow R
  • 我们有一些观察数据$ \bold x = [x_1, …,x_N]^T, \bold y=[y_1,…,y_N]^T, y_i=f(x_i)$
  • 我们想预测函数ff在一些未观察点xx_*的值

采用高斯过程建模函数

高斯过程的核心思想是采用多元高斯分布建模函数。输入空间的每一个点都对应一个随机变量,所有这些随机变量的联合分布符合多元高斯分布。

那么,上面两句话是什么意思呢?我们从简单的二元高斯过程开始。假设输入x0,x1x_0,x_1对应的函数值y0,y1y_0,y_1满足二元高斯分布:

在这里插入图片描述

通常我们以3维的钟形概率密度函数的形式表示这个分布,这里我们不这样做,而是采样。我们采样10次,y0y_0的值对应x=0x=0y1y_1的值对应x=1x=1,并用直线连接两点:

def plot_unit_gaussian_samples(D):
    p = figure(plot_width=800, plot_height=500,
               title='Samples from a unit {}D Gaussian'.format(D))

    xs = np.linspace(0, 1, D)
    for color in Category10[10]:
        ys = np.random.multivariate_normal(np.zeros(D), np.eye(D))
        p.line(xs, ys, line_width=1, color=color)
    return p

show(plot_unit_gaussian_samples(2))

在这里插入图片描述

如上图,看起来我们采样了10个线性函数。如果我们采用20维高斯分布呢?

show(plot_unit_gaussian_samples(20))

在这里插入图片描述

曲线看起来更像是某种函数了,但是噪音太大了。我们思考一下我们想从样本中得到什么以及如何改进高斯分布使得曲线更平滑呢。

多元高斯分布有两个参数,平均值和协方差矩阵。如果我们改变平均值,我们只会改变取值的整体趋势,而不会改变锯齿形状。所以我们让高斯过程的均值保持为0。

我们想达到一种平滑的效果:如果两个点距离相近,则函数的取值页比较接近。

N维高斯分布的的协方差矩阵\sum的维度为N×NN\times N,第(i,j)(i,j)个元素为ij=cov(yi,yj)\sum_{ij}=cov(y_i,y_j).也就是说\sum是一个对称矩阵,保存了随机变量的所有协方差值。

使用核函数平滑函数

那么我们应该如何定义协方差函数呢?我们选择平方指数核:

k(x,x)=exp((xx)22)k(x,x')=exp(-\frac{(x-x')^2}{2})

x=xx=x'时函数取值为1,随x,xx,x'远离而趋近于0。

因此为了达到平滑的效果,我们定义xi,xjx_i,x_j点对应的随机变量yi,yjy_i,y_j的协方差为cov(yi,yj)=k(xi,xj)cov(y_i,y_j)=k(x_i,x_j). xi,xjx_i,x_j越接近,yi,yjy_i,y_j的协方差值越高。

采用以上的协方差矩阵,我们再一次从20维高斯分布中采样:

def k(xs, ys, sigma=1, l=1):
    """Sqared Exponential kernel as above but designed to return the whole
    covariance matrix - i.e. the pairwise covariance of the vectors xs & ys.
    Also with two parameters which are discussed at the end."""

    # Pairwise difference matrix.
    dx = np.expand_dims(xs, 1) - np.expand_dims(ys, 0)
    return (sigma ** 2) * np.exp(-((dx / l) ** 2) / 2)

def m(x):
    """The mean function. As discussed, we can let the mean always be zero."""
    return np.zeros_like(x)

p = figure(plot_width=800, plot_height=500)
D = 20
xs = np.linspace(0, 1, D)
for color in Category10[10]:
    ys = np.random.multivariate_normal(m(xs), k(xs, xs))
    p.circle(xs, ys, size=3, color=color)
    p.line(xs, ys, line_width=1, color=color)

show(p)

在这里插入图片描述

我们增加维度,看一下采样的结果:

n = 100
xs = np.linspace(-5, 5, n)
K = k(xs, xs)
mu = m(xs)

p = figure(plot_width=800, plot_height=500)

for color in Category10[5]:
    ys = np.random.multivariate_normal(mu, K)
    p.line(xs, ys, line_width=2, color=color)
show(p)

在这里插入图片描述

采用先验和观察进行预测

现在我们有了一个函数分布,如何使用训练数据去建模一个隐藏的函数并预测取值呢?

首先我们需要一些训练数据,为了得到训练数据,我们首先创建一个秘密的函数ff.

这里我们采用多项式函数:

f(x)=0.03x5+0.2x40.1x32.4x22.5x+6f(x)=0.03x^5 + 0.2x^4 - 0.1x^3 - 2.4x^2 - 2.5x + 6

当然我们也可以选择其他函数

# coefs[i] is the coefficient of x^i
coefs = [6, -2.5, -2.4, -0.1, 0.2, 0.03]

def f(x):
    total = 0
    for exp, coef in enumerate(coefs):
        total += coef * (x ** exp)
    return total

xs = np.linspace(-5.0, 3.5, 100)
ys = f(xs)

p = figure(plot_width=800, plot_height=400, x_axis_label='x',
           y_axis_label='f(x)', title='The hidden function f(x)')
p.line(xs, ys, line_width=2)
show(p)

在这里插入图片描述

目前我们采用多元高斯分布建模p(yx)p(\bold y | \bold x):

p(yx)=N(ym(x),K)p(\bold y | \bold x) = N(\bold y|m(\bold x), \bold K)

其中K=k(x,x),m(X)=0\bold K = k(\bold x, \bold x), m(\bold X) = \bold 0

这是一个先验的分布,表示在未得到任何观察的情况下给定输入 x\bold x输出y\bold y的分布。

我们有观察数据输入为x,\bold x,,输出$ \bold y = f(\bold x),, 以及需要预测的数据输入\bold x_,, 需要预测值\bold y_ = f(\bold x_*)$.

x_obs = np.array([-4, -1.5, 0, 1.5, 2.5, 2.7])
y_obs = f(x_obs)

x_s = np.linspace(-8, 7, 80)

回忆高斯过程的定义,我们如此来建模y,y\bold y,\bold y_*的联合分布:

在这里插入图片描述

其中:K=k(x,x),K=k(x,x),K=k(xx),m(x)=0,m(x)=0\bold K=k(\bold x,\bold x),\bold K_*=k(\bold x,\bold x_*),\bold K_{**}=k(\bold x_*, \bold x_*), m(\bold x) = \bold 0, m(\bold x_*)=\bold 0.

但是这是对p(y,yx,x)p(\bold y,\bold y_*|\bold x, \bold x_*)的建模,我们需要的是y\bold y_*的分布,这里不做推导,直接给出结果:

p(yx,x,y)=N(yμ,)p(\bold y_*|\bold x_*,\bold x,\bold y) = N(\bold y_*|\mu_*,\sum_*)

其中

μ=m(x)+KTK1(ym(x))\mu_*=m(x_*)+\bold K_*^T\bold K^{-1}(\bold y-m(\bold x))

=KKTK1K\sum_*=\bold K_{**}-\bold K_*^T\bold K^{-1}\bold K_*

目前我们有了yy_*的后验概率分布。

K = k(x_obs, x_obs)
K_s = k(x_obs, x_s)
K_ss = k(x_s, x_s)
K_sTKinv = np.matmul(K_s.T, np.linalg.pinv(K))
mu_s = m(x_s) + np.matmul(K_sTKinv, y_obs - m(x_obs))
Sigma_s = K_ss - np.matmul(K_sTKinv, K_s)

我们可以采用这两个参数从条件概率分布中采样:

p = figure(plot_width=800, plot_height=600, y_range=(-7, 8))

y_true = f(x_s)
p.line(x_s, y_true, line_width=3, color='black', alpha=0.4,
       line_dash='dashed', legend='True f(x)')
p.cross(x_obs, y_obs, size=20, legend='Training data')

stds = np.sqrt(Sigma_s.diagonal())

stds = np.sqrt(Sigma_s.diagonal())
err_xs = np.concatenate((x_s, np.flip(x_s, 0)))
err_ys = np.concatenate((mu_s + 2 * stds, np.flip(mu_s - 2 * stds, 0)))
p.patch(err_xs, err_ys, alpha=0.2, line_width=0, color='grey',
        legend='Uncertainty')


for color in Category10[3]:
    y_s = np.random.multivariate_normal(mu_s, Sigma_s)
    p.line(x_s, y_s, line_width=1, color=color)
    
p.line(x_s, mu_s, line_width=3, color='blue', alpha=0.4, legend='Mean')
show(p)


在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章