Expand class description and some speed improvements

This commit is contained in:
Mark Pullin 2018-07-19 10:17:49 +01:00
parent 09c72eeec5
commit 1cd8606451

View file

@ -7,11 +7,25 @@ class Symmetric(Kern):
""" """
Symmetric kernel that models a function with even or odd symmetry: Symmetric kernel that models a function with even or odd symmetry:
For even symmetry we have:
.. math:: .. math::
f(x) = f(Ax) f(x) = f(Ax)
or we then model the function as:
.. math::
f(x) = g(x) + g(Ax)
the corresponding kernel is:
.. math::
k(x, x') + k(Ax, x') + k(x, Ax') + k(Ax, Ax')
For odd symmetry we have:
.. math:: .. math::
@ -21,13 +35,13 @@ class Symmetric(Kern):
.. math:: .. math::
f(x) = g(x) \pm g(Ax) f(x) = g(x) - g(Ax)
with kernel with kernel
.. math:: .. math::
k(x, x') \pm k(Ax, x') \pm k(x, Ax') + k(Ax, Ax') k(x, x') - k(Ax, x') - k(x, Ax') + k(Ax, Ax')
where k(x, x') is the kernel of g(x) where k(x, x') is the kernel of g(x)
@ -37,8 +51,8 @@ class Symmetric(Kern):
""" """
def __init__(self, base_kernel, transform, symmetry_type='even'): def __init__(self, base_kernel, transform, symmetry_type='even'):
n_dims = max(base_kernel.active_dims) + 1
super(Symmetric, self).__init__(1, [0], name='symmetric_kernel') super(Symmetric, self).__init__(n_dims, list(range(n_dims)), name='symmetric_kernel')
if symmetry_type is 'odd': if symmetry_type is 'odd':
self.symmetry_sign = -1. self.symmetry_sign = -1.
elif symmetry_type is 'even': elif symmetry_type is 'even':
@ -114,15 +128,30 @@ class Symmetric(Kern):
dL_dK_full = np.diag(dL_dK) dL_dK_full = np.diag(dL_dK)
X_sym = X.dot(self.transform) X_sym = X.dot(self.transform)
# Calculate gradient for k(Ax, Ax')
self.base_kernel.update_gradients_diag(dL_dK, X_sym) self.base_kernel.update_gradients_diag(dL_dK, X_sym)
gradient = self.base_kernel.gradient.copy() gradient = self.base_kernel.gradient.copy()
# Calculate gradient for k(x, x')
self.base_kernel.update_gradients_diag(dL_dK, X) self.base_kernel.update_gradients_diag(dL_dK, X)
gradient += self.base_kernel.gradient.copy() gradient += self.base_kernel.gradient.copy()
# The contribution from both cross terms is the same # Batch process cross term for speed
self.base_kernel.update_gradients_full(dL_dK_full, X, X_sym) batch_size = 100
gradient += 2 * self.symmetry_sign * self.base_kernel.gradient.copy() n_points = dL_dK.shape[0]
n_batches = int(np.ceil(n_points / float(batch_size)))
gradient_part = np.zeros(gradient.shape)
for i in range(n_batches):
i_start = i * batch_size
i_end = np.min([(i + 1) * batch_size, n_points])
dL_dK_part = dL_dK_full[i_start:i_end, i_start:i_end]
X_part = X[i_start:i_end, :]
X_sym_part = X_sym[i_start:i_end, :]
self.base_kernel.update_gradients_full(
dL_dK_part, X_part, X_sym_part)
gradient_part += self.base_kernel.gradient.copy()
gradient += 2 * self.symmetry_sign * gradient_part
self.base_kernel.gradient = gradient self.base_kernel.gradient = gradient