You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

高斯过程二分类:为何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组件

解决方案

差异根源

  1. 核参数定义差异:scikit-learn的ConstantKernel表示的是核的振幅(σ),最终输出的1.5是振幅,对应方差为1.5²=2.25;而GPy的RBF核variance参数直接表示方差(σ²)。
  2. 推理过程缩放差异:scikit-learn的高斯过程分类器在Laplace近似中,会对潜在函数进行隐式缩放以匹配伯努利似然的期望;GPy的Laplace推理对潜在函数的正则化逻辑与scikit-learn不同,导致优化后的方差被压缩。

修改GPy实现的步骤

  1. 调整核的初始化与约束范围:
    放宽核方差的约束上限,并设置更贴近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)
    
  2. 手动缩放预测结果:
    如果优化后仍存在尺度差异,可直接对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
    
  3. 对齐推理方法细节:
    确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:38:10