https://github.com/GPflow/GPflow
Tip revision: 2fa87edc7d9b2b6c6201a4900a1a7da6f089c604 authored by Vincent Adam on 23 June 2020, 19:55:46 UTC
seeger demo
seeger demo
Tip revision: 2fa87ed
periodic.py
from typing import List, Optional, Union
import numpy as np
import tensorflow as tf
from ..base import Parameter
from ..utilities import positive
from ..utilities.ops import difference_matrix
from .base import Kernel
from .stationaries import Stationary, IsotropicStationary
class Periodic(Kernel):
"""
The periodic family of kernels. Can be used to wrap any Stationary kernel
to transform it into a periodic version. The canonical form (based on the
SquaredExponential kernel) can be found in Equation (47) of
D.J.C.MacKay. Introduction to Gaussian processes. In C.M.Bishop, editor,
Neural Networks and Machine Learning, pages 133--165. Springer, 1998.
The derivation can be achieved by mapping the original inputs through the
transformation u = (cos(x), sin(x)).
For the SquaredExponential base kernel, the result can be expressed as:
k(r) = σ² exp{ -0.5 sin²(π r / γ) / ℓ²}
where:
r is the Euclidean distance between the input points
ℓ is the lengthscales parameter,
σ² is the variance parameter,
γ is the period parameter.
NOTE: usually we have a factor of 4 instead of 0.5 in front but this
is absorbed into the lengthscales hyperparameter.
NOTE: periodic kernel uses `active_dims` of a base kernel, therefore
the constructor doesn't have it as an argument.
"""
def __init__(self, base_kernel: IsotropicStationary, period: Union[float, List[float]] = 1.0):
"""
:param base_kernel: the base kernel to make periodic; must inherit from Stationary
Note that `active_dims` should be specified in the base kernel.
:param period: the period; to induce a different period per active dimension
this must be initialized with an array the same length as the number
of active dimensions e.g. [1., 1., 1.]
"""
if not isinstance(base_kernel, IsotropicStationary):
raise TypeError("Periodic requires an IsotropicStationary kernel as the `base_kernel`")
super().__init__()
self.base_kernel = base_kernel
self.period = Parameter(period, transform=positive())
self.base_kernel._validate_ard_active_dims(self.period)
@property
def active_dims(self):
return self.base_kernel.active_dims
@active_dims.setter
def active_dims(self, value):
self.base_kernel.active_dims = value
def K_diag(self, X: tf.Tensor) -> tf.Tensor:
return self.base_kernel.K_diag(X)
def K(self, X: tf.Tensor, X2: Optional[tf.Tensor] = None) -> tf.Tensor:
r = np.pi * (difference_matrix(X, X2)) / self.period
scaled_sine = tf.sin(r) / self.base_kernel.lengthscales
if hasattr(self.base_kernel, "K_r"):
sine_r = tf.reduce_sum(tf.abs(scaled_sine), -1)
K = self.base_kernel.K_r(sine_r)
else:
sine_r2 = tf.reduce_sum(tf.square(scaled_sine), -1)
K = self.base_kernel.K_r2(sine_r2)
return K