GaussianProcessRegressor预测结果不一致及平坦输出问题解决
我在用高斯过程(Gaussian Processes)预测并寻找目标函数最大值时,遇到GPR(GaussianProcessRegressor)预测结果有时全范围平坦恒定,重新运行又恢复正常的问题,还存在近乎平坦、仅拟合训练点的异常情况。尝试过数据缩放、设置length_scale但未解决。复现代码如下:
import matplotlib.pyplot as plt import numpy as np from sklearn.gaussian_process.kernels import Matern from sklearn.gaussian_process import GaussianProcessRegressor from sklearn.preprocessing import StandardScaler use_scalar = False scalerx = StandardScaler() scalery = StandardScaler() data_target = np.array([[ 4.11527487e+00, -5.25998354e-02], [ 9.87746489e-02, -4.13503230e-02], [ 3.57381547e+00, -5.25998354e-02], [ 1.60683672e+00, -5.25998354e-02], [ 5.26929603e+00, -6.18080378e-02], [ 9.08232311e-01, -5.25998354e-02], [ 2.39112060e-01, -3.52116406e-02], [ 4.29874823e+00, -4.23911691e-02], [ 9.88334539e-01, -5.25998354e-02], [ 3.10196661e+00, -5.25998354e-02], [ 7.87734943e-01, -5.25998354e-02], [ 8.27486483e-01, -5.16990900e-02], [ 3.80523113e+00, -5.25998354e-02], [ 7.03828442e-01, -2.22452462e-02], [ 5.83227361e+00, -3.09045196e-02], [ 4.65850859e+00, -2.24894464e-02], [ 5.35498380e+00, -4.55683947e-02], [ 5.15052521e+00, -2.59802818e-02], [ 3.43894560e+00, -5.25998354e-02], [ 3.40215825e+00, -5.25998354e-02], [ 0.00000000e+00, -4.35041189e-03], # <- manually added point [ 6.28318531e+00, -4.35041189e-03]]) # <- manually added point krnl = Matern(nu=2.5) gp = GaussianProcessRegressor(kernel=krnl, alpha=1e-6, normalize_y=True, n_restarts_optimizer=5, random_state=np.random.RandomState()) if(use_scalar): # gp.set_params(kernel__length_scale=0.) scalerx.fit(data_target[:,0:1]) scalery.fit(data_target[:,1:]) X = scalerx.transform(optimizer._space.params) Y = scalery.transform(optimizer._space.target) else: X = data_target[:,0:1] Y = data_target[:,1:] gp.fit(X, Y) # predict x_pnts = np.linspace(0, 6.28, 1000).reshape(-1,1) if(use_scalar): x = scalerx.transform(x_pnts) else: x = x_pnts mu, sigma = gp.predict(x, return_std=True) if(use_scalar): mu = scalery.inverse_transform(mu.reshape(-1,1)) plt.scatter(data_target[:,0], data_target[:,1], marker='*') plt.scatter(x_pnts, mu, marker='.') plt.show()
问题原因分析
1. 随机初始化导致结果不可复现
创建GaussianProcessRegressor时使用random_state=np.random.RandomState()但未指定固定种子,每次运行的随机状态不同。GPR的n_restarts_optimizer会多次随机初始化核参数,不同初始点可能让优化器收敛到不同局部最优,导致预测结果差异。
2. 核参数优化陷入局部最优
Matern核的length_scale、sigma_f等参数通过最大化边际似然优化,该问题存在多个局部最优解。当优化器收敛到较差的局部最优(比如length_scale极大,导致核函数输出近乎恒定)时,就会出现全范围平坦的预测结果。
3. 数据分布不平衡
训练数据中大部分点的Y值集中在-5.25998354e-02,仅少数点有差异,这种分布会让模型倾向于拟合多数值,容易生成平坦的预测曲线。
4. 数据缩放代码存在笔误
当use_scalar=True时,代码中使用了未定义的optimizer._space.params和optimizer._space.target,导致缩放基于错误数据,进而影响模型训练和预测。
修正方案
1. 固定随机种子,确保结果可复现
给random_state指定固定整数,让每次运行的随机初始化一致:
gp = GaussianProcessRegressor(kernel=krnl, alpha=1e-6, normalize_y=True, n_restarts_optimizer=5, random_state=42)
2. 增加优化重启次数,提升全局最优概率
调大n_restarts_optimizer的值,让优化器尝试更多初始点:
gp = GaussianProcessRegressor(kernel=krnl, alpha=1e-6, normalize_y=True, n_restarts_optimizer=20, random_state=42)
3. 手动设置核参数初始值
根据数据尺度设置合理的初始length_scale,避免优化器从极端值开始:
# X范围是0~6.28,设置初始length_scale为1.0(可根据实际调整) krnl = Matern(nu=2.5, length_scale=1.0)
4. 调整噪声项alpha
增大alpha或使用自动估计,避免模型对噪声过于敏感:
# 手动调大alpha gp = GaussianProcessRegressor(kernel=krnl, alpha=1e-4, normalize_y=True, n_restarts_optimizer=20, random_state=42) # 或自动估计噪声 gp = GaussianProcessRegressor(kernel=krnl, alpha='auto', normalize_y=True, n_restarts_optimizer=20, random_state=42)
5. 修正数据缩放代码
替换错误的optimizer._space相关变量,确保缩放基于训练数据:
if(use_scalar): scalerx.fit(data_target[:,0:1]) scalery.fit(data_target[:,1:]) X = scalerx.transform(data_target[:,0:1]) Y = scalery.transform(data_target[:,1:])
6. 补充训练数据
在Y值有差异的区域增加采样点,让模型学到更丰富的函数模式,减少平坦预测的概率。
内容的提问来源于stack exchange,提问作者GuyS

