diff --git a/GPy/kern/kern.py b/GPy/kern/kern.py index e9fa0caa..6a72ac8d 100644 --- a/GPy/kern/kern.py +++ b/GPy/kern/kern.py @@ -692,7 +692,7 @@ def kern_test(kern, X=None, X2=None, verbose=False): Kern_check_dK_dtheta(kern, X=X, X2=None).checkgrad(verbose=True) pass_checks = False return False - + if verbose: print("Checking gradients of K(X, X2) wrt theta.") result = Kern_check_dK_dtheta(kern, X=X, X2=X2).checkgrad(verbose=verbose) @@ -703,7 +703,7 @@ def kern_test(kern, X=None, X2=None, verbose=False): Kern_check_dK_dtheta(kern, X=X, X2=X2).checkgrad(verbose=True) pass_checks = False return False - + if verbose: print("Checking gradients of Kdiag(X) wrt theta.") result = Kern_check_dKdiag_dtheta(kern, X=X).checkgrad(verbose=verbose) @@ -714,10 +714,15 @@ def kern_test(kern, X=None, X2=None, verbose=False): Kern_check_dKdiag_dtheta(kern, X=X).checkgrad(verbose=True) pass_checks = False return False - + if verbose: print("Checking gradients of K(X, X) wrt X.") - result = Kern_check_dK_dX(kern, X=X, X2=None).checkgrad(verbose=verbose) + try: + result = Kern_check_dK_dX(kern, X=X, X2=None).checkgrad(verbose=verbose) + except NotImplementedError: + result=True + if verbose: + print("dK_dX not implemented for " + kern.name) if result and verbose: print("Check passed.") if not result: @@ -728,7 +733,12 @@ def kern_test(kern, X=None, X2=None, verbose=False): if verbose: print("Checking gradients of K(X, X2) wrt X.") - result = Kern_check_dK_dX(kern, X=X, X2=X2).checkgrad(verbose=verbose) + try: + result = Kern_check_dK_dX(kern, X=X, X2=X2).checkgrad(verbose=verbose) + except NotImplementedError: + result=True + if verbose: + print("dK_dX not implemented for " + kern.name) if result and verbose: print("Check passed.") if not result: @@ -739,7 +749,12 @@ def kern_test(kern, X=None, X2=None, verbose=False): if verbose: print("Checking gradients of Kdiag(X) wrt X.") - result = Kern_check_dKdiag_dX(kern, X=X).checkgrad(verbose=verbose) + try: + result = Kern_check_dKdiag_dX(kern, X=X).checkgrad(verbose=verbose) + except NotImplementedError: + result=True + if verbose: + print("dK_dX not implemented for " + kern.name) if result and verbose: print("Check passed.") if not result: @@ -747,5 +762,5 @@ def kern_test(kern, X=None, X2=None, verbose=False): Kern_check_dKdiag_dX(kern, X=X).checkgrad(verbose=True) pass_checks = False return False - + return pass_checks diff --git a/GPy/kern/parts/hetero.py b/GPy/kern/parts/hetero.py index 2ee1a549..d3939563 100644 --- a/GPy/kern/parts/hetero.py +++ b/GPy/kern/parts/hetero.py @@ -10,9 +10,12 @@ import GPy class Hetero(Kernpart): """ - TODO: Need to constrain the function outputs positive (still thinking of best way of doing this!!! Yes, intend to use transformations, but what's the *best* way). Currently just squaring output. + TODO: Need to constrain the function outputs + positive (still thinking of best way of doing this!!! Yes, intend to use + transformations, but what's the *best* way). Currently just squaring output. - Heteroschedastic noise which depends on input location. See, for example, this paper by Goldberg et al. + Heteroschedastic noise which depends on input location. See, for example, + this paper by Goldberg et al. .. math:: @@ -20,15 +23,15 @@ class Hetero(Kernpart): where :math:`\sigma^2(x)` is a function giving the variance as a function of input space and :math:`\delta_{i,j}` is the Kronecker delta function. - The parameters are the parameters of \sigma^2(x) which is a - function that can be specified by the user, by default an - multi-layer peceptron is used. + The parameters are the parameters of \sigma^2(x) which is a + function that can be specified by the user, by default an + multi-layer peceptron is used. - :param input_dim: the number of input dimensions - :type input_dim: int - :param mapping: the mapping that gives the lengthscale across the input space (by default GPy.mappings.MLP is used with 20 hidden nodes). - :type mapping: GPy.core.Mapping - :rtype: Kernpart object + :param input_dim: the number of input dimensions + :type input_dim: int + :param mapping: the mapping that gives the lengthscale across the input space (by default GPy.mappings.MLP is used with 20 hidden nodes). + :type mapping: GPy.core.Mapping + :rtype: Kernpart object See this paper: @@ -36,7 +39,7 @@ class Hetero(Kernpart): C. M. (1998) Regression with Input-dependent Noise: a Gaussian Process Treatment In Advances in Neural Information Processing Systems, Volume 10, pp. 493-499. MIT Press - + for a Gaussian process treatment of this problem. """ @@ -47,7 +50,7 @@ class Hetero(Kernpart): mapping = GPy.mappings.MLP(output_dim=1, hidden_dim=20, input_dim=input_dim) if not transform: transform = GPy.core.transformations.logexp() - + self.transform = transform self.mapping = mapping self.name='hetero' @@ -66,7 +69,7 @@ class Hetero(Kernpart): def K(self, X, X2, target): """Return covariance between X and X2.""" - if X2==None or X2 is X: + if (X2 is None) or (X2 is X): target[np.diag_indices_from(target)] += self._Kdiag(X) def Kdiag(self, X, target): @@ -76,26 +79,26 @@ class Hetero(Kernpart): def _Kdiag(self, X): """Helper function for computing the diagonal elements of the covariance.""" return self.mapping.f(X).flatten()**2 - + def dK_dtheta(self, dL_dK, X, X2, target): """Derivative of the covariance with respect to the parameters.""" - if X2==None or X2 is X: + if (X2 is None) or (X2 is X): dL_dKdiag = dL_dK.flat[::dL_dK.shape[0]+1] self.dKdiag_dtheta(dL_dKdiag, X, target) def dKdiag_dtheta(self, dL_dKdiag, X, target): """Gradient of diagonal of covariance with respect to parameters.""" - target += 2.*self.mapping.df_dtheta(dL_dKdiag[:, None], X)*self.mapping.f(X) + target += 2.*self.mapping.df_dtheta(dL_dKdiag[:, None]*self.mapping.f(X), X) def dK_dX(self, dL_dK, X, X2, target): """Derivative of the covariance matrix with respect to X.""" if X2==None or X2 is X: dL_dKdiag = dL_dK.flat[::dL_dK.shape[0]+1] self.dKdiag_dX(dL_dKdiag, X, target) - + def dKdiag_dX(self, dL_dKdiag, X, target): """Gradient of diagonal of covariance with respect to X.""" target += 2.*self.mapping.df_dX(dL_dKdiag[:, None], X)*self.mapping.f(X) - + diff --git a/GPy/kern/parts/kernpart.py b/GPy/kern/parts/kernpart.py index f4b6783e..475d835f 100644 --- a/GPy/kern/parts/kernpart.py +++ b/GPy/kern/parts/kernpart.py @@ -58,6 +58,8 @@ class Kernpart(object): raise NotImplementedError def dK_dX(self, dL_dK, X, X2, target): raise NotImplementedError + def dKdiag_dX(self, dL_dK, X, target): + raise NotImplementedError @@ -97,6 +99,9 @@ class Kernpart_stationary(Kernpart): # wrt lengthscale is 0. target[0] += np.sum(dL_dKdiag) + def dKdiag_dX(self, dL_dK, X, target): + pass # true for all stationary kernels + class Kernpart_inner(Kernpart): def __init__(self,input_dim):