我們來考慮一個簡單的線性迴歸問題:
- 假設我們需要建模的函數爲
- 我們有一些觀察數據$ \bold x = [x_1, …,x_N]^T, \bold y=[y_1,…,y_N]^T, y_i=f(x_i)$
- 我們想預測函數在一些未觀察點的值
採用高斯過程建模函數
高斯過程的核心思想是採用多元高斯分佈建模函數。輸入空間的每一個點都對應一個隨機變量,所有這些隨機變量的聯合分佈符合多元高斯分佈。
那麼,上面兩句話是什麼意思呢?我們從簡單的二元高斯過程開始。假設輸入對應的函數值滿足二元高斯分佈:
通常我們以3維的鐘形概率密度函數的形式表示這個分佈,這裏我們不這樣做,而是採樣。我們採樣10次,的值對應,的值對應,並用直線連接兩點:
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維高斯分佈的的協方差矩陣的維度爲,第個元素爲.也就是說是一個對稱矩陣,保存了隨機變量的所有協方差值。
使用核函數平滑函數
那麼我們應該如何定義協方差函數呢?我們選擇平方指數核:
當時函數取值爲1,隨遠離而趨近於0。
因此爲了達到平滑的效果,我們定義點對應的隨機變量的協方差爲. 越接近,的協方差值越高。
採用以上的協方差矩陣,我們再一次從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)
採用先驗和觀察進行預測
現在我們有了一個函數分佈,如何使用訓練數據去建模一個隱藏的函數並預測取值呢?
首先我們需要一些訓練數據,爲了得到訓練數據,我們首先創建一個祕密的函數.
這裏我們採用多項式函數:
當然我們也可以選擇其他函數
# 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)
目前我們採用多元高斯分佈建模:
其中
這是一個先驗的分佈,表示在未得到任何觀察的情況下給定輸入 輸出的分佈。
我們有觀察數據輸入爲,輸出$ \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)
回憶高斯過程的定義,我們如此來建模的聯合分佈:
其中:.
但是這是對的建模,我們需要的是的分佈,這裏不做推導,直接給出結果:
其中
目前我們有了的後驗概率分佈。
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)