我正在研究使用GPR作为一个相当特殊的上下文,我需要编写自己的内核。但是我发现没有关于如何做到这一点的文档。尝试简单地从Kernel
继承并实施方法__call__
,get_params
,diag
和is_stationary
足以使拟合过程起作用,但随后会中断当我试图预测y值和标准差时。构建一个在使用自己的函数时继承自Kernel
的最小但功能类的必要步骤是什么?谢谢!
答案 0 :(得分:5)
根据您内核的异国情调,您问题的答案可能有所不同。
我发现implementation of the RBF kernel完全是自我记录的,因此我将其用作参考。要点如下:
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内核遵循一个约定,您的内核也应遵循一个约定:在构造函数的签名中将参数指定为关键字参数(请参见{{ 1}}。这样可以确保您的内核可以通过length_scale
复制(这可能是您无法预测标准偏差的原因)。
这时,您可能会注意到另一个参数GaussianProcessRegressor.fit(...)
。这仅是对实际超参数length_scale_bounds
的约束(请参阅约束优化)。这带给我们一个事实,即您还需要声明hyper parameters,要进行优化并且需要在length_scale
实现中计算梯度。为此,您可以定义类的属性,该属性以__call__
为前缀(参见代码中的hyperparameter_
)。 hyperparameter_length_scale
返回每个不固定(固定= hyperparameter.fixed == True
)的超级参数,GP在Kernel.theta
上使用它来计算边际对数似然。因此,如果要使参数适合数据,这是 essential 。
关于fit()
的最后一个细节,该实现指出:
返回(展平,对数转换的)非固定超参数。
因此,您应该在超级参数中使用0值,因为它们最终可能会变成np.nan并破坏东西。
我希望这会有所帮助,即使这个问题已经有点老了。我实际上从未亲自实现过内核,但渴望浏览sklearn代码库。不幸的是,没有关于它的官方教程,但是代码库却很干净而且带有注释。