高斯過程(一)

我們來考慮一個簡單的線性迴歸問題:

  • 假設我們需要建模的函數爲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)


在這裏插入圖片描述

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