我正在考虑在一个相当特殊的环境中使用 GPR,我需要编写自己的内核。但是我发现没有关于如何执行此操作的文档。尝试简单地继承
Kernel
并实现方法 __call__
、get_params
、diag
和 is_stationary
足以让拟合过程正常工作,但当我尝试预测 y 值和标准时就会崩溃偏差。构建一个最小但功能齐全的类,该类继承自 Kernel
,同时使用自己的函数,需要哪些必要步骤?谢谢!
根据您的内核的异国情调,您问题的答案可能会有所不同。
我发现 RBF 内核的实现 非常自我记录,所以我用它作为参考。要点如下:
class RBF(StationaryKernelMixin, NormalizedKernelMixin, Kernel):
def __init__(self, length_scale=1.0, length_scale_bounds=(1e-5, 1e5)):
self.length_scale = length_scale
self.length_scale_bounds = length_scale_bounds
@property
def hyperparameter_length_scale(self):
if self.anisotropic:
return Hyperparameter("length_scale", "numeric",
self.length_scale_bounds,
len(self.length_scale))
return Hyperparameter(
"length_scale", "numeric", self.length_scale_bounds)
def __call__(self, X, Y=None, eval_gradient=False):
# ...
正如您所提到的,您的内核应该继承自Kernel,这需要您实现
__call__
,diag
和is_stationary
。请注意,sklearn.gaussian_process.kernels
提供了StationaryKernelMixin
和NormalizedKernelMixin
,它们为您实现了diag
和is_stationary
(参见代码中的RBF类定义)。
您不应该覆盖
get_params
!这是由 Kernel 类为您完成的,它期望 scikit-learn 内核遵循约定,您的内核也应该遵循约定:将构造函数签名中的参数指定为关键字参数(请参阅上一个示例中的length_scale
) RBF 核)。这确保了您的内核可以被复制,这是由 GaussianProcessRegressor.fit(...)
完成的(这可能是您无法预测标准偏差的原因)。
此时,您可能会注意到另一个参数
length_scale_bounds
。这只是对实际超参数 length_scale
的约束(参见约束优化)。这让我们认识到一个事实,即您还需要声明您想要优化的超级参数,并且需要在您的__call__
实现中计算梯度。您可以通过定义一个以 hyperparameter_
为前缀的类属性来实现这一点(参见代码中的 hyperparameter_length_scale
)。每个不固定的超参数(固定 = hyperparameter.fixed == True
)由 Kernel.theta
返回,GP 在 fit()
上使用它并计算边际对数似然。因此,如果您想使参数适合您的数据,这是必不可少的。
关于
Kernel.theta
的最后一个细节,实施状态:
返回(展平、对数转换)非固定超参数。
因此,您应该小心超参数中的 0 值,因为它们最终可能会成为 np.nan 并破坏内容。
我希望这会有所帮助,尽管这个问题已经有点老了。实际上,我自己从未实现过内核,但很想浏览一下 sklearn 代码库。不幸的是,没有这方面的官方教程,但是代码库非常干净并带有注释。