1.7. 高斯过程#
高斯过程 (GP) 是一种非参数监督学习方法,用于解决回归和概率分类问题。
高斯过程的优点包括
预测会插值观测值(至少对于常规核是如此)。
预测是概率性的(高斯分布),因此可以计算经验置信区间,并根据这些区间来决定是否应在感兴趣的区域重新拟合(在线拟合、自适应拟合)预测。
多功能:可以指定不同的核函数。提供了常用核函数,也可以指定自定义核函数。
高斯过程的缺点包括
我们的实现不是稀疏的,即它们使用所有样本/特征信息来执行预测。
它们在高维空间中效率低下——即当特征数量超过几十个时。
1.7.1. 高斯过程回归 (GPR)#
GaussianProcessRegressor 实现了用于回归目的的高斯过程 (GP)。为此,需要指定 GP 的先验。GP 将结合这个先验和基于训练样本的似然函数。它通过在预测时给出均值和标准差作为输出来提供概率方法。
先验均值假定为恒定且为零(对于 normalize_y=False)或训练数据的均值(对于 normalize_y=True)。先验的协方差通过传入一个 核函数 对象来指定。核函数的超参数在拟合 GaussianProcessRegressor 时通过最大化基于传入的 optimizer 的对数边缘似然 (LML) 来优化。由于 LML 可能有多个局部最优解,可以通过指定 n_restarts_optimizer 来重复启动优化器。第一次运行始终从核函数的初始超参数值开始;后续运行从允许范围内随机选择的超参数值开始。如果初始超参数应保持固定,可以将 None 传递给优化器。
可以通过参数 alpha 来指定目标中的噪声水平,可以作为标量全局指定,也可以按数据点指定。请注意,适度的噪声水平也有助于处理拟合过程中的数值不稳定性,因为它被有效地实现为 Tikhonov 正则化,即通过将其添加到核矩阵的对角线上。明确指定噪声水平的另一种方法是将 WhiteKernel 组件包含在核函数中,它可以从数据中估计全局噪声水平(见下例)。下图显示了通过设置参数 alpha 处理噪声目标的效果。
该实现基于 [RW2006] 的算法 2.1。除了标准 scikit-learn 估计器的 API 之外,GaussianProcessRegressor
允许在没有事先拟合的情况下进行预测(基于 GP 先验)
提供了一个额外的方法
sample_y(X),它在给定输入下评估从 GPR(先验或后验)中抽取的样本暴露了一个方法
log_marginal_likelihood(theta),可以外部用于其他选择超参数的方式,例如通过马尔可夫链蒙特卡洛。
示例
1.7.2. 高斯过程分类 (GPC)#
GaussianProcessClassifier 实现了用于分类目的的高斯过程 (GP),更具体地说用于概率分类,其中测试预测采用类概率的形式。GaussianProcessClassifier 在潜在函数 \(f\) 上放置了一个 GP 先验,然后通过链接函数 \(\pi\) 进行压缩以获得概率分类。潜在函数 \(f\) 是一个所谓的干扰函数,其值未被观测到,并且本身并不重要。它的目的是允许模型的方便 формулировка,并且 \(f\) 在预测过程中被移除(积分出去)。GaussianProcessClassifier 实现了 logistic 链接函数,其积分不能解析计算,但在二元情况下很容易近似。
与回归设置不同,即使对于 GP 先验,潜在函数 \(f\) 的后验也不是高斯分布,因为高斯似然不适合离散类标签。相反,使用了对应于 logistic 链接函数(logit)的非高斯似然。GaussianProcessClassifier 基于拉普拉斯近似将非高斯后验近似为高斯分布。更多细节可以在 [RW2006] 的第 3 章中找到。
GP 先验均值假定为零。先验的协方差通过传入一个 核函数 对象来指定。核函数的超参数在拟合 GaussianProcessRegressor 时通过最大化基于传入的 optimizer 的对数边缘似然 (LML) 来优化。由于 LML 可能有多个局部最优解,可以通过指定 n_restarts_optimizer 来重复启动优化器。第一次运行始终从核函数的初始超参数值开始;后续运行从允许范围内随机选择的超参数值开始。如果初始超参数应保持固定,可以将 None 传递给优化器。
在某些情况下,需要有关潜在函数 \(f\) 的信息(即 [RW2006] 中方程 (3.21) 和 (3.24) 中描述的均值 \(\bar{f_*}\) 和方差 \(\text{Var}[f_*]\))。GaussianProcessClassifier 通过 latent_mean_and_variance 方法提供对这些量的访问。
GaussianProcessClassifier 通过执行“一对多”或“一对一”的训练和预测来支持多类分类。在“一对多”中,为每个类拟合一个二元高斯过程分类器,训练该分类器以将此类与其余类分离。在“一对一”中,为每对类拟合一个二元高斯过程分类器,训练该分类器以分离这两个类。这些二元预测器的预测被组合成多类预测。有关更多详细信息,请参阅关于多类分类的部分。
在高斯过程分类的情况下,“一对一”在计算上可能更便宜,因为它必须解决许多只涉及整个训练集子集的问题,而不是解决整个数据集上的少数问题。由于高斯过程分类的计算复杂度与数据集大小呈立方关系,这可能会快得多。然而,请注意,“一对一”不支持预测概率估计,只支持普通预测。此外,请注意 GaussianProcessClassifier 尚未在内部实现真正的多类拉普拉斯近似,而是如上所述,基于内部解决几个二元分类任务,并使用“一对多”或“一对一”组合。
1.7.3. GPC 示例#
1.7.3.1. GPC 的概率预测#
此示例说明了 GPC 对于 RBF 核在不同超参数选择下的预测概率。第一张图显示了 GPC 在任意选择的超参数和对应于最大对数边缘似然 (LML) 的超参数下的预测概率。
虽然通过优化 LML 选择的超参数具有明显更大的 LML,但根据测试数据上的对数损失,它们的性能稍差。图表显示这是因为它们在类别边界处表现出类概率的急剧变化(这是好的),但在远离类别边界的地方预测概率接近 0.5(这是不好的)。这种不良影响是由 GPC 内部使用的拉普拉斯近似引起的。
第二张图显示了不同核函数超参数选择下的对数边缘似然,用黑点突出显示了第一张图中使用的两种超参数选择。
1.7.3.2. GPC 在 XOR 数据集上的说明#
此示例说明了 GPC 在 XOR 数据上的应用。比较了平稳、各向同性核 (RBF) 和非平稳核 (DotProduct)。在这个特定数据集上,DotProduct 核获得了明显更好的结果,因为类别边界是线性的并且与坐标轴重合。然而,在实践中,像 RBF 这样的平稳核通常会获得更好的结果。
1.7.3.3. GPC 在 iris 数据集上的高斯过程分类 (GPC)#
此示例说明了 GPC 对于 iris 数据集的二维版本上的各向同性核和各向异性 RBF 核的预测概率。这说明了 GPC 对非二元分类的适用性。各向异性 RBF 核通过为两个特征维度分配不同的长度尺度来获得稍高的对数边缘似然。
1.7.4. 高斯过程的核函数#
核函数(在 GP 背景下也称为“协方差函数”)是 GP 的关键组成部分,它决定了 GP 先验和后验的形状。它们通过定义两个数据点之间的“相似性”以及相似数据点应具有相似目标值的假设来编码对所学习函数的假设。核函数可以分为两类:平稳核仅取决于两个数据点之间的距离,而不取决于它们的绝对值 \(k(x_i, x_j)= k(d(x_i, x_j))\),因此在输入空间中平移不变;而非平稳核也取决于数据点的特定值。平稳核可以进一步细分为各向同性核和各向异性核,其中各向同性核在输入空间中也旋转不变。有关更多详细信息,请参阅 [RW2006] 的第 4 章。此示例展示了如何定义离散数据上的自定义核函数。有关如何最好地组合不同核函数的指导,请参阅 [Duv2014]。
高斯过程核函数 API#
核函数 Kernel 的主要用途是计算 GP 在数据点之间的协方差。为此,可以调用核函数的 __call__ 方法。此方法可用于计算 2d 数组 X 中所有数据点对的“自协方差”,或计算 2d 数组 X 中的数据点与 2d 数组 Y 中的数据点所有组合的“交叉协方差”。以下恒等式对所有核函数 k(WhiteKernel 除外)成立:k(X) == K(X, Y=X)
如果只使用自协方差的对角线,可以调用核函数的 diag() 方法,这比等效调用 __call__ 更高效:np.diag(k(X, X)) == k.diag(X)
核函数由超参数向量 \(\theta\) 参数化。这些超参数可以控制核函数的长度尺度或周期性(见下文)。所有核函数都支持通过在 __call__ 方法中设置 eval_gradient=True 来计算核函数自协方差对 \(log(\theta)\) 的解析梯度。即返回一个 (len(X), len(X), len(theta)) 数组,其中条目 [i, j, l] 包含 \(\frac{\partial k_\theta(x_i, x_j)}{\partial log(\theta_l)}\)。该梯度被高斯过程(回归器和分类器)用于计算对数边缘似然的梯度,进而用于通过梯度上升确定使对数边缘似然最大化的 \(\theta\) 值。对于每个超参数,需要在创建核函数实例时指定初始值和边界。可以通过核函数对象的属性 theta 获取和设置 \(\theta\) 的当前值。此外,可以通过核函数的属性 bounds 访问超参数的边界。请注意,这两个属性(theta 和 bounds)都返回内部使用值的对数转换值,因为这些值通常更适合基于梯度的优化。每个超参数的规范以 Hyperparameter 实例的形式存储在相应的核函数中。请注意,使用名为“x”的超参数的核函数必须具有属性 self.x 和 self.x_bounds。
所有核函数的抽象基类是 Kernel。Kernel 实现了与 BaseEstimator 类似的接口,提供 get_params()、set_params() 和 clone() 方法。这允许通过元估计器(如 Pipeline 或 GridSearchCV)设置核函数值。请注意,由于核函数的嵌套结构(通过应用核函数运算符,见下文),核函数参数的名称可能会变得相对复杂。通常,对于二元核函数运算符,左操作数的参数前缀为 k1__,右操作数的参数前缀为 k2__。另一个方便的方法是 clone_with_theta(theta),它返回核函数的克隆版本,但超参数设置为 theta。一个说明性示例
>>> from sklearn.gaussian_process.kernels import ConstantKernel, RBF
>>> kernel = ConstantKernel(constant_value=1.0, constant_value_bounds=(0.0, 10.0)) * RBF(length_scale=0.5, length_scale_bounds=(0.0, 10.0)) + RBF(length_scale=2.0, length_scale_bounds=(0.0, 10.0))
>>> for hyperparameter in kernel.hyperparameters: print(hyperparameter)
Hyperparameter(name='k1__k1__constant_value', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
Hyperparameter(name='k1__k2__length_scale', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
Hyperparameter(name='k2__length_scale', value_type='numeric', bounds=array([[ 0., 10.]]), n_elements=1, fixed=False)
>>> params = kernel.get_params()
>>> for key in sorted(params): print("%s : %s" % (key, params[key]))
k1 : 1**2 * RBF(length_scale=0.5)
k1__k1 : 1**2
k1__k1__constant_value : 1.0
k1__k1__constant_value_bounds : (0.0, 10.0)
k1__k2 : RBF(length_scale=0.5)
k1__k2__length_scale : 0.5
k1__k2__length_scale_bounds : (0.0, 10.0)
k2 : RBF(length_scale=2)
k2__length_scale : 2.0
k2__length_scale_bounds : (0.0, 10.0)
>>> print(kernel.theta) # Note: log-transformed
[ 0. -0.69314718 0.69314718]
>>> print(kernel.bounds) # Note: log-transformed
[[ -inf 2.30258509]
[ -inf 2.30258509]
[ -inf 2.30258509]]
所有高斯过程核函数都可以与 sklearn.metrics.pairwise 互操作,反之亦然:Kernel 子类的实例可以作为 metric 传递给来自 sklearn.metrics.pairwise 的 pairwise_kernels。此外,pairwise 中的核函数可以通过使用包装类 PairwiseKernel 用作 GP 核函数。唯一的注意事项是超参数的梯度不是解析的,而是数值的,并且所有这些核函数只支持各向同性距离。参数 gamma 被视为超参数并可能被优化。其他核函数参数在初始化时直接设置并保持固定。
1.7.4.1. 基本核函数#
ConstantKernel 核函数可以用作 Product 核函数的一部分,其中它缩放另一个因子(核函数)的大小,或者用作 Sum 核函数的一部分,其中它修改高斯过程的均值。它依赖于一个参数 \(constant\_value\)。它的定义是
WhiteKernel 核函数的主要用途是作为和核函数的一部分,其中它解释了信号的噪声分量。调整其参数 \(noise\_level\) 对应于估计噪声水平。它的定义是
1.7.4.2. 核函数运算符#
核函数运算符接受一个或两个基本核函数并将它们组合成一个新的核函数。Sum 核函数接受两个核函数 \(k_1\) 和 \(k_2\) 并通过 \(k_{sum}(X, Y) = k_1(X, Y) + k_2(X, Y)\) 组合它们。Product 核函数接受两个核函数 \(k_1\) 和 \(k_2\) 并通过 \(k_{product}(X, Y) = k_1(X, Y) * k_2(X, Y)\) 组合它们。Exponentiation 核函数接受一个基本核函数和一个标量参数 \(p\) 并通过 \(k_{exp}(X, Y) = k(X, Y)^p\) 组合它们。请注意,魔术方法 __add__、__mul___ 和 __pow__ 在 Kernel 对象上被重写,因此可以使用例如 RBF() + RBF() 作为 Sum(RBF(), RBF()) 的快捷方式。
1.7.4.3. 径向基函数 (RBF) 核函数#
RBF 核函数是一个平稳核函数。它也被称为“平方指数”核函数。它由一个长度尺度参数 \(l>0\) 参数化,该参数可以是标量(核函数的各向同性变体)或与输入 \(x\) 具有相同维度的向量(核函数的各向异性变体)。核函数由下式给出
其中 \(d(\cdot, \cdot)\) 是欧几里得距离。该核函数是无限可微的,这意味着以该核函数作为协方差函数的 GP 具有所有阶的均方导数,因此非常平滑。RBF 核函数产生的高斯过程的先验和后验如下图所示
1.7.4.4. Matérn 核函数#
Matern 核函数是一个平稳核函数,也是 RBF 核函数的推广。它有一个额外的参数 \(\nu\),用于控制所得函数的平滑度。它由一个长度尺度参数 \(l>0\) 参数化,该参数可以是标量(核函数的各向同性变体)或与输入 \(x\) 具有相同维度的向量(核函数的各向异性变体)。
Matérn 核函数的数学实现#
核函数由下式给出
其中 \(d(\cdot,\cdot)\) 是欧几里得距离,\(K_\nu(\cdot)\) 是修正贝塞尔函数,\(\Gamma(\cdot)\) 是伽马函数。当 \(\nu\rightarrow\infty\) 时,Matérn 核函数收敛到 RBF 核函数。当 \(\nu = 1/2\) 时,Matérn 核函数与绝对指数核函数相同,即
特别是,\(\nu = 3/2\)
和 \(\nu = 5/2\)
是学习非无限可微函数(如 RBF 核函数所假定的)但至少可微一次 (\(\nu = 3/2\)) 或两次 (\(\nu = 5/2\)) 的流行选择。
通过 \(\nu\) 控制学习函数的平滑度的灵活性允许适应真实潜在函数关系的属性。
Matérn 核函数产生的高斯过程的先验和后验如下图所示
有关 Matérn 核函数的不同变体的更多详细信息,请参阅 [RW2006],第 84 页。
1.7.4.5. 有理二次核函数#
RationalQuadratic 核函数可以看作是具有不同特征长度尺度的 RBF 核函数的尺度混合(无限和)。它由一个长度尺度参数 \(l>0\) 和一个尺度混合参数 \(\alpha>0\) 参数化。目前仅支持 \(l\) 为标量的各向同性变体。核函数由下式给出
RationalQuadratic 核函数产生的高斯过程的先验和后验如下图所示
1.7.4.6. Exp-Sine-Squared 核函数#
ExpSineSquared 核函数允许对周期性函数进行建模。它由一个长度尺度参数 \(l>0\) 和一个周期性参数 \(p>0\) 参数化。目前仅支持 \(l\) 为标量的各向同性变体。核函数由下式给出
ExpSineSquared 核函数产生的高斯过程的先验和后验如下图所示
1.7.4.7. 点积核函数#
DotProduct 核函数是非平稳的,可以通过在线性回归中对 \(x_d (d = 1, . . . , D)\) 的系数设置 \(N(0, 1)\) 先验和对偏差设置 \(N(0, \sigma_0^2)\) 先验来获得。DotProduct 核函数对围绕原点的坐标旋转是不变的,但对平移是不变的。它由一个参数 \(\sigma_0^2\) 参数化。对于 \(\sigma_0^2 = 0\),该核函数被称为齐次线性核函数,否则为非齐次。核函数由下式给出
DotProduct 核函数通常与幂运算结合使用。下图显示了一个指数为 2 的示例