高斯过程 - 我做错了什么?

机器算法验证 Python 高斯过程 插值
2022-03-27 03:32:03

我最近开始研究高斯过程。在我的复习中,我发现一本书指出可以将高斯过程的平均值解释为基函数的组合,即:

(1)f¯(x)=n=1Nαik(xi,x)

其中是高斯过程的训练点数,是 RBF 核,个条目Nkaii

(2)α=[α1,...,αN]T=(K+σn2I)1y

其中是 Gram 矩阵(训练点处内核评估 ×),是长度为的向量,包含预测值在训练点这些方程取自Rasmussen & Williams(第 11 页,方程 2.27)。在我的情况下,我们可以假设,所以KNNKn,m=k(xn,xm)yNxi,i=1,...,Nσn=0

(3)α=[α1,...,αN]T=K1y

现在问题来了:如果我遵循这种形式,我的高斯过程不能正确拟合训练数据。如果我尝试其他实现,高斯过程会正确拟合数据。不幸的是,我需要方程 (1) 形式的高斯过程,因为我想对 (1) wrt求导数。x

您能否检查一下我是否在下面的代码示例中的某个地方出错了?我根据(1)的解决方案被绘制为绿色虚线,我使用的替代方法被绘制为红色虚线。

在此处输入图像描述

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(1)

def evaluate_kernel(x1,x2,hs):
    
    """
    This function takes two arrays of shape (N x D) and (M x D) as well as a 
    vector of bandwidths hs (M) and returns a  (N x M) matrix of RBF kernel 
    evaluations. D is the dimensionality of the parameters; here D = 1
    """

    # Pre-allocate empty matrix
    matrix      = np.zeros((x1.shape[0],x2.shape[0]))
    
    for n in range(x2.shape[0]):
        
        dist        = np.linalg.norm(x1-x2[n,:],axis=1)
        matrix[:,n] = np.exp(-(dist**2)/(2*hs[n]))
        
    return matrix

# Create training samples
N           = 20
x_train     = np.random.uniform(0,1,size=(N,1))
y_train     = np.cos(x_train*2*np.pi)

# Set the bandwidths to 1 for now
hs          = np.ones(N)/100

# Get the Gaussian Process parameters
K           = evaluate_kernel(x_train,x_train,hs)


params      = np.dot(np.linalg.inv(K.copy()),y_train)

# Get the evaluation points
M           = 101
x_test      = np.linspace(0,1,M).reshape((M,1))
K_star      = evaluate_kernel(x_test,x_train,hs)

# Evaluate the posterior mean
mu          = np.dot(K_star,params)

# Plot the results
plt.scatter(x_train,y_train)
plt.plot(x_test,mu,'g:')

# Alternative approach: works -------------------------------------------------

# Alternative approach
# Apply the kernel function to our training points
L = np.linalg.cholesky(K)

# Compute the mean at our test points.
Lk = np.linalg.solve(L, K_star.T)
mu_alt = np.dot(Lk.T, np.linalg.solve(L, y_train)).reshape((101,))

plt.plot(x_test,mu_alt,'r:')
2个回答

高斯过程的协方差矩阵是根据核函数在数据点对上的评估来定义的,即对于训练和测试数据集,我们有子矩阵在这种情况下,高斯过程的预测均值是KkKij=k(xi,xj)XXK=K(X,X)K=K(X,X)

μ=KKy

目测代码,我没有看到任何明显的错误。您需要进行标准调试,因此对于每一步检查输出是否与您对处理输入(值、形状等)的期望相匹配。另外,我建议从简单的、未优化的代码开始,因为过早的优化是万恶之源。例如:为了评估内核,使用老式的 for 循环而不是矢量化代码,此外,您似乎使用来避免转置,而是完全按照等式编写它,并且仅如果它按预期工作,请优化代码。最后,编写单元测试。K=K(X,X)

我认为如果 N 很大,您将从 [0, 1] 密集采样。x_train 中的一些数据点彼此非常接近,导致 K 几乎是奇异的。因此 np.linalg.inv(K) 会给你不稳定的结果。使用 np.linalg.pinv(K) 应该可以解决您的问题。