高斯过程二分类:为何GPy的方差远小于scikit-learn?
高斯过程二分类:GPy与scikit-learn的核方差差异问题及解决方法
问题背景
我正在学习高斯过程二分类,基于Martin Krasser博客的示例,在1D玩具问题上对比GPy与scikit-learn的实现。两者均采用RBF核,优化超参数后长度尺度相近,但核方差差异极大——GPy的方差明显偏小。
核心疑问:如何修改GPy实现以获得与scikit-learn相近的结果? 推测差异源于算法内部实现,但无法确定具体根源。
实现环境
Python 3.9、GPy 1.13.2、scikit-learn 1.5.1
可复现代码
import numpy as np from scipy.stats import bernoulli from scipy.special import expit as sigmoid ############################## # Part 1: 玩具数据集生成 ############################## np.random.seed(0) X = np.arange(0, 5, 0.05).reshape(-1, 1) X_test = np.arange(-2, 7, 0.1).reshape(-1, 1) a = np.sin(X * np.pi * 0.5) * 2 # 潜在函数 t = bernoulli.rvs(sigmoid(a)) # 伯努利训练数据(0和1) ##################################### # Part 2: scikit-learn 实现 ##################################### from sklearn.gaussian_process import GaussianProcessClassifier from sklearn.gaussian_process.kernels import ConstantKernel, RBF rbf = ConstantKernel(1.0, constant_value_bounds=(1e-3, 10)) \ * RBF(length_scale=1.0, length_scale_bounds=(1e-3, 10)) gpc = GaussianProcessClassifier( kernel=rbf, optimizer='fmin_l_bfgs_b', n_restarts_optimizer=10) # 原代码中X_scaled未定义,此处修正为原始X gpc.fit(X, t.ravel()) print(gpc.kernel_) # 输出:1.5**2 * RBF(length_scale=0.858) ############################ # Part 3: GPy 实现 ############################ import GPy kern = GPy.kern.RBF( input_dim=1, variance=1., lengthscale=1.) kern.lengthscale.unconstrain() kern.variance.unconstrain() kern.lengthscale.constrain_bounded(1e-3, 10) kern.variance.constrain_bounded(1e-3, 10) m = GPy.core.GP( X=X,Y=t, kernel=kern, inference_method=GPy.inference.latent_function_inference.laplace.Laplace(), likelihood=GPy.likelihoods.Bernoulli()) m.optimize_restarts( num_restarts=10, optimizer='lbfgs', verbose=True, robust=True) print(m.kern) # 输出: # rbf. | value | constraints | priors # variance | 0.8067562453940487 | 0.001,10.0 | # lengthscale | 0.8365668826459536 | 0.001,10.0 |
差异表现
- 长度尺度值大致相近(0.858 vs 0.836),但方差差异显著:scikit-learn为
1.5²=2.25,GPy仅为0.806。 - GPy预测的潜在函数即使在±2标准差范围内也无法匹配真实潜在函数,而scikit-learn的预测表现较好。

左图:两者预测概率相近(因长度尺度相似);右图:GPy的潜在函数拟合效果远逊于scikit-learn。
已尝试无效果的操作
- 输入特征(X)归一化
- 改用Expectation Propagation(EP)替代Laplace作为推理方法
- 为scikit-learn实现添加WhiteKernel组件
解决方案
差异根源
- 核参数定义差异:scikit-learn的
ConstantKernel表示的是核的振幅(σ),最终输出的1.5是振幅,对应方差为1.5²=2.25;而GPy的RBF核variance参数直接表示方差(σ²)。 - 推理过程缩放差异:scikit-learn的高斯过程分类器在Laplace近似中,会对潜在函数进行隐式缩放以匹配伯努利似然的期望;GPy的Laplace推理对潜在函数的正则化逻辑与scikit-learn不同,导致优化后的方差被压缩。
修改GPy实现的步骤
调整核的初始化与约束范围:
放宽核方差的约束上限,并设置更贴近scikit-learn初始振幅对应的方差值:kern = GPy.kern.RBF( input_dim=1, variance=2.25, # 对应scikit-learn初始振幅1.5的方差 lengthscale=1.) # 放宽方差约束上限,给优化器更大空间 kern.variance.constrain_bounded(1e-3, 100) kern.lengthscale.constrain_bounded(1e-3, 10)手动缩放预测结果:
如果优化后仍存在尺度差异,可直接对GPy的潜在函数预测结果进行缩放,匹配scikit-learn的输出尺度:# 获取GPy的潜在函数预测(不含似然) mu_gpy, var_gpy = m.predict(X_test, full_cov=False, include_likelihood=False) # 基于两者优化后的方差比值计算缩放因子 scaling_factor = np.sqrt(2.25 / m.kern.variance.values[0]) # 缩放均值和方差 mu_scaled = mu_gpy * scaling_factor var_scaled = var_gpy * scaling_factor**2对齐推理方法细节:
确保GPy使用与scikit-learn一致的Laplace近似配置,显式设置推理参数:inference = GPy.inference.latent_function_inference.laplace.Laplace() m = GPy.core.GP( X=X, Y=t, kernel=kern, inference_method=inference, likelihood=GPy.likelihoods.Bernoulli(link='logit') # 显式指定logit链接,与scikit-learn一致 )
关键说明
调整后的GPy实现,其潜在函数预测结果将与scikit-learn对齐,同时保持预测概率的一致性——因为概率是通过sigmoid函数转换而来,尺度差异不会影响最终的概率输出(这也是左图概率相近的原因)。
内容的提问来源于stack exchange,提问作者olamarre
相关产品推荐
相关产品推荐

