mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-05-14 06:22:38 +02:00
Merge pull request #174 from beckdaniel/kernel_prod_bugfix
Kernel product bugfix
This commit is contained in:
commit
9f51137469
2 changed files with 50 additions and 4 deletions
|
|
@ -6,6 +6,20 @@ from kern import CombinationKernel
|
||||||
from ...util.caching import Cache_this
|
from ...util.caching import Cache_this
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
|
def numpy_invalid_op_as_exception(func):
|
||||||
|
"""
|
||||||
|
A decorator that allows catching numpy invalid operations
|
||||||
|
as exceptions (the default behaviour is raising warnings).
|
||||||
|
"""
|
||||||
|
def func_wrapper(*args, **kwargs):
|
||||||
|
np.seterr(invalid='raise')
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
np.seterr(invalid='warn')
|
||||||
|
return result
|
||||||
|
return func_wrapper
|
||||||
|
|
||||||
|
|
||||||
class Prod(CombinationKernel):
|
class Prod(CombinationKernel):
|
||||||
"""
|
"""
|
||||||
Computes the product of 2 kernels
|
Computes the product of 2 kernels
|
||||||
|
|
@ -41,21 +55,35 @@ class Prod(CombinationKernel):
|
||||||
which_parts = self.parts
|
which_parts = self.parts
|
||||||
return reduce(np.multiply, (p.Kdiag(X) for p in which_parts))
|
return reduce(np.multiply, (p.Kdiag(X) for p in which_parts))
|
||||||
|
|
||||||
|
@numpy_invalid_op_as_exception
|
||||||
def update_gradients_full(self, dL_dK, X, X2=None):
|
def update_gradients_full(self, dL_dK, X, X2=None):
|
||||||
k = self.K(X,X2)*dL_dK
|
k = self.K(X,X2)*dL_dK
|
||||||
for p in self.parts:
|
try:
|
||||||
p.update_gradients_full(k/p.K(X,X2),X,X2)
|
for p in self.parts:
|
||||||
|
p.update_gradients_full(k/p.K(X,X2),X,X2)
|
||||||
|
except FloatingPointError:
|
||||||
|
for combination in itertools.combinations(self.parts, len(self.parts) - 1):
|
||||||
|
prod = reduce(np.multiply, [p.K(X, X2) for p in combination])
|
||||||
|
to_update = list(set(self.parts) - set(combination))[0]
|
||||||
|
to_update.update_gradients_full(dL_dK * prod, X, X2)
|
||||||
|
|
||||||
def update_gradients_diag(self, dL_dKdiag, X):
|
def update_gradients_diag(self, dL_dKdiag, X):
|
||||||
k = self.Kdiag(X)*dL_dKdiag
|
k = self.Kdiag(X)*dL_dKdiag
|
||||||
for p in self.parts:
|
for p in self.parts:
|
||||||
p.update_gradients_diag(k/p.Kdiag(X),X)
|
p.update_gradients_diag(k/p.Kdiag(X),X)
|
||||||
|
|
||||||
|
@numpy_invalid_op_as_exception
|
||||||
def gradients_X(self, dL_dK, X, X2=None):
|
def gradients_X(self, dL_dK, X, X2=None):
|
||||||
target = np.zeros(X.shape)
|
target = np.zeros(X.shape)
|
||||||
k = self.K(X,X2)*dL_dK
|
k = self.K(X,X2)*dL_dK
|
||||||
for p in self.parts:
|
try:
|
||||||
target += p.gradients_X(k/p.K(X,X2),X,X2)
|
for p in self.parts:
|
||||||
|
target += p.gradients_X(k/p.K(X,X2),X,X2)
|
||||||
|
except FloatingPointError:
|
||||||
|
for combination in itertools.combinations(self.parts, len(self.parts) - 1):
|
||||||
|
prod = reduce(np.multiply, [p.K(X, X2) for p in combination])
|
||||||
|
to_update = list(set(self.parts) - set(combination))[0]
|
||||||
|
target += to_update.gradients_X(dL_dK * prod, X, X2)
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def gradients_X_diag(self, dL_dKdiag, X):
|
def gradients_X_diag(self, dL_dKdiag, X):
|
||||||
|
|
@ -64,3 +92,5 @@ class Prod(CombinationKernel):
|
||||||
for p in self.parts:
|
for p in self.parts:
|
||||||
target += p.gradients_X_diag(k/p.Kdiag(X),X)
|
target += p.gradients_X_diag(k/p.Kdiag(X),X)
|
||||||
return target
|
return target
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -401,11 +401,27 @@ class Coregionalize_weave_test(unittest.TestCase):
|
||||||
GPy.util.config.config.set('weave', 'working', 'False')
|
GPy.util.config.config.set('weave', 'working', 'False')
|
||||||
|
|
||||||
|
|
||||||
|
class KernelTestsProductWithZeroValues(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.X = np.array([[0,1],[1,0]])
|
||||||
|
self.k = GPy.kern.Linear(2) * GPy.kern.Bias(2)
|
||||||
|
|
||||||
|
def test_zero_valued_kernel_full(self):
|
||||||
|
self.k.update_gradients_full(1, self.X)
|
||||||
|
self.assertFalse(np.isnan(self.k['linear.variances'].gradient),
|
||||||
|
"Gradient resulted in NaN")
|
||||||
|
|
||||||
|
def test_zero_valued_kernel_gradients_X(self):
|
||||||
|
target = self.k.gradients_X(1, self.X)
|
||||||
|
self.assertFalse(np.any(np.isnan(target)),
|
||||||
|
"Gradient resulted in NaN")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print "Running unit tests, please be (very) patient..."
|
print "Running unit tests, please be (very) patient..."
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
||||||
# np.random.seed(0)
|
# np.random.seed(0)
|
||||||
# N0 = 3
|
# N0 = 3
|
||||||
# N1 = 9
|
# N1 = 9
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue