pca adjustements to lvm models

This commit is contained in:
Max Zwiessele 2013-12-16 11:37:42 +00:00
parent f9c9e8e1d5
commit a6725b55e1
3 changed files with 94 additions and 33 deletions

View file

@ -2,17 +2,18 @@
# Licensed under the BSD 3-clause license (see LICENSE.txt) # Licensed under the BSD 3-clause license (see LICENSE.txt)
import numpy as np import numpy as np
import itertools
from matplotlib import pyplot
from ..core.sparse_gp import SparseGP from ..core.sparse_gp import SparseGP
from ..likelihoods import Gaussian from ..likelihoods import Gaussian
from .. import kern from .. import kern
import itertools from ..inference.optimization import SCG
from matplotlib.colors import colorConverter from ..util import plot_latent, linalg
from GPy.inference.optimization import SCG from .gplvm import GPLVM, initialise_latent
from GPy.util import plot_latent, linalg from ..util.plot_latent import most_significant_input_dimensions
from .gplvm import GPLVM from ..core.model import Model
from GPy.util.plot_latent import most_significant_input_dimensions from ..util.subarray_and_sorting import common_subarrays
from matplotlib import pyplot
from GPy.core.model import Model
class BayesianGPLVM(SparseGP, GPLVM): class BayesianGPLVM(SparseGP, GPLVM):
""" """
@ -34,7 +35,7 @@ class BayesianGPLVM(SparseGP, GPLVM):
likelihood = likelihood_or_Y likelihood = likelihood_or_Y
if X == None: if X == None:
X = self.initialise_latent(init, input_dim, likelihood.Y) X = initialise_latent(init, input_dim, likelihood.Y)
self.init = init self.init = init
if X_variance is None: if X_variance is None:
@ -308,14 +309,36 @@ class BayesianGPLVMWithMissingData(Model):
:type init: 'PCA' | 'random' :type init: 'PCA' | 'random'
""" """
def __init__(self, likelihood_or_Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10, def __init__(self, likelihood_or_Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
Z=None, kernel=None, missing=np.nan, **kwargs): Z=None, kernel=None, **kwargs):
#=======================================================================
# Filter Y, such that same missing data is at same positions.
# If full rows are missing, delete them entirely!
if type(likelihood_or_Y) is np.ndarray: if type(likelihood_or_Y) is np.ndarray:
likelihood = Gaussian(likelihood_or_Y) Y = likelihood_or_Y
likelihood = Gaussian
params = 1.
normalize=None
else: else:
likelihood = likelihood_or_Y Y = likelihood_or_Y.Y
likelihood = likelihood_or_Y.__class__
params = likelihood_or_Y._get_params()
if isinstance(likelihood_or_Y, Gaussian):
normalize = True
scale = likelihood_or_Y._scale
offset = likelihood_or_Y._offset
# Get common subrows
filter_ = np.isnan(Y)
self.subarray_indices = common_subarrays(filter_,axis=1)
likelihoods = [likelihood(Y[~np.array(v,dtype=bool),:][:,ind]) for v,ind in self.subarray_indices.iteritems()]
for l in likelihoods:
l._set_params(params)
if normalize: # get normalization in common
l._scale = scale
l._offset = offset
#=======================================================================
if X == None: if X == None:
X = self.initialise_latent(init, input_dim, likelihood.Y) X = initialise_latent(init, input_dim, Y[:,np.any(np.isnan(Y),1)])
self.init = init self.init = init
if X_variance is None: if X_variance is None:
@ -328,13 +351,52 @@ class BayesianGPLVMWithMissingData(Model):
if kernel is None: if kernel is None:
kernel = kern.rbf(input_dim) # + kern.white(input_dim) kernel = kern.rbf(input_dim) # + kern.white(input_dim)
SparseGP.__init__(self, X, likelihood, kernel, Z=Z, X_variance=X_variance, **kwargs) self.submodels = [BayesianGPLVM(l, input_dim, X, X_variance, init, num_inducing, Z, kernel) for l in likelihoods]
self.gref = self.submodels[0]
#:type self.gref: BayesianGPLVM
self.ensure_default_constraints() self.ensure_default_constraints()
def log_likelihood(self):
ll = -self.gref.KL_divergence()
for g in self.submodels:
ll += SparseGP.log_likelihood(g)
return ll
def _log_likelihood_gradients(self):
dLdmu, dLdS = reduce(lambda a, b: [a[0] + b[0], a[1] + b[1]], (g.dL_dmuS() for g in self.bgplvms))
dKLmu, dKLdS = self.gref.dKL_dmuS()
dLdmu -= dKLmu
dLdS -= dKLdS
dLdmuS = np.hstack((dLdmu.flatten(), dLdS.flatten())).flatten()
dldzt1 = reduce(lambda a, b: a + b, (SparseGP._log_likelihood_gradients(g)[:self.gref.num_inducing*self.gref.input_dim] for g in self.submodels))
return np.hstack((dLdmuS,
dldzt1,
np.hstack([np.hstack([g.dL_dtheta(),
g.likelihood._gradients(\
partial=g.partial_for_likelihood)]) \
for g in self.submodels])))
def getstate(self):
return Model.getstate(self)+[self.submodels,self.subarray_indices]
def setstate(self, state):
self.subarray_indices = state.pop()
self.submodels = state.pop()
self.gref = self.submodels[0]
Model.setstate(self, state)
self._set_params(self._get_params())
def _get_param_names(self): def _get_param_names(self):
X_names = sum([['X_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], []) X_names = sum([['X_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], [])
S_names = sum([['X_variance_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], []) S_names = sum([['X_variance_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], [])
return (X_names + S_names + SparseGP._get_param_names(self)) return (X_names + S_names + SparseGP._get_param_names(self.gref))
def _get_params(self):
return self.gref._get_params()
def _set_params(self, x):
[g._set_params(x) for g in self.submodels]
pass pass

View file

@ -10,6 +10,13 @@ from ..core import GP
from ..likelihoods import Gaussian from ..likelihoods import Gaussian
from .. import util from .. import util
def initialise_latent(init, input_dim, Y):
Xr = np.random.randn(Y.shape[0], input_dim)
if init == 'pca':
from ..util.linalg import pca
PC = pca(Y, input_dim)[0]
Xr[:PC.shape[0], :PC.shape[1]] = PC
return Xr
class GPLVM(GP): class GPLVM(GP):
""" """
@ -20,12 +27,12 @@ class GPLVM(GP):
:param input_dim: latent dimensionality :param input_dim: latent dimensionality
:type input_dim: int :type input_dim: int
:param init: initialisation method for the latent space :param init: initialisation method for the latent space
:type init: 'PCA'|'random' :type init: 'pca'|'random'
""" """
def __init__(self, Y, input_dim, init='PCA', X=None, kernel=None, normalize_Y=False): def __init__(self, Y, input_dim, init='pca', X=None, kernel=None, normalize_Y=False):
if X is None: if X is None:
X = self.initialise_latent(init, input_dim, Y) X = initialise_latent(init, input_dim, Y)
if kernel is None: if kernel is None:
kernel = kern.rbf(input_dim, ARD=input_dim > 1) + kern.bias(input_dim, np.exp(-2)) kernel = kern.rbf(input_dim, ARD=input_dim > 1) + kern.bias(input_dim, np.exp(-2))
likelihood = Gaussian(Y, normalize=normalize_Y, variance=np.exp(-2.)) likelihood = Gaussian(Y, normalize=normalize_Y, variance=np.exp(-2.))
@ -33,14 +40,6 @@ class GPLVM(GP):
self.set_prior('.*X', priors.Gaussian(0, 1)) self.set_prior('.*X', priors.Gaussian(0, 1))
self.ensure_default_constraints() self.ensure_default_constraints()
def initialise_latent(self, init, input_dim, Y):
Xr = np.random.randn(Y.shape[0], input_dim)
if init == 'PCA':
from ..util.linalg import PCA
PC = PCA(Y, input_dim)[0]
Xr[:PC.shape[0], :PC.shape[1]] = PC
return Xr
def _get_param_names(self): def _get_param_names(self):
return sum([['X_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], []) + GP._get_param_names(self) return sum([['X_%i_%i' % (n, q) for q in range(self.input_dim)] for n in range(self.num_data)], []) + GP._get_param_names(self)

View file

@ -5,7 +5,7 @@ Created on 10 Apr 2013
''' '''
from GPy.core import Model from GPy.core import Model
from GPy.core import SparseGP from GPy.core import SparseGP
from GPy.util.linalg import PCA from GPy.util.linalg import pca
import numpy import numpy
import itertools import itertools
import pylab import pylab
@ -26,8 +26,8 @@ class MRD(Model):
:type input_dim: int :type input_dim: int
:param initx: initialisation method for the latent space : :param initx: initialisation method for the latent space :
* 'concat' - PCA on concatenation of all datasets * 'concat' - pca on concatenation of all datasets
* 'single' - Concatenation of PCA on datasets, respectively * 'single' - Concatenation of pca on datasets, respectively
* 'random' - Random draw from a normal * 'random' - Random draw from a normal
:type initx: ['concat'|'single'|'random'] :type initx: ['concat'|'single'|'random']
@ -42,7 +42,7 @@ class MRD(Model):
""" """
def __init__(self, likelihood_or_Y_list, input_dim, num_inducing=10, names=None, def __init__(self, likelihood_or_Y_list, input_dim, num_inducing=10, names=None,
kernels=None, initx='PCA', kernels=None, initx='pca',
initz='permute', _debug=False, **kw): initz='permute', _debug=False, **kw):
if names is None: if names is None:
self.names = ["{}".format(i) for i in range(len(likelihood_or_Y_list))] self.names = ["{}".format(i) for i in range(len(likelihood_or_Y_list))]
@ -237,7 +237,7 @@ class MRD(Model):
partial=g.partial_for_likelihood)]) \ partial=g.partial_for_likelihood)]) \
for g in self.bgplvms]))) for g in self.bgplvms])))
def _init_X(self, init='PCA', likelihood_list=None): def _init_X(self, init='pca', likelihood_list=None):
if likelihood_list is None: if likelihood_list is None:
likelihood_list = self.likelihood_list likelihood_list = self.likelihood_list
Ylist = [] Ylist = []
@ -248,11 +248,11 @@ class MRD(Model):
Ylist.append(likelihood_or_Y.Y) Ylist.append(likelihood_or_Y.Y)
del likelihood_list del likelihood_list
if init in "PCA_concat": if init in "PCA_concat":
X = PCA(numpy.hstack(Ylist), self.input_dim)[0] X = pca(numpy.hstack(Ylist), self.input_dim)[0]
elif init in "PCA_single": elif init in "PCA_single":
X = numpy.zeros((Ylist[0].shape[0], self.input_dim)) X = numpy.zeros((Ylist[0].shape[0], self.input_dim))
for qs, Y in itertools.izip(numpy.array_split(numpy.arange(self.input_dim), len(Ylist)), Ylist): for qs, Y in itertools.izip(numpy.array_split(numpy.arange(self.input_dim), len(Ylist)), Ylist):
X[:, qs] = PCA(Y, len(qs))[0] X[:, qs] = pca(Y, len(qs))[0]
else: # init == 'random': else: # init == 'random':
X = numpy.random.randn(Ylist[0].shape[0], self.input_dim) X = numpy.random.randn(Ylist[0].shape[0], self.input_dim)
self.X = X self.X = X