注意
转到结尾 下载完整的示例代码。或通过 JupyterLite 或 Binder 在浏览器中运行此示例
高斯过程回归 (GPR) 估计数据噪声水平的能力#
此示例展示了WhiteKernel
估计数据噪声水平的能力。此外,我们还展示了核超参数初始化的重要性。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
数据生成#
我们将在一个X
包含单个特征的环境中工作。我们创建一个函数来生成要预测的目标值。我们将添加一个选项来向生成的目 标值添加一些噪声。
import numpy as np
def target_generator(X, add_noise=False):
target = 0.5 + np.sin(3 * X)
if add_noise:
rng = np.random.RandomState(1)
target += rng.normal(0, 0.3, size=target.shape)
return target.squeeze()
让我们来看一下目标生成器,在其中我们不会添加任何噪声来观察我们想要预测的信号。
X = np.linspace(0, 5, num=80).reshape(-1, 1)
y = target_generator(X, add_noise=False)
import matplotlib.pyplot as plt
plt.plot(X, y, label="Expected signal")
plt.legend()
plt.xlabel("X")
_ = plt.ylabel("y")
目标值使用正弦函数转换输入X
。现在,我们将生成一些带噪声的训练样本。为了说明噪声水平,我们将绘制真实的信号以及带噪声的训练样本。
rng = np.random.RandomState(0)
X_train = rng.uniform(0, 5, size=20).reshape(-1, 1)
y_train = target_generator(X_train, add_noise=True)
plt.plot(X, y, label="Expected signal")
plt.scatter(
x=X_train[:, 0],
y=y_train,
color="black",
alpha=0.4,
label="Observations",
)
plt.legend()
plt.xlabel("X")
_ = plt.ylabel("y")
GPR中核超参数的优化#
现在,我们将使用一个加性核创建一个GaussianProcessRegressor
,该核添加了RBF
和WhiteKernel
核。WhiteKernel
是一个能够估计数据中噪声量的核,而RBF
将用于拟合数据和目标之间的非线性关系。
但是,我们将展示超参数空间包含多个局部最小值。这将突出显示初始超参数值的重要性。
我们将使用一个具有高噪声水平和较大长度尺度的核创建一个模型,这将通过噪声解释数据中的所有变化。
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, WhiteKernel
kernel = 1.0 * RBF(length_scale=1e1, length_scale_bounds=(1e-2, 1e3)) + WhiteKernel(
noise_level=1, noise_level_bounds=(1e-10, 1e1)
)
gpr = GaussianProcessRegressor(kernel=kernel, alpha=0.0)
gpr.fit(X_train, y_train)
y_mean, y_std = gpr.predict(X, return_std=True)
/home/circleci/project/sklearn/gaussian_process/kernels.py:452: ConvergenceWarning:
The optimal value found for dimension 0 of parameter k1__k2__length_scale is close to the specified upper bound 1000.0. Increasing the bound and calling fit again may find a better value.
plt.plot(X, y, label="Expected signal")
plt.scatter(x=X_train[:, 0], y=y_train, color="black", alpha=0.4, label="Observations")
plt.errorbar(X, y_mean, y_std, label="Posterior mean ± std")
plt.legend()
plt.xlabel("X")
plt.ylabel("y")
_ = plt.title(
(
f"Initial: {kernel}\nOptimum: {gpr.kernel_}\nLog-Marginal-Likelihood: "
f"{gpr.log_marginal_likelihood(gpr.kernel_.theta)}"
),
fontsize=8,
)
我们看到,找到的最佳核仍然具有较高的噪声水平和更大的长度尺度。长度尺度达到了我们允许的该参数的最大边界,因此我们收到警告。
更重要的是,我们观察到该模型没有提供有用的预测:平均预测似乎是恒定的:它没有遵循预期的无噪声信号。
现在,我们将使用更大的length_scale
初始值初始化RBF
,并使用较小的初始噪声水平初始化WhiteKernel
,同时保持参数边界不变。
kernel = 1.0 * RBF(length_scale=1e-1, length_scale_bounds=(1e-2, 1e3)) + WhiteKernel(
noise_level=1e-2, noise_level_bounds=(1e-10, 1e1)
)
gpr = GaussianProcessRegressor(kernel=kernel, alpha=0.0)
gpr.fit(X_train, y_train)
y_mean, y_std = gpr.predict(X, return_std=True)
plt.plot(X, y, label="Expected signal")
plt.scatter(x=X_train[:, 0], y=y_train, color="black", alpha=0.4, label="Observations")
plt.errorbar(X, y_mean, y_std, label="Posterior mean ± std")
plt.legend()
plt.xlabel("X")
plt.ylabel("y")
_ = plt.title(
(
f"Initial: {kernel}\nOptimum: {gpr.kernel_}\nLog-Marginal-Likelihood: "
f"{gpr.log_marginal_likelihood(gpr.kernel_.theta)}"
),
fontsize=8,
)
首先,我们看到模型的预测比之前的模型更精确:这个新模型能够估计无噪声的函数关系。
查看核超参数,我们看到找到的最佳组合具有比第一个模型更小的噪声水平和更短的长度尺度。
我们可以检查GaussianProcessRegressor
不同超参数的负对数边际似然 (LML),以了解局部最小值。
from matplotlib.colors import LogNorm
length_scale = np.logspace(-2, 4, num=80)
noise_level = np.logspace(-2, 1, num=80)
length_scale_grid, noise_level_grid = np.meshgrid(length_scale, noise_level)
log_marginal_likelihood = [
gpr.log_marginal_likelihood(theta=np.log([0.36, scale, noise]))
for scale, noise in zip(length_scale_grid.ravel(), noise_level_grid.ravel())
]
log_marginal_likelihood = np.reshape(log_marginal_likelihood, noise_level_grid.shape)
vmin, vmax = (-log_marginal_likelihood).min(), 50
level = np.around(np.logspace(np.log10(vmin), np.log10(vmax), num=20), decimals=1)
plt.contour(
length_scale_grid,
noise_level_grid,
-log_marginal_likelihood,
levels=level,
norm=LogNorm(vmin=vmin, vmax=vmax),
)
plt.colorbar()
plt.xscale("log")
plt.yscale("log")
plt.xlabel("Length-scale")
plt.ylabel("Noise-level")
plt.title("Negative log-marginal-likelihood")
plt.show()
我们看到有两个局部最小值对应于先前找到的超参数组合。根据超参数的初始值,基于梯度的优化可能收敛到最佳模型,也可能不收敛。因此,重要的是要对不同的初始化重复优化多次。这可以通过设置GaussianProcessRegressor
类的n_restarts_optimizer
参数来完成。
让我们再次尝试使用错误的初始值拟合我们的模型,但这次进行10次随机重启。
kernel = 1.0 * RBF(length_scale=1e1, length_scale_bounds=(1e-2, 1e3)) + WhiteKernel(
noise_level=1, noise_level_bounds=(1e-10, 1e1)
)
gpr = GaussianProcessRegressor(
kernel=kernel, alpha=0.0, n_restarts_optimizer=10, random_state=0
)
gpr.fit(X_train, y_train)
y_mean, y_std = gpr.predict(X, return_std=True)
plt.plot(X, y, label="Expected signal")
plt.scatter(x=X_train[:, 0], y=y_train, color="black", alpha=0.4, label="Observations")
plt.errorbar(X, y_mean, y_std, label="Posterior mean ± std")
plt.legend()
plt.xlabel("X")
plt.ylabel("y")
_ = plt.title(
(
f"Initial: {kernel}\nOptimum: {gpr.kernel_}\nLog-Marginal-Likelihood: "
f"{gpr.log_marginal_likelihood(gpr.kernel_.theta)}"
),
fontsize=8,
)
正如我们所希望的,随机重启允许优化找到最佳超参数集,即使初始值很差。
脚本总运行时间:(0 分钟 6.192 秒)
相关示例