diff --git a/GPy/core/parameterised.py b/GPy/core/parameterised.py index 007f1b25..b5d880a3 100644 --- a/GPy/core/parameterised.py +++ b/GPy/core/parameterised.py @@ -56,7 +56,7 @@ class parameterised(object): return copy.deepcopy(self) - def tie_param(self, which): + def tie_params(self, which): matches = self.grep_param_names(which) assert matches.size > 0, "need at least something to tie together" if len(self.tied_indices): diff --git a/GPy/examples/classification.py b/GPy/examples/classification.py index 00842e3b..c6b7f0ac 100644 --- a/GPy/examples/classification.py +++ b/GPy/examples/classification.py @@ -62,7 +62,7 @@ def oil(): # Contrain all parameters to be positive m.constrain_positive('') - m.tie_param('lengthscale') + m.tie_params('lengthscale') m.update_likelihood_approximation() # Optimize diff --git a/GPy/examples/tutorials.py b/GPy/examples/tutorials.py index 9d892b8e..2bc9ba60 100644 --- a/GPy/examples/tutorials.py +++ b/GPy/examples/tutorials.py @@ -138,7 +138,7 @@ def tuto_kernel_overview(): k.constrain_positive('var') k.constrain_fixed(np.array([1]),1.75) - k.tie_param('len') + k.tie_params('len') k.unconstrain('white') k.constrain_bounded('white',lower=1e-5,upper=.5) print k diff --git a/GPy/kern/__init__.py b/GPy/kern/__init__.py index 132fad41..6852384c 100644 --- a/GPy/kern/__init__.py +++ b/GPy/kern/__init__.py @@ -2,5 +2,5 @@ # Licensed under the BSD 3-clause license (see LICENSE.txt) -from constructors import rbf, Matern32, Matern52, exponential, linear, white, bias, finite_dimensional, spline, Brownian, rbf_sympy, sympykern, periodic_exponential, periodic_Matern32, periodic_Matern52, prod, prod_orthogonal, symmetric, coregionalise +from constructors import rbf, Matern32, Matern52, exponential, linear, white, bias, finite_dimensional, spline, Brownian, rbf_sympy, sympykern, periodic_exponential, periodic_Matern32, periodic_Matern52, prod, prod_orthogonal, symmetric, coregionalise, rational_quadratic from kern import kern diff --git a/GPy/kern/constructors.py b/GPy/kern/constructors.py index b848821b..983674b0 100644 --- a/GPy/kern/constructors.py +++ b/GPy/kern/constructors.py @@ -22,6 +22,7 @@ from prod import prod as prodpart from prod_orthogonal import prod_orthogonal as prod_orthogonalpart from symmetric import symmetric as symmetric_part from coregionalise import coregionalise as coregionalise_part +from rational_quadratic import rational_quadratic as rational_quadraticpart #TODO these s=constructors are not as clean as we'd like. Tidy the code up #using meta-classes to make the objects construct properly wthout them. @@ -280,3 +281,18 @@ def coregionalise(Nout,R=1, W=None, kappa=None): return kern(1,[p]) +def rational_quadratic(D,variance=1., lengthscale=1., power=1.): + """ + Construct rational quadratic kernel. + + :param D: the number of input dimensions + :type D: int (D=1 is the only value currently supported) + :param variance: the variance :math:`\sigma^2` + :type variance: float + :param lengthscale: the lengthscale :math:`\ell` + :type lengthscale: float + :rtype: kern object + + """ + part = rational_quadraticpart(D,variance, lengthscale, power) + return kern(D, [part]) diff --git a/GPy/kern/kern.py b/GPy/kern/kern.py index b2970674..be45fa70 100644 --- a/GPy/kern/kern.py +++ b/GPy/kern/kern.py @@ -237,7 +237,7 @@ class kern(parameterised): for i in range(K1.Nparam + K2.Nparam): index = np.where(index_param==i)[0] if index.size > 1: - self.tie_param(index) + self.tie_params(index) for i in prev_constr_pos: self.constrain_positive(np.where(index_param==i)[0]) for i in prev_constr_neg: @@ -391,9 +391,13 @@ class kern(parameterised): target += p2.variance*(p1._psi1[:,:,None]+p1._psi1[:,None,:]) #linear X bias elif p1.name=='bias' and p2.name=='linear': - raise NotImplementedError + tmp = np.zeros((mu.shape[0],Z.shape[0])) + p2.psi1(Z,mu,S,tmp) + target += p1.variance*(tmp[:,:,None] + tmp[:,None,:]) elif p2.name=='bias' and p1.name=='linear': - raise NotImplementedError + tmp = np.zeros((mu.shape[0],Z.shape[0])) + p1.psi1(Z,mu,S,tmp) + target += p2.variance*(tmp[:,:,None] + tmp[:,None,:]) #rbf X linear elif p1.name=='linear' and p2.name=='rbf': raise NotImplementedError #TODO @@ -426,6 +430,11 @@ class kern(parameterised): elif p2.name=='bias' and p1.name=='rbf': p1.dpsi1_dtheta(dL_dpsi2.sum(1)*p2.variance*2.,Z,mu,S,target[ps1]) p2.dpsi1_dtheta(dL_dpsi2.sum(1)*p1._psi1*2.,Z,mu,S,target[ps2]) + #linear X bias + elif p1.name=='bias' and p2.name=='linear': + p2.dpsi1_dtheta(dL_dpsi2.sum(1)*p1.variance*2., Z, mu, S, target[ps1]) + elif p2.name=='bias' and p1.name=='linear': + p1.dpsi1_dtheta(dL_dpsi2.sum(1)*p2.variance*2., Z, mu, S, target[ps1]) #rbf X linear elif p1.name=='linear' and p2.name=='rbf': raise NotImplementedError #TODO @@ -451,6 +460,11 @@ class kern(parameterised): p2.dpsi1_dX(dL_dpsi2.sum(1).T*p1.variance,Z,mu,S,target) elif p2.name=='bias' and p1.name=='rbf': p1.dpsi1_dZ(dL_dpsi2.sum(1).T*p2.variance,Z,mu,S,target) + #linear X bias + elif p1.name=='bias' and p2.name=='linear': + p2.dpsi1_dZ(dL_dpsi2.sum(1).T*p1.variance, Z, mu, S, target) + elif p2.name=='bias' and p1.name=='linear': + p1.dpsi1_dZ(dL_dpsi2.sum(1).T*p2.variance, Z, mu, S, target) #rbf X linear elif p1.name=='linear' and p2.name=='rbf': raise NotImplementedError #TODO @@ -478,6 +492,11 @@ class kern(parameterised): p2.dpsi1_dmuS(dL_dpsi2.sum(1).T*p1.variance*2.,Z,mu,S,target_mu,target_S) elif p2.name=='bias' and p1.name=='rbf': p1.dpsi1_dmuS(dL_dpsi2.sum(1).T*p2.variance*2.,Z,mu,S,target_mu,target_S) + #linear X bias + elif p1.name=='bias' and p2.name=='linear': + p2.dpsi1_dmuS(dL_dpsi2.sum(1).T*p1.variance*2., Z, mu, S, target_mu, target_S) + elif p2.name=='bias' and p1.name=='linear': + p1.dpsi1_dmuS(dL_dpsi2.sum(1).T*p2.variance*2., Z, mu, S, target_mu, target_S) #rbf X linear elif p1.name=='linear' and p2.name=='rbf': raise NotImplementedError #TODO diff --git a/GPy/kern/rational_quadratic.py b/GPy/kern/rational_quadratic.py new file mode 100644 index 00000000..b71d1354 --- /dev/null +++ b/GPy/kern/rational_quadratic.py @@ -0,0 +1,79 @@ +# Copyright (c) 2012, GPy authors (see AUTHORS.txt). +# Licensed under the BSD 3-clause license (see LICENSE.txt) + + +from kernpart import kernpart +import numpy as np + +class rational_quadratic(kernpart): + """ + rational quadratic kernel + + .. math:: + + k(r) = \sigma^2 \left(1 + \frac{r^2}{2 \ell^2})^{- \alpha} \ \ \ \ \ \\text{ where } r^2 = (x-y)^2 + + :param D: the number of input dimensions + :type D: int (D=1 is the only value currently supported) + :param variance: the variance :math:`\sigma^2` + :type variance: float + :param lengthscale: the lengthscale :math:`\ell` + :type lengthscale: float + :rtype: kernpart object + + """ + def __init__(self,D,variance=1.,lengthscale=1.,power=1.): + assert D == 1, "For this kernel we assume D=1" + self.D = D + self.Nparam = 3 + self.name = 'rat_quad' + self.variance = variance + self.lengthscale = lengthscale + self.power = power + + def _get_params(self): + return np.hstack((self.variance,self.lengthscale,self.power)) + + def _set_params(self,x): + self.variance = x[0] + self.lengthscale = x[1] + self.power = x[2] + + def _get_param_names(self): + return ['variance','lengthscale','power'] + + def K(self,X,X2,target): + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + target += self.variance*(1 + dist2/2.)**(-self.power) + + def Kdiag(self,X,target): + target += self.variance + + def dK_dtheta(self,dL_dK,X,X2,target): + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + + dvar = (1 + dist2/2.)**(-self.power) + dl = self.power * self.variance * dist2 * self.lengthscale**(-3) * (1 + dist2/2./self.power)**(-self.power-1) + dp = - self.variance * np.log(1 + dist2/2.) * (1 + dist2/2.)**(-self.power) + + target[0] += np.sum(dvar*dL_dK) + target[1] += np.sum(dl*dL_dK) + target[2] += np.sum(dp*dL_dK) + + def dKdiag_dtheta(self,dL_dKdiag,X,target): + target[0] += np.sum(dL_dKdiag) + # here self.lengthscale and self.power have no influence on Kdiag so target[1:] are unchanged + + def dK_dX(self,dL_dK,X,X2,target): + """derivative of the covariance matrix with respect to X.""" + if X2 is None: X2 = X + dist2 = np.square((X-X2.T)/self.lengthscale) + + dX = -self.variance*self.power * (X-X2.T)/self.lengthscale**2 * (1 + dist2/2./self.power)**(-self.power-1) + target += np.sum(dL_dK*dX) + + def dKdiag_dX(self,dL_dKdiag,X,target): + pass + diff --git a/GPy/kern/rbf.py b/GPy/kern/rbf.py index 3c3d59e6..133895ff 100644 --- a/GPy/kern/rbf.py +++ b/GPy/kern/rbf.py @@ -55,6 +55,7 @@ class rbf(kernpart): self._X, self._X2, self._params = np.empty(shape=(3,1)) def _get_params(self): + foo return np.hstack((self.variance,self.lengthscale)) def _set_params(self,x): diff --git a/GPy/models/BGPLVM.py b/GPy/models/Bayesian_GPLVM.py similarity index 100% rename from GPy/models/BGPLVM.py rename to GPy/models/Bayesian_GPLVM.py diff --git a/GPy/models/__init__.py b/GPy/models/__init__.py index c099d0d5..22aa803c 100644 --- a/GPy/models/__init__.py +++ b/GPy/models/__init__.py @@ -10,4 +10,4 @@ from GPLVM import GPLVM from warped_GP import warpedGP from sparse_GPLVM import sparse_GPLVM from uncollapsed_sparse_GP import uncollapsed_sparse_GP -from BGPLVM import Bayesian_GPLVM +from Bayesian_GPLVM import Bayesian_GPLVM diff --git a/GPy/testing/bgplvm_tests.py b/GPy/testing/bgplvm_tests.py index dda92b90..b182c1a8 100644 --- a/GPy/testing/bgplvm_tests.py +++ b/GPy/testing/bgplvm_tests.py @@ -58,7 +58,7 @@ class BGPLVMTests(unittest.TestCase): m.randomize() self.assertTrue(m.checkgrad()) - @unittest.skip('psi2 cross terms are NotImplemented for this combination') + #@unittest.skip('psi2 cross terms are NotImplemented for this combination') def test_linear_bias_kern(self): N, M, Q, D = 10, 3, 2, 4 X = np.random.rand(N, Q) diff --git a/GPy/testing/kernel_tests.py b/GPy/testing/kernel_tests.py index bb809ea6..f1762db8 100644 --- a/GPy/testing/kernel_tests.py +++ b/GPy/testing/kernel_tests.py @@ -8,7 +8,7 @@ import GPy class KernelTests(unittest.TestCase): def test_kerneltie(self): K = GPy.kern.rbf(5, ARD=True) - K.tie_param('[01]') + K.tie_params('[01]') K.constrain_fixed('2') X = np.random.rand(5,5) Y = np.ones((5,1))