more variational quadtrature code

This commit is contained in:
James Hensman 2014-10-16 15:41:01 +01:00
parent 9bfd569c7b
commit 30343f5e53
3 changed files with 21 additions and 23 deletions

View file

@ -113,10 +113,8 @@ class Bernoulli(Likelihood):
.. Note: .. Note:
Each y_i must be in {0, 1} Each y_i must be in {0, 1}
""" """
assert np.atleast_1d(inv_link_f).shape == np.atleast_1d(y).shape
#objective = (inv_link_f**y) * ((1.-inv_link_f)**(1.-y)) #objective = (inv_link_f**y) * ((1.-inv_link_f)**(1.-y))
objective = np.where(y, inv_link_f, 1.-inv_link_f) return np.where(y, inv_link_f, 1.-inv_link_f)
return np.exp(np.sum(np.log(objective)))
def logpdf_link(self, inv_link_f, y, Y_metadata=None): def logpdf_link(self, inv_link_f, y, Y_metadata=None):
""" """
@ -133,9 +131,7 @@ class Bernoulli(Likelihood):
:returns: log likelihood evaluated at points inverse link of f. :returns: log likelihood evaluated at points inverse link of f.
:rtype: float :rtype: float
""" """
assert np.atleast_1d(inv_link_f).shape == np.atleast_1d(y).shape
#objective = y*np.log(inv_link_f) + (1.-y)*np.log(inv_link_f) #objective = y*np.log(inv_link_f) + (1.-y)*np.log(inv_link_f)
state = np.seterr(divide='ignore')
p = np.where(y==1, inv_link_f, 1.-inv_link_f) p = np.where(y==1, inv_link_f, 1.-inv_link_f)
return np.log(p) return np.log(p)
@ -154,13 +150,10 @@ class Bernoulli(Likelihood):
:returns: gradient of log likelihood evaluated at points inverse link of f. :returns: gradient of log likelihood evaluated at points inverse link of f.
:rtype: Nx1 array :rtype: Nx1 array
""" """
assert np.atleast_1d(inv_link_f).shape == np.atleast_1d(y).shape
#grad = (y/inv_link_f) - (1.-y)/(1-inv_link_f) #grad = (y/inv_link_f) - (1.-y)/(1-inv_link_f)
state = np.seterr(divide='ignore') #grad = np.where(y, 1./inv_link_f, -1./(1-inv_link_f))
# TODO check y \in {0, 1} or {-1, 1} denom = np.where(y, inv_link_f, -(1-inv_link_f))
grad = np.where(y, 1./inv_link_f, -1./(1-inv_link_f)) return 1./denom
np.seterr(**state)
return grad
def d2logpdf_dlink2(self, inv_link_f, y, Y_metadata=None): def d2logpdf_dlink2(self, inv_link_f, y, Y_metadata=None):
""" """
@ -183,13 +176,12 @@ class Bernoulli(Likelihood):
Will return diagonal of hessian, since every where else it is 0, as the likelihood factorizes over cases Will return diagonal of hessian, since every where else it is 0, as the likelihood factorizes over cases
(the distribution for y_i depends only on inverse link of f_i not on inverse link of f_(j!=i) (the distribution for y_i depends only on inverse link of f_i not on inverse link of f_(j!=i)
""" """
assert np.atleast_1d(inv_link_f).shape == np.atleast_1d(y).shape
#d2logpdf_dlink2 = -y/(inv_link_f**2) - (1-y)/((1-inv_link_f)**2) #d2logpdf_dlink2 = -y/(inv_link_f**2) - (1-y)/((1-inv_link_f)**2)
state = np.seterr(divide='ignore') state = np.seterr(divide='ignore')
# TODO check y \in {0, 1} or {-1, 1} # TODO check y \in {0, 1} or {-1, 1}
d2logpdf_dlink2 = np.where(y, -1./np.square(inv_link_f), -1./np.square(1.-inv_link_f)) #d2logpdf_dlink2 = np.where(y, -1./np.square(inv_link_f), -1./np.square(1.-inv_link_f))
np.seterr(**state) arg = np.where(y, inv_link_f, 1.-inv_link_f)
return d2logpdf_dlink2 return -1./np.square(arg)
def d3logpdf_dlink3(self, inv_link_f, y, Y_metadata=None): def d3logpdf_dlink3(self, inv_link_f, y, Y_metadata=None):
""" """

View file

@ -146,20 +146,26 @@ class Likelihood(Parameterized):
if gh_points is None: if gh_points is None:
gh_x, gh_w = np.polynomial.hermite.hermgauss(20) gh_x, gh_w = np.polynomial.hermite.hermgauss(20)
else:
gh_x, gh_w = gh_points
shape = m.shape shape = m.shape
m,v,Y = m.flatten(), v.flatten(), Y.flatten() m,v,Y = m.flatten(), v.flatten(), Y.flatten()
#make a grid of points #make a grid of points
X = gh_x[None,:]*np.sqrt(2.*v[:,None]) + m[:,None] X = gh_x[None,:]*np.sqrt(2.*v[:,None]) + m[:,None]
logp = self.logpdf(X,Y[:,None])
p = np.clip(p, 1e-9, 1.-1e-9) # for numerical stability #evaluate the likelhood for the grid. First ax indexes the data (and mu, var) and the second indexes the grid.
N = stats.norm.pdf(X) # broadcast needs to be handled carefully.
F = np.log(p).dot(self.gh_w) logp = self.logpdf(X,Y[:,None])
NoverP = N/p dlogp_dx = self.dlogpdf_df(X, Y[:,None])
dF_dm = (NoverP*self.Ysign[:,None]).dot(self.gh_w) d2logp_dx2 = self.d2logpdf_df2(X, Y[:,None])
dF_dv = -0.5*(NoverP**2 + NoverP*X).dot(self.gh_w)
#average over the gird to get derivatives of the Gaussian's parameters
F = np.dot(logp, gh_w)
dF_dm = np.dot(dlogp_dx, gh_w)
dF_dv = np.dot(d2logp_dx2, gh_w)/2.
return F, dF_dm, dF_dv return F, dF_dm, dF_dv

View file

@ -352,7 +352,7 @@ class TestNoiseModels(object):
print model print model
#print model._get_params() #print model._get_params()
np.testing.assert_almost_equal( np.testing.assert_almost_equal(
model.pdf(f.copy(), Y.copy()), model.pdf(f.copy(), Y.copy()).prod(),
np.exp(model.logpdf(f.copy(), Y.copy()).sum()) np.exp(model.logpdf(f.copy(), Y.copy()).sum())
) )