mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-05-08 03:22:38 +02:00
Added testing of variational expectations, analytic vs numeric, and gradient checks
This commit is contained in:
parent
7ba26eda1c
commit
51092854fc
1 changed files with 95 additions and 2 deletions
|
|
@ -105,6 +105,7 @@ class TestNoiseModels(object):
|
||||||
Generic model checker
|
Generic model checker
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
np.random.seed(0)
|
||||||
self.N = 15
|
self.N = 15
|
||||||
self.D = 3
|
self.D = 3
|
||||||
self.X = np.random.rand(self.N, self.D)*10
|
self.X = np.random.rand(self.N, self.D)*10
|
||||||
|
|
@ -218,7 +219,8 @@ class TestNoiseModels(object):
|
||||||
"constraints": [(".*variance", self.constrain_positive)]
|
"constraints": [(".*variance", self.constrain_positive)]
|
||||||
},
|
},
|
||||||
"laplace": True,
|
"laplace": True,
|
||||||
"ep": False # FIXME: Should be True when we have it working again
|
"ep": False, # FIXME: Should be True when we have it working again
|
||||||
|
"variational_expectations": True,
|
||||||
},
|
},
|
||||||
"Gaussian_log": {
|
"Gaussian_log": {
|
||||||
"model": GPy.likelihoods.Gaussian(gp_link=link_functions.Log(), variance=self.var),
|
"model": GPy.likelihoods.Gaussian(gp_link=link_functions.Log(), variance=self.var),
|
||||||
|
|
@ -252,7 +254,8 @@ class TestNoiseModels(object):
|
||||||
"link_f_constraints": [partial(self.constrain_bounded, lower=0, upper=1)],
|
"link_f_constraints": [partial(self.constrain_bounded, lower=0, upper=1)],
|
||||||
"laplace": True,
|
"laplace": True,
|
||||||
"Y": self.binary_Y,
|
"Y": self.binary_Y,
|
||||||
"ep": False # FIXME: Should be True when we have it working again
|
"ep": False, # FIXME: Should be True when we have it working again
|
||||||
|
"variational_expectations": True
|
||||||
},
|
},
|
||||||
"Exponential_default": {
|
"Exponential_default": {
|
||||||
"model": GPy.likelihoods.Exponential(),
|
"model": GPy.likelihoods.Exponential(),
|
||||||
|
|
@ -347,6 +350,10 @@ class TestNoiseModels(object):
|
||||||
ep = attributes["ep"]
|
ep = attributes["ep"]
|
||||||
else:
|
else:
|
||||||
ep = False
|
ep = False
|
||||||
|
if "variational_expectations" in attributes:
|
||||||
|
var_exp = attributes["variational_expectations"]
|
||||||
|
else:
|
||||||
|
var_exp = False
|
||||||
|
|
||||||
#if len(param_vals) > 1:
|
#if len(param_vals) > 1:
|
||||||
#raise NotImplementedError("Cannot support multiple params in likelihood yet!")
|
#raise NotImplementedError("Cannot support multiple params in likelihood yet!")
|
||||||
|
|
@ -377,6 +384,11 @@ class TestNoiseModels(object):
|
||||||
if ep:
|
if ep:
|
||||||
#ep likelihood gradcheck
|
#ep likelihood gradcheck
|
||||||
yield self.t_ep_fit_rbf_white, model, self.X, Y, f, Y_metadata, self.step, param_vals, param_names, param_constraints
|
yield self.t_ep_fit_rbf_white, model, self.X, Y, f, Y_metadata, self.step, param_vals, param_names, param_constraints
|
||||||
|
if var_exp:
|
||||||
|
#Need to specify mu and var!
|
||||||
|
yield self.t_varexp, model, Y, Y_metadata
|
||||||
|
yield self.t_dexp_dmu, model, Y, Y_metadata
|
||||||
|
yield self.t_dexp_dvar, model, Y, Y_metadata
|
||||||
|
|
||||||
|
|
||||||
self.tearDown()
|
self.tearDown()
|
||||||
|
|
@ -603,6 +615,87 @@ class TestNoiseModels(object):
|
||||||
print(m)
|
print(m)
|
||||||
assert m.checkgrad(verbose=1, step=step)
|
assert m.checkgrad(verbose=1, step=step)
|
||||||
|
|
||||||
|
################
|
||||||
|
# variational expectations #
|
||||||
|
################
|
||||||
|
@with_setup(setUp, tearDown)
|
||||||
|
def t_varexp(self, model, Y, Y_metadata):
|
||||||
|
#Test that the analytic implementation (if it exists) matches the generic gauss
|
||||||
|
#hermite implementation
|
||||||
|
print("\n{}".format(inspect.stack()[0][3]))
|
||||||
|
#Make mu and var (marginal means and variances of q(f)) draws from a GP
|
||||||
|
k = GPy.kern.RBF(1).K(np.linspace(0,1,Y.shape[0])[:, None])
|
||||||
|
L = GPy.util.linalg.jitchol(k)
|
||||||
|
mu = L.dot(np.random.randn(*Y.shape))
|
||||||
|
#Variance must be positive
|
||||||
|
var = np.abs(L.dot(np.random.randn(*Y.shape)))
|
||||||
|
|
||||||
|
expectation = model.variational_expectations(Y=Y, m=mu, v=var, gh_points=None, Y_metadata=Y_metadata)[0]
|
||||||
|
|
||||||
|
#Implementation of gauss hermite integration
|
||||||
|
shape = mu.shape
|
||||||
|
gh_x, gh_w= np.polynomial.hermite.hermgauss(50)
|
||||||
|
m,v,Y = mu.flatten(), var.flatten(), Y.flatten()
|
||||||
|
#make a grid of points
|
||||||
|
X = gh_x[None,:]*np.sqrt(2.*v[:,None]) + m[:,None]
|
||||||
|
#evaluate the likelhood for the grid. First ax indexes the data (and mu, var) and the second indexes the grid.
|
||||||
|
# broadcast needs to be handled carefully.
|
||||||
|
logp = model.logpdf(X, Y[:,None], Y_metadata=Y_metadata)
|
||||||
|
#average over the gird to get derivatives of the Gaussian's parameters
|
||||||
|
#division by pi comes from fact that for each quadrature we need to scale by 1/sqrt(pi)
|
||||||
|
expectation_gh = np.dot(logp, gh_w)/np.sqrt(np.pi)
|
||||||
|
expectation_gh = expectation_gh.reshape(*shape)
|
||||||
|
|
||||||
|
np.testing.assert_almost_equal(expectation, expectation_gh, decimal=5)
|
||||||
|
|
||||||
|
@with_setup(setUp, tearDown)
|
||||||
|
def t_dexp_dmu(self, model, Y, Y_metadata):
|
||||||
|
print("\n{}".format(inspect.stack()[0][3]))
|
||||||
|
#Make mu and var (marginal means and variances of q(f)) draws from a GP
|
||||||
|
k = GPy.kern.RBF(1).K(np.linspace(0,1,Y.shape[0])[:, None])
|
||||||
|
L = GPy.util.linalg.jitchol(k)
|
||||||
|
mu = L.dot(np.random.randn(*Y.shape))
|
||||||
|
#Variance must be positive
|
||||||
|
var = np.abs(L.dot(np.random.randn(*Y.shape)))
|
||||||
|
expectation = functools.partial(model.variational_expectations, Y=Y, v=var, gh_points=None, Y_metadata=Y_metadata)
|
||||||
|
|
||||||
|
#Function to get the nth returned value
|
||||||
|
def F(mu):
|
||||||
|
return expectation(m=mu)[0]
|
||||||
|
def dmu(mu):
|
||||||
|
return expectation(m=mu)[1]
|
||||||
|
|
||||||
|
grad = GradientChecker(F, dmu, mu.copy(), 'm')
|
||||||
|
|
||||||
|
grad.randomize()
|
||||||
|
print(grad)
|
||||||
|
print(model)
|
||||||
|
assert grad.checkgrad(verbose=1)
|
||||||
|
|
||||||
|
@with_setup(setUp, tearDown)
|
||||||
|
def t_dexp_dvar(self, model, Y, Y_metadata):
|
||||||
|
print("\n{}".format(inspect.stack()[0][3]))
|
||||||
|
#Make mu and var (marginal means and variances of q(f)) draws from a GP
|
||||||
|
k = GPy.kern.RBF(1).K(np.linspace(0,1,Y.shape[0])[:, None])
|
||||||
|
L = GPy.util.linalg.jitchol(k)
|
||||||
|
mu = L.dot(np.random.randn(*Y.shape))
|
||||||
|
#Variance must be positive
|
||||||
|
var = np.abs(L.dot(np.random.randn(*Y.shape)))
|
||||||
|
expectation = functools.partial(model.variational_expectations, Y=Y, m=mu, gh_points=None, Y_metadata=Y_metadata)
|
||||||
|
|
||||||
|
#Function to get the nth returned value
|
||||||
|
def F(var):
|
||||||
|
return expectation(v=var)[0]
|
||||||
|
def dvar(var):
|
||||||
|
return expectation(v=var)[2]
|
||||||
|
|
||||||
|
grad = GradientChecker(F, dvar, var.copy(), 'v')
|
||||||
|
|
||||||
|
self.constrain_positive('v', grad)
|
||||||
|
grad.randomize()
|
||||||
|
print(grad)
|
||||||
|
print(model)
|
||||||
|
assert grad.checkgrad(verbose=1)
|
||||||
|
|
||||||
class LaplaceTests(unittest.TestCase):
|
class LaplaceTests(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue