使用 GPflow 2.0,我想用 Haversine 而不是欧几里得距离实现自定义的 Matern 5/2 内核。我在该类之上创建了一个自定义类gpflow.kernels.Matern52
,其中包含一个scaled_squared_dist
覆盖scaled_squared_euclid_dist
从该类继承的函数。 Stationary
当前编写的类不会改变 Matern52 类;使用此HaversineKernel_Matern52
内核的 GP 回归与使用 Matern52 内核的 GP 回归完全一样。
import gpflow
from gpflow.utilities.ops import square_distance
class HaversineKernel_Matern52(gpflow.kernels.Matern52):
"""
Isotropic Matern52 Kernel with Haversine distance instead of euclidean distance.
Assumes 2-dimensional inputs, with columns [latitude, longitude] in degrees.
"""
def __init__(self, lengthscale=1.0, variance=1.0, active_dims=None, ard=None):
super().__init__(active_dims=active_dims, variance=variance,
lengthscale=lengthscale, ard=ard)
def haversine_dist(self, X, X2):
pi = np.pi / 180
f = tf.expand_dims(X * pi, -2) # ... x N x 1 x D
f2 = tf.expand_dims(X2 * pi, -3) # ... x 1 x M x D
d = tf.sin((f - f2) / 2) ** 2
lat1, lat2 = tf.expand_dims(X[:, 0] * pi, -1), \
tf.expand_dims(X2[:, 0] * pi, -2)
cos_prod = tf.cos(lat2) * tf.cos(lat1)
a = d[:,:,0] + cos_prod * d[:,:,1]
c = tf.asin(tf.sqrt(a)) * 6371 * 2
return c
def scaled_squared_dist(self, X, X2=None):
"""
Returns ||(X - X2ᵀ) / ℓ||² i.e. squared L2-norm.
"""
X_scaled = X / self.lengthscale
X2_scaled = X2 / self.lengthscale if X2 is not None else X2
return square_distance(X_scaled, X2_scaled)
我需要改变什么才能使这个内核正确地重新计算 Haversine 距离?
这个问题建立在GPflow 问题 #969之上。
谢谢!