mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-06-05 14:55:15 +02:00
Merge branch 'params' of github.com:SheffieldML/GPy into params
This commit is contained in:
commit
c7a3060c5a
38 changed files with 1131 additions and 1053 deletions
|
|
@ -4,6 +4,7 @@ import warnings
|
||||||
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
||||||
|
|
||||||
import core
|
import core
|
||||||
|
from core.parameterization import transformations, priors
|
||||||
import models
|
import models
|
||||||
import mappings
|
import mappings
|
||||||
import inference
|
import inference
|
||||||
|
|
@ -14,7 +15,6 @@ import testing
|
||||||
from numpy.testing import Tester
|
from numpy.testing import Tester
|
||||||
from nose.tools import nottest
|
from nose.tools import nottest
|
||||||
import kern
|
import kern
|
||||||
from core import priors
|
|
||||||
import plotting
|
import plotting
|
||||||
|
|
||||||
@nottest
|
@nottest
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
|
|
||||||
from model import *
|
from model import *
|
||||||
from parameterization import priors
|
|
||||||
from parameterization.parameterized import *
|
from parameterization.parameterized import *
|
||||||
from gp import GP
|
from gp import GP
|
||||||
from sparse_gp import SparseGP
|
from sparse_gp import SparseGP
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class GP(Model):
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, X, Y, kernel, likelihood, inference_method=None, name='gp'):
|
def __init__(self, X, Y, kernel, likelihood, inference_method=None, Y_metadata=None, name='gp'):
|
||||||
super(GP, self).__init__(name)
|
super(GP, self).__init__(name)
|
||||||
|
|
||||||
assert X.ndim == 2
|
assert X.ndim == 2
|
||||||
|
|
@ -38,6 +38,11 @@ class GP(Model):
|
||||||
assert Y.shape[0] == self.num_data
|
assert Y.shape[0] == self.num_data
|
||||||
_, self.output_dim = self.Y.shape
|
_, self.output_dim = self.Y.shape
|
||||||
|
|
||||||
|
if Y_metadata is not None:
|
||||||
|
self.Y_metadata = ObservableArray(Y_metadata)
|
||||||
|
else:
|
||||||
|
self.Y_metadata = None
|
||||||
|
|
||||||
assert isinstance(kernel, kern.kern)
|
assert isinstance(kernel, kern.kern)
|
||||||
self.kern = kernel
|
self.kern = kernel
|
||||||
|
|
||||||
|
|
@ -55,10 +60,11 @@ class GP(Model):
|
||||||
|
|
||||||
self.add_parameter(self.kern)
|
self.add_parameter(self.kern)
|
||||||
self.add_parameter(self.likelihood)
|
self.add_parameter(self.likelihood)
|
||||||
self.parameters_changed()
|
if self.__class__ is GP:
|
||||||
|
self.parameters_changed()
|
||||||
|
|
||||||
def parameters_changed(self):
|
def parameters_changed(self):
|
||||||
self.posterior, self._log_marginal_likelihood, grad_dict = self.inference_method.inference(self.kern, self.X, self.likelihood, self.Y)
|
self.posterior, self._log_marginal_likelihood, grad_dict = self.inference_method.inference(self.kern, self.X, self.likelihood, self.Y, Y_metadata=self.Y_metadata)
|
||||||
self._dL_dK = grad_dict['dL_dK']
|
self._dL_dK = grad_dict['dL_dK']
|
||||||
|
|
||||||
def log_likelihood(self):
|
def log_likelihood(self):
|
||||||
|
|
@ -111,7 +117,7 @@ class GP(Model):
|
||||||
This is to allow for different normalizations of the output dimensions.
|
This is to allow for different normalizations of the output dimensions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# normalize X values
|
#predict the latent function values
|
||||||
mu, var = self._raw_predict(Xnew, full_cov=full_cov, which_parts=which_parts)
|
mu, var = self._raw_predict(Xnew, full_cov=full_cov, which_parts=which_parts)
|
||||||
|
|
||||||
# now push through likelihood
|
# now push through likelihood
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,10 @@ import itertools
|
||||||
# import numdifftools as ndt
|
# import numdifftools as ndt
|
||||||
|
|
||||||
class Model(Parameterized):
|
class Model(Parameterized):
|
||||||
_fail_count = 0 # Count of failed optimization steps (see objective)
|
_fail_count = 0 # Count of failed optimization steps (see objective)
|
||||||
_allowed_failures = 10 # number of allowed failures
|
_allowed_failures = 10 # number of allowed failures
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
super(Model, self).__init__(name)#Parameterized.__init__(self)
|
super(Model, self).__init__(name) # Parameterized.__init__(self)
|
||||||
self.priors = []
|
|
||||||
self._priors = ParameterIndexOperations()
|
|
||||||
self.optimization_runs = []
|
self.optimization_runs = []
|
||||||
self.sampling_runs = []
|
self.sampling_runs = []
|
||||||
self.preferred_optimizer = 'scg'
|
self.preferred_optimizer = 'scg'
|
||||||
|
|
@ -30,10 +28,10 @@ class Model(Parameterized):
|
||||||
def log_likelihood(self):
|
def log_likelihood(self):
|
||||||
raise NotImplementedError, "this needs to be implemented to use the model class"
|
raise NotImplementedError, "this needs to be implemented to use the model class"
|
||||||
def _log_likelihood_gradients(self):
|
def _log_likelihood_gradients(self):
|
||||||
#def dK_d(self, param, dL_dK, X, X2)
|
# def dK_d(self, param, dL_dK, X, X2)
|
||||||
g = np.zeros(self.size)
|
g = np.zeros(self.size)
|
||||||
try:
|
try:
|
||||||
#[g.__setitem__(s, self.gradient_mapping[p]().flat) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed]
|
# [g.__setitem__(s, self.gradient_mapping[p]().flat) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed]
|
||||||
[p._collect_gradient(g[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed]
|
[p._collect_gradient(g[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise ValueError, 'Gradient for {} not defined, please specify gradients for parameters to optimize'.format(p.name)
|
raise ValueError, 'Gradient for {} not defined, please specify gradients for parameters to optimize'.format(p.name)
|
||||||
|
|
@ -67,66 +65,66 @@ class Model(Parameterized):
|
||||||
self.priors = state.pop()
|
self.priors = state.pop()
|
||||||
Parameterized._setstate(self, state)
|
Parameterized._setstate(self, state)
|
||||||
|
|
||||||
def set_prior(self, regexp, what):
|
# def set_prior(self, regexp, what):
|
||||||
"""
|
# """
|
||||||
|
#
|
||||||
Sets priors on the model parameters.
|
# Sets priors on the model parameters.
|
||||||
|
#
|
||||||
**Notes**
|
# **Notes**
|
||||||
|
#
|
||||||
Asserts that the prior is suitable for the constraint. If the
|
# Asserts that the prior is suitable for the constraint. If the
|
||||||
wrong constraint is in place, an error is raised. If no
|
# wrong constraint is in place, an error is raised. If no
|
||||||
constraint is in place, one is added (warning printed).
|
# constraint is in place, one is added (warning printed).
|
||||||
|
#
|
||||||
For tied parameters, the prior will only be "counted" once, thus
|
# For tied parameters, the prior will only be "counted" once, thus
|
||||||
a prior object is only inserted on the first tied index
|
# a prior object is only inserted on the first tied index
|
||||||
|
#
|
||||||
:param regexp: regular expression of parameters on which priors need to be set.
|
# :param regexp: regular expression of parameters on which priors need to be set.
|
||||||
:type param: string, regexp, or integer array
|
# :type param: string, regexp, or integer array
|
||||||
:param what: prior to set on parameter.
|
# :param what: prior to set on parameter.
|
||||||
:type what: GPy.core.Prior type
|
# :type what: GPy.core.Prior type
|
||||||
|
#
|
||||||
"""
|
# """
|
||||||
if self.priors is None:
|
# if self.priors is None:
|
||||||
self.priors = [None for i in range(self._get_params().size)]
|
# self.priors = [None for i in range(self._get_params().size)]
|
||||||
|
#
|
||||||
which = self.grep_param_names(regexp)
|
# which = self.grep_param_names(regexp)
|
||||||
|
#
|
||||||
# check tied situation
|
# # check tied situation
|
||||||
tie_partial_matches = [tie for tie in self.tied_indices if (not set(tie).isdisjoint(set(which))) & (not set(tie) == set(which))]
|
# tie_partial_matches = [tie for tie in self.tied_indices if (not set(tie).isdisjoint(set(which))) & (not set(tie) == set(which))]
|
||||||
if len(tie_partial_matches):
|
# if len(tie_partial_matches):
|
||||||
raise ValueError, "cannot place prior across partial ties"
|
# raise ValueError, "cannot place prior across partial ties"
|
||||||
tie_matches = [tie for tie in self.tied_indices if set(which) == set(tie) ]
|
# tie_matches = [tie for tie in self.tied_indices if set(which) == set(tie) ]
|
||||||
if len(tie_matches) > 1:
|
# if len(tie_matches) > 1:
|
||||||
raise ValueError, "cannot place prior across multiple ties"
|
# raise ValueError, "cannot place prior across multiple ties"
|
||||||
elif len(tie_matches) == 1:
|
# elif len(tie_matches) == 1:
|
||||||
which = which[:1] # just place a prior object on the first parameter
|
# which = which[:1] # just place a prior object on the first parameter
|
||||||
|
#
|
||||||
|
#
|
||||||
# check constraints are okay
|
# # check constraints are okay
|
||||||
|
#
|
||||||
if what.domain is _POSITIVE:
|
# if what.domain is _POSITIVE:
|
||||||
constrained_positive_indices = [i for i, t in zip(self.constrained_indices, self.constraints) if t.domain is _POSITIVE]
|
# constrained_positive_indices = [i for i, t in zip(self.constrained_indices, self.constraints) if t.domain is _POSITIVE]
|
||||||
if len(constrained_positive_indices):
|
# if len(constrained_positive_indices):
|
||||||
constrained_positive_indices = np.hstack(constrained_positive_indices)
|
# constrained_positive_indices = np.hstack(constrained_positive_indices)
|
||||||
else:
|
# else:
|
||||||
constrained_positive_indices = np.zeros(shape=(0,))
|
# constrained_positive_indices = np.zeros(shape=(0,))
|
||||||
bad_constraints = np.setdiff1d(self.all_constrained_indices(), constrained_positive_indices)
|
# bad_constraints = np.setdiff1d(self.all_constrained_indices(), constrained_positive_indices)
|
||||||
assert not np.any(which[:, None] == bad_constraints), "constraint and prior incompatible"
|
# assert not np.any(which[:, None] == bad_constraints), "constraint and prior incompatible"
|
||||||
unconst = np.setdiff1d(which, constrained_positive_indices)
|
# unconst = np.setdiff1d(which, constrained_positive_indices)
|
||||||
if len(unconst):
|
# if len(unconst):
|
||||||
print "Warning: constraining parameters to be positive:"
|
# print "Warning: constraining parameters to be positive:"
|
||||||
print '\n'.join([n for i, n in enumerate(self._get_param_names()) if i in unconst])
|
# print '\n'.join([n for i, n in enumerate(self._get_param_names()) if i in unconst])
|
||||||
print '\n'
|
# print '\n'
|
||||||
self.constrain_positive(unconst)
|
# self.constrain_positive(unconst)
|
||||||
elif what.domain is _REAL:
|
# elif what.domain is _REAL:
|
||||||
assert not np.any(which[:, None] == self.all_constrained_indices()), "constraint and prior incompatible"
|
# assert not np.any(which[:, None] == self.all_constrained_indices()), "constraint and prior incompatible"
|
||||||
else:
|
# else:
|
||||||
raise ValueError, "prior not recognised"
|
# raise ValueError, "prior not recognised"
|
||||||
|
#
|
||||||
# store the prior in a local list
|
# # store the prior in a local list
|
||||||
for w in which:
|
# for w in which:
|
||||||
self.priors[w] = what
|
# self.priors[w] = what
|
||||||
|
|
||||||
def get_gradient(self, name, return_names=False):
|
def get_gradient(self, name, return_names=False):
|
||||||
"""
|
"""
|
||||||
|
|
@ -146,36 +144,19 @@ class Model(Parameterized):
|
||||||
else:
|
else:
|
||||||
raise AttributeError, "no parameter matches %s" % name
|
raise AttributeError, "no parameter matches %s" % name
|
||||||
|
|
||||||
def log_prior(self):
|
|
||||||
"""evaluate the prior"""
|
|
||||||
if self.priors is not None:
|
|
||||||
return np.sum([p.lnpdf(x) for p, x in zip(self.priors, self._get_params()) if p is not None])
|
|
||||||
else:
|
|
||||||
return 0.
|
|
||||||
|
|
||||||
def _log_prior_gradients(self):
|
|
||||||
"""evaluate the gradients of the priors"""
|
|
||||||
if self.priors is None:
|
|
||||||
return 0.
|
|
||||||
x = self._get_params()
|
|
||||||
ret = np.zeros(x.size)
|
|
||||||
[np.put(ret, i, p.lnpdf_grad(xx)) for i, (p, xx) in enumerate(zip(self.priors, x)) if not p is None]
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def randomize(self):
|
def randomize(self):
|
||||||
"""
|
"""
|
||||||
Randomize the model.
|
Randomize the model.
|
||||||
Make this draw from the prior if one exists, else draw from N(0,1)
|
Make this draw from the prior if one exists, else draw from N(0,1)
|
||||||
"""
|
"""
|
||||||
# first take care of all parameters (from N(0,1))
|
# first take care of all parameters (from N(0,1))
|
||||||
#x = self._get_params_transformed()
|
# x = self._get_params_transformed()
|
||||||
x = np.random.randn(self.size_transformed)
|
x = np.random.randn(self.size_transformed)
|
||||||
x = self._untransform_params(x)
|
x = self._untransform_params(x)
|
||||||
# now draw from prior where possible
|
# now draw from prior where possible
|
||||||
if self.priors is not None and len(self.priors):
|
[np.put(x, ind, p.rvs(ind.size)) for p, ind in self.priors.iteritems() if not p is None]
|
||||||
[np.put(x, i, p.rvs(1)) for i, p in enumerate(self.priors) if not p is None]
|
|
||||||
self._set_params(x)
|
self._set_params(x)
|
||||||
#self._set_params_transformed(self._get_params_transformed()) # makes sure all of the tied parameters get the same init (since there's only one prior object...)
|
# self._set_params_transformed(self._get_params_transformed()) # makes sure all of the tied parameters get the same init (since there's only one prior object...)
|
||||||
|
|
||||||
def optimize_restarts(self, num_restarts=10, robust=False, verbose=True, parallel=False, num_processes=None, **kwargs):
|
def optimize_restarts(self, num_restarts=10, robust=False, verbose=True, parallel=False, num_processes=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -220,8 +201,8 @@ class Model(Parameterized):
|
||||||
job = pool.apply_async(opt_wrapper, args=(self,), kwds=kwargs)
|
job = pool.apply_async(opt_wrapper, args=(self,), kwds=kwargs)
|
||||||
jobs.append(job)
|
jobs.append(job)
|
||||||
|
|
||||||
pool.close() # signal that no more data coming in
|
pool.close() # signal that no more data coming in
|
||||||
pool.join() # wait for all the tasks to complete
|
pool.join() # wait for all the tasks to complete
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print "Ctrl+c received, terminating and joining pool."
|
print "Ctrl+c received, terminating and joining pool."
|
||||||
pool.terminate()
|
pool.terminate()
|
||||||
|
|
@ -378,7 +359,7 @@ class Model(Parameterized):
|
||||||
|
|
||||||
def optimize_SGD(self, momentum=0.1, learning_rate=0.01, iterations=20, **kwargs):
|
def optimize_SGD(self, momentum=0.1, learning_rate=0.01, iterations=20, **kwargs):
|
||||||
# assert self.Y.shape[1] > 1, "SGD only works with D > 1"
|
# assert self.Y.shape[1] > 1, "SGD only works with D > 1"
|
||||||
sgd = SGD.StochasticGD(self, iterations, learning_rate, momentum, **kwargs) # @UndefinedVariable
|
sgd = SGD.StochasticGD(self, iterations, learning_rate, momentum, **kwargs) # @UndefinedVariable
|
||||||
sgd.run()
|
sgd.run()
|
||||||
self.optimization_runs.append(sgd)
|
self.optimization_runs.append(sgd)
|
||||||
|
|
||||||
|
|
@ -403,17 +384,34 @@ class Model(Parameterized):
|
||||||
x = self._get_params_transformed().copy()
|
x = self._get_params_transformed().copy()
|
||||||
|
|
||||||
if not verbose:
|
if not verbose:
|
||||||
|
# make sure only to test the selected parameters
|
||||||
|
if target_param is None:
|
||||||
|
transformed_index = range(len(x))
|
||||||
|
else:
|
||||||
|
transformed_index = self._raveled_index_for(target_param)
|
||||||
|
if self._has_fixes():
|
||||||
|
indices = np.r_[:self.size]
|
||||||
|
which = (transformed_index[:,None]==indices[self._fixes_][None,:]).nonzero()
|
||||||
|
transformed_index = (indices-(~self._fixes_).cumsum())[transformed_index[which[0]]]
|
||||||
|
|
||||||
|
if transformed_index.size == 0:
|
||||||
|
print "No free parameters to check"
|
||||||
|
return
|
||||||
|
|
||||||
# just check the global ratio
|
# just check the global ratio
|
||||||
dx = step * np.sign(np.random.uniform(-1, 1, x.size))
|
dx = np.zeros_like(x)
|
||||||
|
dx[transformed_index] = step * np.sign(np.random.uniform(-1, 1, transformed_index.size))
|
||||||
|
|
||||||
# evaulate around the point x
|
# evaulate around the point x
|
||||||
f1 = self.objective_function(x + dx)
|
f1 = self.objective_function(x + dx)
|
||||||
f2 = self.objective_function(x - dx)
|
f2 = self.objective_function(x - dx)
|
||||||
gradient = self.objective_function_gradients(x)
|
gradient = self.objective_function_gradients(x)
|
||||||
|
|
||||||
|
dx = dx[transformed_index]
|
||||||
|
gradient = gradient[transformed_index]
|
||||||
|
|
||||||
numerical_gradient = (f1 - f2) / (2 * dx)
|
numerical_gradient = (f1 - f2) / (2 * dx)
|
||||||
global_ratio = (f1 - f2) / (2 * np.dot(dx, np.where(gradient==0, 1e-32, gradient)))
|
global_ratio = (f1 - f2) / (2 * np.dot(dx, np.where(gradient == 0, 1e-32, gradient)))
|
||||||
|
|
||||||
return (np.abs(1. - global_ratio) < tolerance) or (np.abs(gradient - numerical_gradient).mean() < tolerance)
|
return (np.abs(1. - global_ratio) < tolerance) or (np.abs(gradient - numerical_gradient).mean() < tolerance)
|
||||||
else:
|
else:
|
||||||
# check the gradient of each parameter individually, and do some pretty printing
|
# check the gradient of each parameter individually, and do some pretty printing
|
||||||
|
|
@ -433,43 +431,50 @@ class Model(Parameterized):
|
||||||
separator = '-' * len(header_string[0])
|
separator = '-' * len(header_string[0])
|
||||||
print '\n'.join([header_string[0], separator])
|
print '\n'.join([header_string[0], separator])
|
||||||
if target_param is None:
|
if target_param is None:
|
||||||
param_list = range(len(x))
|
param_index = range(len(x))
|
||||||
|
transformed_index = param_index
|
||||||
else:
|
else:
|
||||||
param_list = self._raveled_index_for(target_param)
|
param_index = self._raveled_index_for(target_param)
|
||||||
if self._has_fixes():
|
if self._has_fixes():
|
||||||
param_list = np.intersect1d(param_list, np.r_[:self.size][self._fixes_], True)
|
indices = np.r_[:self.size]
|
||||||
|
which = (param_index[:,None]==indices[self._fixes_][None,:]).nonzero()
|
||||||
if param_list.size == 0:
|
param_index = param_index[which[0]]
|
||||||
|
transformed_index = (indices-(~self._fixes_).cumsum())[param_index]
|
||||||
|
#print param_index, transformed_index
|
||||||
|
else:
|
||||||
|
transformed_index = param_index
|
||||||
|
|
||||||
|
if param_index.size == 0:
|
||||||
print "No free parameters to check"
|
print "No free parameters to check"
|
||||||
return
|
return
|
||||||
|
|
||||||
gradient = self.objective_function_gradients(x)
|
gradient = self.objective_function_gradients(x)
|
||||||
np.where(gradient==0, 1e-312, gradient)
|
np.where(gradient == 0, 1e-312, gradient)
|
||||||
ret = True
|
ret = True
|
||||||
for i, ind in enumerate(param_list):
|
for nind, xind in itertools.izip(param_index, transformed_index):
|
||||||
xx = x.copy()
|
xx = x.copy()
|
||||||
xx[ind] += step
|
xx[xind] += step
|
||||||
f1 = self.objective_function(xx)
|
f1 = self.objective_function(xx)
|
||||||
xx[ind] -= 2.*step
|
xx[xind] -= 2.*step
|
||||||
f2 = self.objective_function(xx)
|
f2 = self.objective_function(xx)
|
||||||
|
|
||||||
numerical_gradient = (f1 - f2) / (2 * step)
|
numerical_gradient = (f1 - f2) / (2 * step)
|
||||||
ratio = (f1 - f2) / (2 * step * gradient[ind])
|
ratio = (f1 - f2) / (2 * step * gradient[xind])
|
||||||
difference = np.abs((f1 - f2) / 2 / step - gradient[ind])
|
difference = np.abs((f1 - f2) / 2 / step - gradient[xind])
|
||||||
|
|
||||||
if (np.abs(1. - ratio) < tolerance) or np.abs(difference) < tolerance:
|
if (np.abs(1. - ratio) < tolerance) or np.abs(difference) < tolerance:
|
||||||
formatted_name = "\033[92m {0} \033[0m".format(names[ind])
|
formatted_name = "\033[92m {0} \033[0m".format(names[nind])
|
||||||
ret &= True
|
ret &= True
|
||||||
else:
|
else:
|
||||||
formatted_name = "\033[91m {0} \033[0m".format(names[ind])
|
formatted_name = "\033[91m {0} \033[0m".format(names[nind])
|
||||||
ret &= False
|
ret &= False
|
||||||
|
|
||||||
r = '%.6f' % float(ratio)
|
r = '%.6f' % float(ratio)
|
||||||
d = '%.6f' % float(difference)
|
d = '%.6f' % float(difference)
|
||||||
g = '%.6f' % gradient[ind]
|
g = '%.6f' % gradient[xind]
|
||||||
ng = '%.6f' % float(numerical_gradient)
|
ng = '%.6f' % float(numerical_gradient)
|
||||||
grad_string = "{0:<{c0}}|{1:^{c1}}|{2:^{c2}}|{3:^{c3}}|{4:^{c4}}".format(formatted_name, r, d, g, ng, c0=cols[0] + 9, c1=cols[1], c2=cols[2], c3=cols[3], c4=cols[4])
|
grad_string = "{0:<{c0}}|{1:^{c1}}|{2:^{c2}}|{3:^{c3}}|{4:^{c4}}".format(formatted_name, r, d, g, ng, c0=cols[0] + 9, c1=cols[1], c2=cols[2], c3=cols[3], c4=cols[4])
|
||||||
print grad_string
|
print grad_string
|
||||||
|
self._set_params_transformed(x)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def input_sensitivity(self):
|
def input_sensitivity(self):
|
||||||
|
|
@ -517,10 +522,10 @@ class Model(Parameterized):
|
||||||
alpha = 0
|
alpha = 0
|
||||||
stop = False
|
stop = False
|
||||||
|
|
||||||
#Handle **kwargs
|
# Handle **kwargs
|
||||||
ep_args = {}
|
ep_args = {}
|
||||||
for arg in kwargs.keys():
|
for arg in kwargs.keys():
|
||||||
if arg in ('epsilon','power_ep'):
|
if arg in ('epsilon', 'power_ep'):
|
||||||
ep_args[arg] = kwargs[arg]
|
ep_args[arg] = kwargs[arg]
|
||||||
del kwargs[arg]
|
del kwargs[arg]
|
||||||
|
|
||||||
|
|
@ -528,7 +533,7 @@ class Model(Parameterized):
|
||||||
last_approximation = self.likelihood.copy()
|
last_approximation = self.likelihood.copy()
|
||||||
last_params = self._get_params()
|
last_params = self._get_params()
|
||||||
if len(ep_args) == 2:
|
if len(ep_args) == 2:
|
||||||
self.update_likelihood_approximation(epsilon=ep_args['epsilon'],power_ep=ep_args['power_ep'])
|
self.update_likelihood_approximation(epsilon=ep_args['epsilon'], power_ep=ep_args['power_ep'])
|
||||||
elif len(ep_args) == 1:
|
elif len(ep_args) == 1:
|
||||||
if ep_args.keys()[0] == 'epsilon':
|
if ep_args.keys()[0] == 'epsilon':
|
||||||
self.update_likelihood_approximation(epsilon=ep_args['epsilon'])
|
self.update_likelihood_approximation(epsilon=ep_args['epsilon'])
|
||||||
|
|
@ -540,8 +545,8 @@ class Model(Parameterized):
|
||||||
ll_change = new_ll - last_ll
|
ll_change = new_ll - last_ll
|
||||||
|
|
||||||
if ll_change < 0:
|
if ll_change < 0:
|
||||||
self.likelihood = last_approximation # restore previous likelihood approximation
|
self.likelihood = last_approximation # restore previous likelihood approximation
|
||||||
self._set_params(last_params) # restore model parameters
|
self._set_params(last_params) # restore model parameters
|
||||||
print "Log-likelihood decrement: %s \nLast likelihood update discarded." % ll_change
|
print "Log-likelihood decrement: %s \nLast likelihood update discarded." % ll_change
|
||||||
stop = True
|
stop = True
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,22 @@
|
||||||
__updated__ = '2013-12-16'
|
__updated__ = '2013-12-16'
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from parameter_core import Observable
|
from parameter_core import Observable, Parameterizable
|
||||||
|
|
||||||
class ListArray(np.ndarray):
|
|
||||||
"""
|
|
||||||
ndarray which can be stored in lists and checked if it is in.
|
|
||||||
WARNING: This overrides the functionality of x==y!!!
|
|
||||||
Use numpy.equal(x,y) for element-wise equality testing.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __new__(cls, input_array):
|
|
||||||
obj = np.asanyarray(input_array).view(cls)
|
|
||||||
return obj
|
|
||||||
#def __eq__(self, other):
|
|
||||||
# return other is self
|
|
||||||
|
|
||||||
class ParamList(list):
|
class ParamList(list):
|
||||||
|
"""
|
||||||
|
List to store ndarray-likes in.
|
||||||
|
It will look for 'is' instead of calling __eq__ on each element.
|
||||||
|
"""
|
||||||
def __contains__(self, other):
|
def __contains__(self, other):
|
||||||
for el in self:
|
for el in self:
|
||||||
if el is other:
|
if el is other:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ObservableArray(ListArray, Observable):
|
class ObservableArray(np.ndarray, Observable):
|
||||||
"""
|
"""
|
||||||
An ndarray which reports changes to its observers.
|
An ndarray which reports changes to its observers.
|
||||||
The observers can add themselves with a callable, which
|
The observers can add themselves with a callable, which
|
||||||
|
|
@ -38,26 +28,43 @@ class ObservableArray(ListArray, Observable):
|
||||||
"""
|
"""
|
||||||
__array_priority__ = -1 # Never give back ObservableArray
|
__array_priority__ = -1 # Never give back ObservableArray
|
||||||
def __new__(cls, input_array):
|
def __new__(cls, input_array):
|
||||||
|
obj = np.atleast_1d(input_array).view(cls)
|
||||||
cls.__name__ = "ObservableArray\n "
|
cls.__name__ = "ObservableArray\n "
|
||||||
obj = super(ObservableArray, cls).__new__(cls, input_array).view(cls)
|
|
||||||
obj._observers_ = {}
|
obj._observers_ = {}
|
||||||
return obj
|
return obj
|
||||||
def __array_finalize__(self, obj):
|
def __array_finalize__(self, obj):
|
||||||
# see InfoArray.__array_finalize__ for comments
|
# see InfoArray.__array_finalize__ for comments
|
||||||
if obj is None: return
|
if obj is None: return
|
||||||
self._observers_ = getattr(obj, '_observers_', None)
|
self._observers_ = getattr(obj, '_observers_', None)
|
||||||
|
|
||||||
|
def _s_not_empty(self, s):
|
||||||
|
# this checks whether there is something picked by this slice.
|
||||||
|
return True
|
||||||
|
# TODO: disarmed, for performance increase,
|
||||||
|
if not isinstance(s, (list,tuple,np.ndarray)):
|
||||||
|
return True
|
||||||
|
if isinstance(s, (list,tuple)):
|
||||||
|
return len(s)!=0
|
||||||
|
if isinstance(s, np.ndarray):
|
||||||
|
if s.dtype is bool:
|
||||||
|
return np.all(s)
|
||||||
|
else:
|
||||||
|
return s.size != 0
|
||||||
|
|
||||||
def __setitem__(self, s, val, update=True):
|
def __setitem__(self, s, val, update=True):
|
||||||
super(ObservableArray, self).__setitem__(s, val)
|
if self._s_not_empty(s):
|
||||||
if update:
|
super(ObservableArray, self).__setitem__(s, val)
|
||||||
self._notify_observers()
|
if update:
|
||||||
|
self._notify_observers()
|
||||||
|
|
||||||
def __getslice__(self, start, stop):
|
def __getslice__(self, start, stop):
|
||||||
return self.__getitem__(slice(start, stop))
|
return self.__getitem__(slice(start, stop))
|
||||||
def __setslice__(self, start, stop, val):
|
def __setslice__(self, start, stop, val):
|
||||||
return self.__setitem__(slice(start, stop), val)
|
return self.__setitem__(slice(start, stop), val)
|
||||||
|
|
||||||
def __copy__(self, *args):
|
def __copy__(self, *args):
|
||||||
return ObservableArray(self.base.base.copy(*args))
|
return ObservableArray(self.view(np.ndarray).copy())
|
||||||
|
|
||||||
def copy(self, *args):
|
def copy(self, *args):
|
||||||
return self.__copy__(*args)
|
return self.__copy__(*args)
|
||||||
|
|
||||||
|
|
@ -65,32 +72,27 @@ class ObservableArray(ListArray, Observable):
|
||||||
r = np.ndarray.__ror__(self, *args, **kwargs)
|
r = np.ndarray.__ror__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def __ilshift__(self, *args, **kwargs):
|
def __ilshift__(self, *args, **kwargs):
|
||||||
r = np.ndarray.__ilshift__(self, *args, **kwargs)
|
r = np.ndarray.__ilshift__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def __irshift__(self, *args, **kwargs):
|
def __irshift__(self, *args, **kwargs):
|
||||||
r = np.ndarray.__irshift__(self, *args, **kwargs)
|
r = np.ndarray.__irshift__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def __rrshift__(self, *args, **kwargs):
|
def __rrshift__(self, *args, **kwargs):
|
||||||
r = np.ndarray.__rrshift__(self, *args, **kwargs)
|
r = np.ndarray.__rrshift__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def __ixor__(self, *args, **kwargs):
|
def __ixor__(self, *args, **kwargs):
|
||||||
r = np.ndarray.__ixor__(self, *args, **kwargs)
|
r = np.ndarray.__ixor__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
|
||||||
def __rxor__(self, *args, **kwargs):
|
def __rxor__(self, *args, **kwargs):
|
||||||
r = np.ndarray.__rxor__(self, *args, **kwargs)
|
r = np.ndarray.__rxor__(self, *args, **kwargs)
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,12 @@ class ParameterIndexOperations(object):
|
||||||
You can give an offset to set an offset for the given indices in the
|
You can give an offset to set an offset for the given indices in the
|
||||||
index array, for multi-param handling.
|
index array, for multi-param handling.
|
||||||
'''
|
'''
|
||||||
def __init__(self):
|
_offset = 0
|
||||||
self._properties = ParamDict()
|
def __init__(self, constraints=None):
|
||||||
#self._reverse = collections.defaultdict(list)
|
self._properties = IntArrayDict()
|
||||||
|
if constraints is not None:
|
||||||
|
for t, i in constraints.iteritems():
|
||||||
|
self.add(t, i)
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
return self._properties#, self._reverse
|
return self._properties#, self._reverse
|
||||||
|
|
@ -71,16 +74,19 @@ class ParameterIndexOperations(object):
|
||||||
def iteritems(self):
|
def iteritems(self):
|
||||||
return self._properties.iteritems()
|
return self._properties.iteritems()
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return self._properties.items()
|
||||||
|
|
||||||
def properties(self):
|
def properties(self):
|
||||||
return self._properties.keys()
|
return self._properties.keys()
|
||||||
|
|
||||||
def iter_properties(self):
|
def iterproperties(self):
|
||||||
return self._properties.iterkeys()
|
return self._properties.iterkeys()
|
||||||
|
|
||||||
def shift(self, start, size):
|
def shift(self, start, size):
|
||||||
for ind in self.iterindices():
|
for ind in self.iterindices():
|
||||||
toshift = ind>=start
|
toshift = ind>=start
|
||||||
if len(toshift) > 0:
|
if toshift.size > 0:
|
||||||
ind[toshift] += size
|
ind[toshift] += size
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
|
@ -96,12 +102,12 @@ class ParameterIndexOperations(object):
|
||||||
return self._properties.values()
|
return self._properties.values()
|
||||||
|
|
||||||
def properties_for(self, index):
|
def properties_for(self, index):
|
||||||
return vectorize(lambda i: [prop for prop in self.iter_properties() if i in self._properties[prop]], otypes=[list])(index)
|
return vectorize(lambda i: [prop for prop in self.iterproperties() if i in self[prop]], otypes=[list])(index)
|
||||||
|
|
||||||
def add(self, prop, indices):
|
def add(self, prop, indices):
|
||||||
try:
|
try:
|
||||||
self._properties[prop] = combine_indices(self._properties[prop], indices)
|
self._properties[prop] = combine_indices(self._properties[prop], indices)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self._properties[prop] = indices
|
self._properties[prop] = indices
|
||||||
|
|
||||||
def remove(self, prop, indices):
|
def remove(self, prop, indices):
|
||||||
|
|
@ -114,8 +120,21 @@ class ParameterIndexOperations(object):
|
||||||
del self._properties[prop]
|
del self._properties[prop]
|
||||||
return removed.astype(int)
|
return removed.astype(int)
|
||||||
return numpy.array([]).astype(int)
|
return numpy.array([]).astype(int)
|
||||||
|
|
||||||
|
def update(self, parameter_index_view, offset=0):
|
||||||
|
for i, v in parameter_index_view.iteritems():
|
||||||
|
self.add(i, v+offset)
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return ParameterIndexOperations(dict(self.iteritems()))
|
||||||
|
|
||||||
def __getitem__(self, prop):
|
def __getitem__(self, prop):
|
||||||
return self._properties[prop]
|
return self._properties[prop]
|
||||||
|
|
||||||
|
def __str__(self, *args, **kwargs):
|
||||||
|
import pprint
|
||||||
|
return pprint.pformat(dict(self._properties))
|
||||||
|
|
||||||
def combine_indices(arr1, arr2):
|
def combine_indices(arr1, arr2):
|
||||||
return numpy.union1d(arr1, arr2)
|
return numpy.union1d(arr1, arr2)
|
||||||
|
|
@ -126,5 +145,97 @@ def remove_indices(arr, to_remove):
|
||||||
def index_empty(index):
|
def index_empty(index):
|
||||||
return numpy.size(index) == 0
|
return numpy.size(index) == 0
|
||||||
|
|
||||||
|
class ParameterIndexOperationsView(object):
|
||||||
|
def __init__(self, param_index_operations, offset, size):
|
||||||
|
self._param_index_ops = param_index_operations
|
||||||
|
self._offset = offset
|
||||||
|
self._size = size
|
||||||
|
|
||||||
|
def __getstate__(self):
|
||||||
|
return [self._param_index_ops, self._offset, self._size]
|
||||||
|
|
||||||
|
|
||||||
|
def __setstate__(self, state):
|
||||||
|
self._param_index_ops = state[0]
|
||||||
|
self._offset = state[1]
|
||||||
|
self._size = state[2]
|
||||||
|
|
||||||
|
|
||||||
|
def _filter_index(self, ind):
|
||||||
|
return ind[(ind >= self._offset) * (ind < (self._offset + self._size))] - self._offset
|
||||||
|
|
||||||
|
|
||||||
|
def iteritems(self):
|
||||||
|
for i, ind in self._param_index_ops.iteritems():
|
||||||
|
ind2 = self._filter_index(ind)
|
||||||
|
if ind2.size > 0:
|
||||||
|
yield i, ind2
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return [[i,v] for i,v in self.iteritems()]
|
||||||
|
|
||||||
|
def properties(self):
|
||||||
|
return [i for i in self.iterproperties()]
|
||||||
|
|
||||||
|
|
||||||
|
def iterproperties(self):
|
||||||
|
for i, _ in self.iteritems():
|
||||||
|
yield i
|
||||||
|
|
||||||
|
|
||||||
|
def shift(self, start, size):
|
||||||
|
raise NotImplementedError, 'Shifting only supported in original ParamIndexOperations'
|
||||||
|
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
for i, ind in self.items():
|
||||||
|
self._param_index_ops.remove(i, ind+self._offset)
|
||||||
|
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
return reduce(lambda a,b: a+b.size, self.iterindices(), 0)
|
||||||
|
|
||||||
|
|
||||||
|
def iterindices(self):
|
||||||
|
for _, ind in self.iteritems():
|
||||||
|
yield ind
|
||||||
|
|
||||||
|
|
||||||
|
def indices(self):
|
||||||
|
return [ind for ind in self.iterindices()]
|
||||||
|
|
||||||
|
|
||||||
|
def properties_for(self, index):
|
||||||
|
return vectorize(lambda i: [prop for prop in self.iterproperties() if i in self[prop]], otypes=[list])(index)
|
||||||
|
|
||||||
|
|
||||||
|
def add(self, prop, indices):
|
||||||
|
self._param_index_ops.add(prop, indices+self._offset)
|
||||||
|
|
||||||
|
|
||||||
|
def remove(self, prop, indices):
|
||||||
|
removed = self._param_index_ops.remove(prop, indices+self._offset)
|
||||||
|
if removed.size > 0:
|
||||||
|
return removed - self._size + 1
|
||||||
|
return removed
|
||||||
|
|
||||||
|
|
||||||
|
def __getitem__(self, prop):
|
||||||
|
ind = self._filter_index(self._param_index_ops[prop])
|
||||||
|
if ind.size > 0:
|
||||||
|
return ind
|
||||||
|
raise KeyError, prop
|
||||||
|
|
||||||
|
def __str__(self, *args, **kwargs):
|
||||||
|
import pprint
|
||||||
|
return pprint.pformat(dict(self.iteritems()))
|
||||||
|
|
||||||
|
def update(self, parameter_index_view, offset=0):
|
||||||
|
for i, v in parameter_index_view.iteritems():
|
||||||
|
self.add(i, v+offset)
|
||||||
|
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return ParameterIndexOperations(dict(self.iteritems()))
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,19 @@
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import numpy
|
import numpy
|
||||||
from parameter_core import Constrainable, Gradcheckable, adjust_name_for_printing
|
from parameter_core import Constrainable, Gradcheckable, Indexable, Parameterizable, adjust_name_for_printing
|
||||||
from array_core import ObservableArray, ParamList
|
from array_core import ObservableArray, ParamList
|
||||||
|
|
||||||
###### printing
|
###### printing
|
||||||
__constraints_name__ = "Constraint"
|
__constraints_name__ = "Constraint"
|
||||||
__index_name__ = "Index"
|
__index_name__ = "Index"
|
||||||
__tie_name__ = "Tied to"
|
__tie_name__ = "Tied to"
|
||||||
|
__priors_name__ = "Prior"
|
||||||
__precision__ = numpy.get_printoptions()['precision'] # numpy printing precision used, sublassing numpy ndarray after all
|
__precision__ = numpy.get_printoptions()['precision'] # numpy printing precision used, sublassing numpy ndarray after all
|
||||||
__print_threshold__ = 5
|
__print_threshold__ = 5
|
||||||
######
|
######
|
||||||
|
|
||||||
class Float(numpy.float64, Constrainable):
|
class Param(ObservableArray, Constrainable, Gradcheckable, Indexable, Parameterizable):
|
||||||
def __init__(self, f, base):
|
|
||||||
super(Float,self).__init__(f)
|
|
||||||
self._base = base
|
|
||||||
|
|
||||||
|
|
||||||
class Param(ObservableArray, Constrainable, Gradcheckable):
|
|
||||||
"""
|
"""
|
||||||
Parameter object for GPy models.
|
Parameter object for GPy models.
|
||||||
|
|
||||||
|
|
@ -46,8 +41,10 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
"""
|
"""
|
||||||
__array_priority__ = -1 # Never give back Param
|
__array_priority__ = -1 # Never give back Param
|
||||||
_fixes_ = None
|
_fixes_ = None
|
||||||
|
_parameters_ = []
|
||||||
def __new__(cls, name, input_array, default_constraint=None):
|
def __new__(cls, name, input_array, default_constraint=None):
|
||||||
obj = numpy.atleast_1d(super(Param, cls).__new__(cls, input_array=input_array))
|
obj = numpy.atleast_1d(super(Param, cls).__new__(cls, input_array=input_array))
|
||||||
|
cls.__name__ = "Param"
|
||||||
obj._current_slice_ = (slice(obj.shape[0]),)
|
obj._current_slice_ = (slice(obj.shape[0]),)
|
||||||
obj._realshape_ = obj.shape
|
obj._realshape_ = obj.shape
|
||||||
obj._realsize_ = obj.size
|
obj._realsize_ = obj.size
|
||||||
|
|
@ -62,7 +59,7 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
|
|
||||||
def __init__(self, name, input_array, default_constraint=None):
|
def __init__(self, name, input_array, default_constraint=None):
|
||||||
super(Param, self).__init__(name=name, default_constraint=default_constraint)
|
super(Param, self).__init__(name=name, default_constraint=default_constraint)
|
||||||
|
|
||||||
def __array_finalize__(self, obj):
|
def __array_finalize__(self, obj):
|
||||||
# see InfoArray.__array_finalize__ for comments
|
# see InfoArray.__array_finalize__ for comments
|
||||||
if obj is None: return
|
if obj is None: return
|
||||||
|
|
@ -80,9 +77,11 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
self._original_ = getattr(obj, '_original_', None)
|
self._original_ = getattr(obj, '_original_', None)
|
||||||
self._name = getattr(obj, 'name', None)
|
self._name = getattr(obj, 'name', None)
|
||||||
self.gradient = getattr(obj, 'gradient', None)
|
self.gradient = getattr(obj, 'gradient', None)
|
||||||
|
self.constraints = getattr(obj, 'constraints', None)
|
||||||
|
self.priors = getattr(obj, 'priors', None)
|
||||||
|
|
||||||
def __array_wrap__(self, out_arr, context=None):
|
#def __array_wrap__(self, out_arr, context=None):
|
||||||
return out_arr.view(numpy.ndarray)
|
# return out_arr.view(numpy.ndarray)
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Pickling operations
|
# Pickling operations
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -121,157 +120,17 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# get/set parameters
|
# get/set parameters
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
||||||
def _set_params(self, param, update=True):
|
def _set_params(self, param, update=True):
|
||||||
self.flat = param
|
self.flat = param
|
||||||
self._notify_tied_parameters()
|
#self._notify_tied_parameters()
|
||||||
self._notify_observers()
|
self._notify_observers()
|
||||||
|
|
||||||
def _get_params(self):
|
def _get_params(self):
|
||||||
return self.flat
|
return self.flat
|
||||||
# @property
|
|
||||||
# def name(self):
|
|
||||||
# """
|
|
||||||
# Name of this parameter.
|
|
||||||
# This can be a callable without parameters. The callable will be called
|
|
||||||
# every time the name property is accessed.
|
|
||||||
# """
|
|
||||||
# if callable(self.name):
|
|
||||||
# return self.name()
|
|
||||||
# return self.name
|
|
||||||
# @name.setter
|
|
||||||
# def name(self, new_name):
|
|
||||||
# from_name = self.name
|
|
||||||
# self.name = new_name
|
|
||||||
# self._direct_parent_._name_changed(self, from_name)
|
|
||||||
@property
|
|
||||||
def _parameters_(self):
|
|
||||||
return []
|
|
||||||
def _collect_gradient(self, target):
|
def _collect_gradient(self, target):
|
||||||
target[:] = self.gradient.flat
|
target[:] = self.gradient.flat
|
||||||
#===========================================================================
|
|
||||||
# Tying operations -> bugged, TODO
|
|
||||||
#===========================================================================
|
|
||||||
def tie_to(self, param):
|
|
||||||
"""
|
|
||||||
:param param: the parameter object to tie this parameter to.
|
|
||||||
Can be ParamConcatenation (retrieved by regexp search)
|
|
||||||
|
|
||||||
Tie this parameter to the given parameter.
|
|
||||||
Broadcasting is not allowed, but you can tie a whole dimension to
|
|
||||||
one parameter: self[:,0].tie_to(other), where other is a one-value
|
|
||||||
parameter.
|
|
||||||
|
|
||||||
Note: For now only one parameter can have ties, so all of a parameter
|
|
||||||
will be removed, when re-tieing!
|
|
||||||
"""
|
|
||||||
#Note: this method will tie to the parameter which is the last in
|
|
||||||
# the chain of ties. Thus, if you tie to a tied parameter,
|
|
||||||
# this tie will be created to the parameter the param is tied
|
|
||||||
# to.
|
|
||||||
|
|
||||||
assert isinstance(param, Param), "Argument {1} not of type {0}".format(Param, param.__class__)
|
|
||||||
param = numpy.atleast_1d(param)
|
|
||||||
if param.size != 1:
|
|
||||||
raise NotImplementedError, "Broadcast tying is not implemented yet"
|
|
||||||
try:
|
|
||||||
if self._original_:
|
|
||||||
self[:] = param
|
|
||||||
else: # this happens when indexing created a copy of the array
|
|
||||||
self._direct_parent_._get_original(self)[self._current_slice_] = param
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError("Trying to tie {} with shape {} to {} with shape {}".format(self.name, self.shape, param.name, param.shape))
|
|
||||||
if param is self:
|
|
||||||
raise RuntimeError, 'Cyclic tieing is not allowed'
|
|
||||||
# if len(param._tied_to_) > 0:
|
|
||||||
# if (self._direct_parent_._get_original(self) is param._direct_parent_._get_original(param)
|
|
||||||
# and len(set(self._raveled_index())&set(param._tied_to_[0]._raveled_index()))!=0):
|
|
||||||
# raise RuntimeError, 'Cyclic tieing is not allowed'
|
|
||||||
# self.tie_to(param._tied_to_[0])
|
|
||||||
# return
|
|
||||||
if not param in self._direct_parent_._get_original(self)._tied_to_:
|
|
||||||
self._direct_parent_._get_original(self)._tied_to_ += [param]
|
|
||||||
param._add_tie_listener(self)
|
|
||||||
self._highest_parent_._set_fixed(self)
|
|
||||||
cs = self._highest_parent_._constraints_for(param, param._raveled_index())
|
|
||||||
for cs in self._highest_parent_._constraints_for(param, param._raveled_index()):
|
|
||||||
[self.constrain(c, warning=False) for c in cs]
|
|
||||||
# for t in self._tied_to_me_.keys():
|
|
||||||
# if t is not self:
|
|
||||||
# t.untie(self)
|
|
||||||
# t.tie_to(param)
|
|
||||||
|
|
||||||
def untie(self, *ties):
|
|
||||||
"""
|
|
||||||
remove all ties.
|
|
||||||
"""
|
|
||||||
[t._direct_parent_._get_original(t)._remove_tie_listener(self) for t in self._tied_to_]
|
|
||||||
new_ties = []
|
|
||||||
for t in self._direct_parent_._get_original(self)._tied_to_:
|
|
||||||
for tied in t._tied_to_me_.keys():
|
|
||||||
if t._parent_index_ is tied._parent_index_:
|
|
||||||
new_ties.append(tied)
|
|
||||||
self._direct_parent_._get_original(self)._tied_to_ = new_ties
|
|
||||||
self._direct_parent_._get_original(self)._highest_parent_._set_unfixed(self)
|
|
||||||
# self._direct_parent_._remove_tie(self, *params)
|
|
||||||
def _notify_tied_parameters(self):
|
|
||||||
for tied, ind in self._tied_to_me_.iteritems():
|
|
||||||
tied._on_tied_parameter_changed(self.base, list(ind))
|
|
||||||
def _add_tie_listener(self, tied_to_me):
|
|
||||||
for t in self._tied_to_me_.keys():
|
|
||||||
if tied_to_me._parent_index_ is t._parent_index_:
|
|
||||||
t_rav_i = t._raveled_index()
|
|
||||||
tr_rav_i = tied_to_me._raveled_index()
|
|
||||||
new_index = list(set(t_rav_i) | set(tr_rav_i))
|
|
||||||
tmp = t._direct_parent_._get_original(t)[numpy.unravel_index(new_index, t._realshape_)]
|
|
||||||
self._tied_to_me_[tmp] = self._tied_to_me_[t] | set(self._raveled_index())
|
|
||||||
del self._tied_to_me_[t]
|
|
||||||
return
|
|
||||||
self._tied_to_me_[tied_to_me] = set(self._raveled_index())
|
|
||||||
def _remove_tie_listener(self, to_remove):
|
|
||||||
for t in self._tied_to_me_.keys():
|
|
||||||
if t._parent_index_ == to_remove._parent_index_:
|
|
||||||
t_rav_i = t._raveled_index()
|
|
||||||
tr_rav_i = to_remove._raveled_index()
|
|
||||||
import ipdb;ipdb.set_trace()
|
|
||||||
new_index = list(set(t_rav_i) - set(tr_rav_i))
|
|
||||||
if new_index:
|
|
||||||
tmp = t._direct_parent_._get_original(t)[numpy.unravel_index(new_index, t._realshape_)]
|
|
||||||
self._tied_to_me_[tmp] = self._tied_to_me_[t]
|
|
||||||
del self._tied_to_me_[t]
|
|
||||||
if len(self._tied_to_me_[tmp]) == 0:
|
|
||||||
del self._tied_to_me_[tmp]
|
|
||||||
else:
|
|
||||||
del self._tied_to_me_[t]
|
|
||||||
def _on_tied_parameter_changed(self, val, ind):
|
|
||||||
if not self._updated_: # not fast_array_equal(self, val[ind]):
|
|
||||||
val = numpy.atleast_1d(val)
|
|
||||||
self._updated_ = True
|
|
||||||
if self._original_:
|
|
||||||
self.__setitem__(slice(None), val[ind], update=False)
|
|
||||||
else: # this happens when indexing created a copy of the array
|
|
||||||
self._direct_parent_._get_original(self).__setitem__(self._current_slice_, val[ind], update=False)
|
|
||||||
self._notify_tied_parameters()
|
|
||||||
self._updated_ = False
|
|
||||||
#===========================================================================
|
|
||||||
# Prior Operations
|
|
||||||
#===========================================================================
|
|
||||||
def set_prior(self, prior):
|
|
||||||
"""
|
|
||||||
:param prior: prior to be set for this parameter
|
|
||||||
|
|
||||||
Set prior for this parameter.
|
|
||||||
"""
|
|
||||||
if not hasattr(self._highest_parent_, '_set_prior'):
|
|
||||||
raise AttributeError("Parent of type {} does not support priors".format(self._highest_parent_.__class__))
|
|
||||||
self._highest_parent_._set_prior(self, prior)
|
|
||||||
def unset_prior(self, *priors):
|
|
||||||
"""
|
|
||||||
:param priors: priors to remove from this parameter
|
|
||||||
|
|
||||||
Remove all priors from this parameter
|
|
||||||
"""
|
|
||||||
self._highest_parent_._remove_prior(self, *priors)
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Array operations -> done
|
# Array operations -> done
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -286,9 +145,10 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
return new_arr
|
return new_arr
|
||||||
def __setitem__(self, s, val, update=True):
|
def __setitem__(self, s, val, update=True):
|
||||||
super(Param, self).__setitem__(s, val, update=update)
|
super(Param, self).__setitem__(s, val, update=update)
|
||||||
self._notify_tied_parameters()
|
#self._notify_tied_parameters()
|
||||||
if update:
|
if update and self._s_not_empty(s):
|
||||||
self._highest_parent_.parameters_changed()
|
self._notify_parameters_changed()
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Index Operations:
|
# Index Operations:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -334,21 +194,21 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
return numpy.r_[a]
|
return numpy.r_[a]
|
||||||
return numpy.r_[:b]
|
return numpy.r_[:b]
|
||||||
return itertools.imap(f, itertools.izip_longest(slice_index[:self._realndim_], self._realshape_, fillvalue=slice(self.size)))
|
return itertools.imap(f, itertools.izip_longest(slice_index[:self._realndim_], self._realshape_, fillvalue=slice(self.size)))
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Convienience
|
# Convenience
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
@property
|
@property
|
||||||
def is_fixed(self):
|
def is_fixed(self):
|
||||||
return self._highest_parent_._is_fixed(self)
|
return self._highest_parent_._is_fixed(self)
|
||||||
def round(self, decimals=0, out=None):
|
#def round(self, decimals=0, out=None):
|
||||||
view = super(Param, self).round(decimals, out).view(Param)
|
# view = super(Param, self).round(decimals, out).view(Param)
|
||||||
view.__array_finalize__(self)
|
# view.__array_finalize__(self)
|
||||||
return view
|
# return view
|
||||||
def _has_fixes(self):
|
#round.__doc__ = numpy.round.__doc__
|
||||||
return False
|
|
||||||
round.__doc__ = numpy.round.__doc__
|
|
||||||
def _get_original(self, param):
|
def _get_original(self, param):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Printing -> done
|
# Printing -> done
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -356,7 +216,7 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
def _description_str(self):
|
def _description_str(self):
|
||||||
if self.size <= 1: return ["%f" % self]
|
if self.size <= 1: return ["%f" % self]
|
||||||
else: return [str(self.shape)]
|
else: return [str(self.shape)]
|
||||||
def _parameter_names(self, add_name):
|
def parameter_names(self, add_name=False):
|
||||||
return [self.name]
|
return [self.name]
|
||||||
@property
|
@property
|
||||||
def flattened_parameters(self):
|
def flattened_parameters(self):
|
||||||
|
|
@ -366,7 +226,10 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
return [self.shape]
|
return [self.shape]
|
||||||
@property
|
@property
|
||||||
def _constraints_str(self):
|
def _constraints_str(self):
|
||||||
return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self._highest_parent_._constraints_iter_items(self)))]
|
return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self.constraints.iteritems()))]
|
||||||
|
@property
|
||||||
|
def _priors_str(self):
|
||||||
|
return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self.priors.iteritems()))]
|
||||||
@property
|
@property
|
||||||
def _ties_str(self):
|
def _ties_str(self):
|
||||||
return [t._short() for t in self._tied_to_] or ['']
|
return [t._short() for t in self._tied_to_] or ['']
|
||||||
|
|
@ -391,14 +254,15 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
if len(ind) != 1: ties[i, matches[0][ind_rav_matches]] = numpy.take(tt_rav_index, matches[1], mode='wrap')[ind_rav_matches]
|
if len(ind) != 1: ties[i, matches[0][ind_rav_matches]] = numpy.take(tt_rav_index, matches[1], mode='wrap')[ind_rav_matches]
|
||||||
else: ties[i, matches[0]] = numpy.take(tt_rav_index, matches[1], mode='wrap')
|
else: ties[i, matches[0]] = numpy.take(tt_rav_index, matches[1], mode='wrap')
|
||||||
return map(lambda a: sum(a, []), zip(*[[[tie.flatten()] if tx != None else [] for tx in t] for t, tie in zip(ties, self._tied_to_)]))
|
return map(lambda a: sum(a, []), zip(*[[[tie.flatten()] if tx != None else [] for tx in t] for t, tie in zip(ties, self._tied_to_)]))
|
||||||
def _constraints_for(self, rav_index):
|
|
||||||
return self._highest_parent_._constraints_for(self, rav_index)
|
|
||||||
def _indices(self, slice_index=None):
|
def _indices(self, slice_index=None):
|
||||||
# get a int-array containing all indices in the first axis.
|
# get a int-array containing all indices in the first axis.
|
||||||
if slice_index is None:
|
if slice_index is None:
|
||||||
slice_index = self._current_slice_
|
slice_index = self._current_slice_
|
||||||
if isinstance(slice_index, (tuple, list)):
|
if isinstance(slice_index, (tuple, list)):
|
||||||
clean_curr_slice = [s for s in slice_index if numpy.any(s != Ellipsis)]
|
clean_curr_slice = [s for s in slice_index if numpy.any(s != Ellipsis)]
|
||||||
|
for i in range(self._realndim_-len(clean_curr_slice)):
|
||||||
|
i+=len(clean_curr_slice)
|
||||||
|
clean_curr_slice += range(self._realshape_[i])
|
||||||
if (all(isinstance(n, (numpy.ndarray, list, tuple)) for n in clean_curr_slice)
|
if (all(isinstance(n, (numpy.ndarray, list, tuple)) for n in clean_curr_slice)
|
||||||
and len(set(map(len, clean_curr_slice))) <= 1):
|
and len(set(map(len, clean_curr_slice))) <= 1):
|
||||||
return numpy.fromiter(itertools.izip(*clean_curr_slice),
|
return numpy.fromiter(itertools.izip(*clean_curr_slice),
|
||||||
|
|
@ -407,6 +271,7 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
return numpy.fromiter(itertools.product(*expanded_index),
|
return numpy.fromiter(itertools.product(*expanded_index),
|
||||||
dtype=[('', int)] * self._realndim_, count=reduce(lambda a, b: a * b.size, expanded_index, 1)).view((int, self._realndim_))
|
dtype=[('', int)] * self._realndim_, count=reduce(lambda a, b: a * b.size, expanded_index, 1)).view((int, self._realndim_))
|
||||||
def _max_len_names(self, gen, header):
|
def _max_len_names(self, gen, header):
|
||||||
|
gen = map(lambda x: " ".join(map(str, x)), gen)
|
||||||
return reduce(lambda a, b:max(a, len(b)), gen, len(header))
|
return reduce(lambda a, b:max(a, len(b)), gen, len(header))
|
||||||
def _max_len_values(self):
|
def _max_len_values(self):
|
||||||
return reduce(lambda a, b:max(a, len("{x:=.{0}g}".format(__precision__, x=b))), self.flat, len(self.name_hirarchical))
|
return reduce(lambda a, b:max(a, len("{x:=.{0}g}".format(__precision__, x=b))), self.flat, len(self.name_hirarchical))
|
||||||
|
|
@ -421,21 +286,26 @@ class Param(ObservableArray, Constrainable, Gradcheckable):
|
||||||
if ind.size > 4: indstr = ','.join(map(str, ind[:2])) + "..." + ','.join(map(str, ind[-2:]))
|
if ind.size > 4: indstr = ','.join(map(str, ind[:2])) + "..." + ','.join(map(str, ind[-2:]))
|
||||||
else: indstr = ','.join(map(str, ind))
|
else: indstr = ','.join(map(str, ind))
|
||||||
return name + '[' + indstr + ']'
|
return name + '[' + indstr + ']'
|
||||||
def __str__(self, constr_matrix=None, indices=None, ties=None, lc=None, lx=None, li=None, lt=None):
|
def __str__(self, constr_matrix=None, indices=None, prirs=None, ties=None, lc=None, lx=None, li=None, lp=None, lt=None, only_name=False):
|
||||||
filter_ = self._current_slice_
|
filter_ = self._current_slice_
|
||||||
vals = self.flat
|
vals = self.flat
|
||||||
if indices is None: indices = self._indices(filter_)
|
if indices is None: indices = self._indices(filter_)
|
||||||
ravi = self._raveled_index(filter_)
|
ravi = self._raveled_index(filter_)
|
||||||
if constr_matrix is None: constr_matrix = self._constraints_for(ravi)
|
if constr_matrix is None: constr_matrix = self.constraints.properties_for(ravi)
|
||||||
|
if prirs is None: prirs = self.priors.properties_for(ravi)
|
||||||
if ties is None: ties = self._ties_for(ravi)
|
if ties is None: ties = self._ties_for(ravi)
|
||||||
ties = [' '.join(map(lambda x: x._short(), t)) for t in ties]
|
ties = [' '.join(map(lambda x: x._short(), t)) for t in ties]
|
||||||
if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__)
|
if lc is None: lc = self._max_len_names(constr_matrix, __constraints_name__)
|
||||||
if lx is None: lx = self._max_len_values()
|
if lx is None: lx = self._max_len_values()
|
||||||
if li is None: li = self._max_len_index(indices)
|
if li is None: li = self._max_len_index(indices)
|
||||||
if lt is None: lt = self._max_len_names(ties, __tie_name__)
|
if lt is None: lt = self._max_len_names(ties, __tie_name__)
|
||||||
header = " {i:^{2}s} | \033[1m{x:^{1}s}\033[0;0m | {c:^{0}s} | {t:^{3}s}".format(lc, lx, li, lt, x=self.name_hirarchical, c=__constraints_name__, i=__index_name__, t=__tie_name__) # nice header for printing
|
if lp is None: lp = self._max_len_names(prirs, __tie_name__)
|
||||||
|
sep = '-'
|
||||||
|
header_format = " {i:{5}^{2}s} | \033[1m{x:{5}^{1}s}\033[0;0m | {c:{5}^{0}s} | {p:{5}^{4}s} | {t:{5}^{3}s}"
|
||||||
|
if only_name: header = header_format.format(lc, lx, li, lt, lp, ' ', x=self.name_hirarchical, c=sep*lc, i=sep*li, t=sep*lt, p=sep*lp) # nice header for printing
|
||||||
|
else: header = header_format.format(lc, lx, li, lt, lp, ' ', x=self.name_hirarchical, c=__constraints_name__, i=__index_name__, t=__tie_name__, p=__priors_name__) # nice header for printing
|
||||||
if not ties: ties = itertools.cycle([''])
|
if not ties: ties = itertools.cycle([''])
|
||||||
return "\n".join([header] + [" {i!s:^{3}s} | {x: >{1}.{2}g} | {c:^{0}s} | {t:^{4}s} ".format(lc, lx, __precision__, li, lt, x=x, c=" ".join(map(str, c)), t=(t or ''), i=i) for i, x, c, t in itertools.izip(indices, vals, constr_matrix, ties)]) # return all the constraints with right indices
|
return "\n".join([header] + [" {i!s:^{3}s} | {x: >{1}.{2}g} | {c:^{0}s} | {p:^{5}s} | {t:^{4}s} ".format(lc, lx, __precision__, li, lt, lp, x=x, c=" ".join(map(str, c)), p=" ".join(map(str, p)), t=(t or ''), i=i) for i, x, c, t, p in itertools.izip(indices, vals, constr_matrix, ties, prirs)]) # return all the constraints with right indices
|
||||||
# except: return super(Param, self).__str__()
|
# except: return super(Param, self).__str__()
|
||||||
|
|
||||||
class ParamConcatenation(object):
|
class ParamConcatenation(object):
|
||||||
|
|
@ -467,17 +337,17 @@ class ParamConcatenation(object):
|
||||||
def __setitem__(self, s, val, update=True):
|
def __setitem__(self, s, val, update=True):
|
||||||
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
|
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
|
||||||
vals = self._vals(); vals[s] = val; del val
|
vals = self._vals(); vals[s] = val; del val
|
||||||
[numpy.place(p, ind[ps], vals[ps]) and p._notify_tied_parameters()
|
[numpy.place(p, ind[ps], vals[ps])# and p._notify_tied_parameters()
|
||||||
for p, ps in zip(self.params, self._param_slices_)]
|
for p, ps in zip(self.params, self._param_slices_)]
|
||||||
if update:
|
if update:
|
||||||
self.params[0]._highest_parent_.parameters_changed()
|
self.params[0]._notify_parameters_changed()
|
||||||
def _vals(self):
|
def _vals(self):
|
||||||
return numpy.hstack([p._get_params() for p in self.params])
|
return numpy.hstack([p._get_params() for p in self.params])
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# parameter operations:
|
# parameter operations:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def update_all_params(self):
|
def update_all_params(self):
|
||||||
self.params[0]._highest_parent_.parameters_changed()
|
self.params[0]._notify_parameters_changed()
|
||||||
|
|
||||||
def constrain(self, constraint, warning=True):
|
def constrain(self, constraint, warning=True):
|
||||||
[param.constrain(constraint, update=False) for param in self.params]
|
[param.constrain(constraint, update=False) for param in self.params]
|
||||||
|
|
@ -531,7 +401,7 @@ class ParamConcatenation(object):
|
||||||
def checkgrad(self, verbose=0, step=1e-6, tolerance=1e-3):
|
def checkgrad(self, verbose=0, step=1e-6, tolerance=1e-3):
|
||||||
return self.params[0]._highest_parent_._checkgrad(self, verbose, step, tolerance)
|
return self.params[0]._highest_parent_._checkgrad(self, verbose, step, tolerance)
|
||||||
#checkgrad.__doc__ = Gradcheckable.checkgrad.__doc__
|
#checkgrad.__doc__ = Gradcheckable.checkgrad.__doc__
|
||||||
|
|
||||||
__lt__ = lambda self, val: self._vals() < val
|
__lt__ = lambda self, val: self._vals() < val
|
||||||
__le__ = lambda self, val: self._vals() <= val
|
__le__ = lambda self, val: self._vals() <= val
|
||||||
__eq__ = lambda self, val: self._vals() == val
|
__eq__ = lambda self, val: self._vals() == val
|
||||||
|
|
@ -541,53 +411,20 @@ class ParamConcatenation(object):
|
||||||
def __str__(self, *args, **kwargs):
|
def __str__(self, *args, **kwargs):
|
||||||
def f(p):
|
def f(p):
|
||||||
ind = p._raveled_index()
|
ind = p._raveled_index()
|
||||||
return p._constraints_for(ind), p._ties_for(ind)
|
return p.constraints.properties_for(ind), p._ties_for(ind), p.priors.properties_for(ind)
|
||||||
params = self.params
|
params = self.params
|
||||||
constr_matrices, ties_matrices = zip(*map(f, params))
|
constr_matrices, ties_matrices, prior_matrices = zip(*map(f, params))
|
||||||
indices = [p._indices() for p in params]
|
indices = [p._indices() for p in params]
|
||||||
lc = max([p._max_len_names(cm, __constraints_name__) for p, cm in itertools.izip(params, constr_matrices)])
|
lc = max([p._max_len_names(cm, __constraints_name__) for p, cm in itertools.izip(params, constr_matrices)])
|
||||||
lx = max([p._max_len_values() for p in params])
|
lx = max([p._max_len_values() for p in params])
|
||||||
li = max([p._max_len_index(i) for p, i in itertools.izip(params, indices)])
|
li = max([p._max_len_index(i) for p, i in itertools.izip(params, indices)])
|
||||||
lt = max([p._max_len_names(tm, __tie_name__) for p, tm in itertools.izip(params, ties_matrices)])
|
lt = max([p._max_len_names(tm, __tie_name__) for p, tm in itertools.izip(params, ties_matrices)])
|
||||||
strings = [p.__str__(cm, i, tm, lc, lx, li, lt) for p, cm, i, tm in itertools.izip(params,constr_matrices,indices,ties_matrices)]
|
lp = max([p._max_len_names(pm, __constraints_name__) for p, pm in itertools.izip(params, prior_matrices)])
|
||||||
|
strings = []
|
||||||
|
start = True
|
||||||
|
for p, cm, i, tm, pm in itertools.izip(params,constr_matrices,indices,ties_matrices,prior_matrices):
|
||||||
|
strings.append(p.__str__(constr_matrix=cm, indices=i, prirs=pm, ties=tm, lc=lc, lx=lx, li=li, lp=lp, lt=lt, only_name=(1-start)))
|
||||||
|
start = False
|
||||||
return "\n".join(strings)
|
return "\n".join(strings)
|
||||||
return "\n{}\n".format(" -"+"- | -".join(['-'*l for l in [li,lx,lc,lt]])).join(strings)
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "\n".join(map(repr,self.params))
|
return "\n".join(map(repr,self.params))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
|
|
||||||
from GPy.core.parameterized import Parameterized
|
|
||||||
from GPy.core.parameter import Param
|
|
||||||
|
|
||||||
#X = numpy.random.randn(2,3,1,5,2,4,3)
|
|
||||||
X = numpy.random.randn(3,2)
|
|
||||||
print "random done"
|
|
||||||
p = Param("q_mean", X)
|
|
||||||
p1 = Param("q_variance", numpy.random.rand(*p.shape))
|
|
||||||
p2 = Param("Y", numpy.random.randn(p.shape[0], 1))
|
|
||||||
|
|
||||||
p3 = Param("variance", numpy.random.rand())
|
|
||||||
p4 = Param("lengthscale", numpy.random.rand(2))
|
|
||||||
|
|
||||||
m = Parameterized()
|
|
||||||
rbf = Parameterized(name='rbf')
|
|
||||||
|
|
||||||
rbf.add_parameter(p3,p4)
|
|
||||||
m.add_parameter(p,p1,rbf)
|
|
||||||
|
|
||||||
print "setting params"
|
|
||||||
#print m.q_v[3:5,[1,4,5]]
|
|
||||||
print "constraining variance"
|
|
||||||
#m[".*variance"].constrain_positive()
|
|
||||||
#print "constraining rbf"
|
|
||||||
#m.rbf_l.constrain_positive()
|
|
||||||
#m.q_variance[1,[0,5,11,19,2]].tie_to(m.rbf_v)
|
|
||||||
#m.rbf_v.tie_to(m.rbf_l[0])
|
|
||||||
#m.rbf_l[0].tie_to(m.rbf_l[1])
|
|
||||||
#m.q_v.tie_to(m.rbf_v)
|
|
||||||
# m.rbf_l.tie_to(m.rbf_va)
|
|
||||||
# pt = numpy.array(params._get_params_transformed())
|
|
||||||
# ptr = numpy.random.randn(*pt.shape)
|
|
||||||
# params.X.tie_to(params.rbf_v)
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
||||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
|
|
||||||
from transformations import Logexp, NegativeLogexp, Logistic
|
from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||||
|
|
||||||
__updated__ = '2013-12-16'
|
__updated__ = '2013-12-16'
|
||||||
|
|
||||||
|
|
@ -19,8 +19,7 @@ class Observable(object):
|
||||||
del self._observers_[observer]
|
del self._observers_[observer]
|
||||||
def _notify_observers(self):
|
def _notify_observers(self):
|
||||||
[callble(self) for callble in self._observers_.itervalues()]
|
[callble(self) for callble in self._observers_.itervalues()]
|
||||||
|
|
||||||
|
|
||||||
class Pickleable(object):
|
class Pickleable(object):
|
||||||
def _getstate(self):
|
def _getstate(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -52,10 +51,17 @@ class Parentable(object):
|
||||||
super(Parentable,self).__init__()
|
super(Parentable,self).__init__()
|
||||||
self._direct_parent_ = direct_parent
|
self._direct_parent_ = direct_parent
|
||||||
self._parent_index_ = parent_index
|
self._parent_index_ = parent_index
|
||||||
|
|
||||||
def has_parent(self):
|
def has_parent(self):
|
||||||
return self._direct_parent_ is not None
|
return self._direct_parent_ is not None
|
||||||
|
|
||||||
|
def _notify_parent_change(self):
|
||||||
|
for p in self._parameters_:
|
||||||
|
p._parent_changed(self)
|
||||||
|
|
||||||
|
def _parent_changed(self):
|
||||||
|
raise NotImplementedError, "shouldnt happen, Parentable objects need to be able to change their parent"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _highest_parent_(self):
|
def _highest_parent_(self):
|
||||||
if self._direct_parent_ is None:
|
if self._direct_parent_ is None:
|
||||||
|
|
@ -78,6 +84,50 @@ class Nameable(Parentable):
|
||||||
if self.has_parent():
|
if self.has_parent():
|
||||||
self._direct_parent_._name_changed(self, from_name)
|
self._direct_parent_._name_changed(self, from_name)
|
||||||
|
|
||||||
|
|
||||||
|
class Parameterizable(Parentable):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Parameterizable, self).__init__(*args, **kwargs)
|
||||||
|
from GPy.core.parameterization.array_core import ParamList
|
||||||
|
_parameters_ = ParamList()
|
||||||
|
|
||||||
|
def parameter_names(self, add_name=False):
|
||||||
|
if add_name:
|
||||||
|
return [adjust_name_for_printing(self.name) + "." + xi for x in self._parameters_ for xi in x.parameter_names(add_name=True)]
|
||||||
|
return [xi for x in self._parameters_ for xi in x.parameter_names(add_name=True)]
|
||||||
|
|
||||||
|
def _collect_gradient(self, target):
|
||||||
|
import itertools
|
||||||
|
[p._collect_gradient(target[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
||||||
|
|
||||||
|
def _get_params(self):
|
||||||
|
import numpy as np
|
||||||
|
# don't overwrite this anymore!
|
||||||
|
if not self.size:
|
||||||
|
return np.empty(shape=(0,), dtype=np.float64)
|
||||||
|
return np.hstack([x._get_params() for x in self._parameters_ if x.size > 0])
|
||||||
|
|
||||||
|
def _set_params(self, params, update=True):
|
||||||
|
# don't overwrite this anymore!
|
||||||
|
import itertools
|
||||||
|
[p._set_params(params[s], update=update) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
||||||
|
self.parameters_changed()
|
||||||
|
|
||||||
|
def parameters_changed(self):
|
||||||
|
"""
|
||||||
|
This method gets called when parameters have changed.
|
||||||
|
Another way of listening to param changes is to
|
||||||
|
add self as a listener to the param, such that
|
||||||
|
updates get passed through. See :py:function:``GPy.core.param.Observable.add_observer``
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _notify_parameters_changed(self):
|
||||||
|
self.parameters_changed()
|
||||||
|
if self.has_parent():
|
||||||
|
self._direct_parent_._notify_parameters_changed()
|
||||||
|
|
||||||
|
|
||||||
class Gradcheckable(Parentable):
|
class Gradcheckable(Parentable):
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Gradchecking
|
# Gradchecking
|
||||||
|
|
@ -89,11 +139,34 @@ class Gradcheckable(Parentable):
|
||||||
def _checkgrad(self, param):
|
def _checkgrad(self, param):
|
||||||
raise NotImplementedError, "Need log likelihood to check gradient against"
|
raise NotImplementedError, "Need log likelihood to check gradient against"
|
||||||
|
|
||||||
|
class Indexable(object):
|
||||||
class Constrainable(Nameable):
|
def _raveled_index(self):
|
||||||
|
raise NotImplementedError, "Need to be able to get the raveled Index"
|
||||||
|
|
||||||
|
def _internal_offset(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _offset_for(self, param):
|
||||||
|
raise NotImplementedError, "shouldnt happen, offset required from non parameterization object?"
|
||||||
|
|
||||||
|
def _raveled_index_for(self, param):
|
||||||
|
"""
|
||||||
|
get the raveled index for a param
|
||||||
|
that is an int array, containing the indexes for the flattened
|
||||||
|
param inside this parameterized logic.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError, "shouldnt happen, raveld index transformation required from non parameterization object?"
|
||||||
|
|
||||||
|
class Constrainable(Nameable, Indexable, Parameterizable):
|
||||||
def __init__(self, name, default_constraint=None):
|
def __init__(self, name, default_constraint=None):
|
||||||
super(Constrainable,self).__init__(name)
|
super(Constrainable,self).__init__(name)
|
||||||
self._default_constraint_ = default_constraint
|
self._default_constraint_ = default_constraint
|
||||||
|
from index_operations import ParameterIndexOperations
|
||||||
|
self.constraints = ParameterIndexOperations()
|
||||||
|
self.priors = ParameterIndexOperations()
|
||||||
|
if self._default_constraint_ is not None:
|
||||||
|
self.constrain(self._default_constraint_)
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Fixing Parameters:
|
# Fixing Parameters:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -105,17 +178,75 @@ class Constrainable(Nameable):
|
||||||
"""
|
"""
|
||||||
if value is not None:
|
if value is not None:
|
||||||
self[:] = value
|
self[:] = value
|
||||||
self._highest_parent_._fix(self,warning)
|
self.constrain(__fixed__, warning=warning)
|
||||||
|
rav_i = self._highest_parent_._raveled_index_for(self)
|
||||||
|
self._highest_parent_._set_fixed(rav_i)
|
||||||
fix = constrain_fixed
|
fix = constrain_fixed
|
||||||
|
|
||||||
def unconstrain_fixed(self):
|
def unconstrain_fixed(self):
|
||||||
"""
|
"""
|
||||||
This parameter will no longer be fixed.
|
This parameter will no longer be fixed.
|
||||||
"""
|
"""
|
||||||
self._highest_parent_._unfix(self)
|
unconstrained = self.unconstrain(__fixed__)
|
||||||
|
self._highest_parent_._set_unfixed(unconstrained)
|
||||||
unfix = unconstrain_fixed
|
unfix = unconstrain_fixed
|
||||||
|
|
||||||
|
def _set_fixed(self, index):
|
||||||
|
import numpy as np
|
||||||
|
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool)
|
||||||
|
self._fixes_[index] = FIXED
|
||||||
|
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
|
||||||
|
|
||||||
|
def _set_unfixed(self, index):
|
||||||
|
import numpy as np
|
||||||
|
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool)
|
||||||
|
#rav_i = self._raveled_index_for(param)[index]
|
||||||
|
self._fixes_[index] = UNFIXED
|
||||||
|
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
|
||||||
|
|
||||||
|
def _connect_fixes(self):
|
||||||
|
import numpy as np
|
||||||
|
fixed_indices = self.constraints[__fixed__]
|
||||||
|
if fixed_indices.size > 0:
|
||||||
|
self._fixes_ = np.ones(self.size, dtype=bool) * UNFIXED
|
||||||
|
self._fixes_[fixed_indices] = FIXED
|
||||||
|
else:
|
||||||
|
self._fixes_ = None
|
||||||
|
|
||||||
|
def _has_fixes(self):
|
||||||
|
return hasattr(self, "_fixes_") and self._fixes_ is not None
|
||||||
|
|
||||||
|
#===========================================================================
|
||||||
|
# Prior Operations
|
||||||
|
#===========================================================================
|
||||||
|
def set_prior(self, prior, warning=True, update=True):
|
||||||
|
repriorized = self.unset_priors()
|
||||||
|
self._add_to_index_operations(self.priors, repriorized, prior, warning, update)
|
||||||
|
|
||||||
|
def unset_priors(self, *priors):
|
||||||
|
return self._remove_from_index_operations(self.priors, priors)
|
||||||
|
|
||||||
|
def log_prior(self):
|
||||||
|
"""evaluate the prior"""
|
||||||
|
if self.priors.size > 0:
|
||||||
|
x = self._get_params()
|
||||||
|
return reduce(lambda a,b: a+b, [p.lnpdf(x[ind]).sum() for p, ind in self.priors.iteritems()], 0)
|
||||||
|
return 0.
|
||||||
|
|
||||||
|
def _log_prior_gradients(self):
|
||||||
|
"""evaluate the gradients of the priors"""
|
||||||
|
import numpy as np
|
||||||
|
if self.priors.size > 0:
|
||||||
|
x = self._get_params()
|
||||||
|
ret = np.zeros(x.size)
|
||||||
|
[np.put(ret, ind, p.lnpdf_grad(x[ind])) for p, ind in self.priors.iteritems()]
|
||||||
|
return ret
|
||||||
|
return 0.
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Constrain operations -> done
|
# Constrain operations -> done
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
||||||
def constrain(self, transform, warning=True, update=True):
|
def constrain(self, transform, warning=True, update=True):
|
||||||
"""
|
"""
|
||||||
:param transform: the :py:class:`GPy.core.transformations.Transformation`
|
:param transform: the :py:class:`GPy.core.transformations.Transformation`
|
||||||
|
|
@ -125,16 +256,20 @@ class Constrainable(Nameable):
|
||||||
Constrain the parameter to the given
|
Constrain the parameter to the given
|
||||||
:py:class:`GPy.core.transformations.Transformation`.
|
:py:class:`GPy.core.transformations.Transformation`.
|
||||||
"""
|
"""
|
||||||
if self.has_parent():
|
if isinstance(transform, Transformation):
|
||||||
self._highest_parent_._add_constrain(self, transform, warning)
|
self._set_params(transform.initialize(self._get_params()), update=False)
|
||||||
if update:
|
reconstrained = self.unconstrain()
|
||||||
self._highest_parent_.parameters_changed()
|
self._add_to_index_operations(self.constraints, reconstrained, transform, warning, update)
|
||||||
else:
|
|
||||||
for p in self._parameters_:
|
|
||||||
self._add_constrain(p, transform, warning)
|
|
||||||
if update:
|
|
||||||
self.parameters_changed()
|
|
||||||
|
|
||||||
|
def unconstrain(self, *transforms):
|
||||||
|
"""
|
||||||
|
:param transforms: The transformations to unconstrain from.
|
||||||
|
|
||||||
|
remove all :py:class:`GPy.core.transformations.Transformation`
|
||||||
|
transformats of this parameter object.
|
||||||
|
"""
|
||||||
|
return self._remove_from_index_operations(self.constraints, transforms)
|
||||||
|
|
||||||
def constrain_positive(self, warning=True, update=True):
|
def constrain_positive(self, warning=True, update=True):
|
||||||
"""
|
"""
|
||||||
:param warning: print a warning if re-constraining parameters.
|
:param warning: print a warning if re-constraining parameters.
|
||||||
|
|
@ -160,19 +295,6 @@ class Constrainable(Nameable):
|
||||||
"""
|
"""
|
||||||
self.constrain(Logistic(lower, upper), warning=warning, update=update)
|
self.constrain(Logistic(lower, upper), warning=warning, update=update)
|
||||||
|
|
||||||
def unconstrain(self, *transforms):
|
|
||||||
"""
|
|
||||||
:param transforms: The transformations to unconstrain from.
|
|
||||||
|
|
||||||
remove all :py:class:`GPy.core.transformations.Transformation`
|
|
||||||
transformats of this parameter object.
|
|
||||||
"""
|
|
||||||
if self.has_parent():
|
|
||||||
self._highest_parent_._remove_constrain(self, *transforms)
|
|
||||||
else:
|
|
||||||
for p in self._parameters_:
|
|
||||||
self._remove_constrain(p, *transforms)
|
|
||||||
|
|
||||||
def unconstrain_positive(self):
|
def unconstrain_positive(self):
|
||||||
"""
|
"""
|
||||||
Remove positive constraint of this parameter.
|
Remove positive constraint of this parameter.
|
||||||
|
|
@ -192,3 +314,35 @@ class Constrainable(Nameable):
|
||||||
Remove (lower, upper) bounded constrain from this parameter/
|
Remove (lower, upper) bounded constrain from this parameter/
|
||||||
"""
|
"""
|
||||||
self.unconstrain(Logistic(lower, upper))
|
self.unconstrain(Logistic(lower, upper))
|
||||||
|
|
||||||
|
def _parent_changed(self, parent):
|
||||||
|
from index_operations import ParameterIndexOperationsView
|
||||||
|
self.constraints = ParameterIndexOperationsView(parent.constraints, parent._offset_for(self), self.size)
|
||||||
|
self.priors = ParameterIndexOperationsView(parent.priors, parent._offset_for(self), self.size)
|
||||||
|
self._fixes_ = None
|
||||||
|
for p in self._parameters_:
|
||||||
|
p._parent_changed(parent)
|
||||||
|
|
||||||
|
def _add_to_index_operations(self, which, reconstrained, transform, warning, update):
|
||||||
|
if warning and reconstrained.size > 0:
|
||||||
|
print "WARNING: reconstraining parameters {}".format(self.parameter_names() or self.name)
|
||||||
|
which.add(transform, self._raveled_index())
|
||||||
|
if update:
|
||||||
|
self._notify_parameters_changed()
|
||||||
|
|
||||||
|
def _remove_from_index_operations(self, which, transforms):
|
||||||
|
if len(transforms) == 0:
|
||||||
|
transforms = which.properties()
|
||||||
|
import numpy as np
|
||||||
|
removed = np.empty((0, ), dtype=int)
|
||||||
|
for t in transforms:
|
||||||
|
unconstrained = which.remove(t, self._raveled_index())
|
||||||
|
removed = np.union1d(removed, unconstrained)
|
||||||
|
if t is __fixed__:
|
||||||
|
self._highest_parent_._set_unfixed(unconstrained)
|
||||||
|
|
||||||
|
return removed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,9 @@ import itertools
|
||||||
from re import compile, _pattern_type
|
from re import compile, _pattern_type
|
||||||
from param import ParamConcatenation, Param
|
from param import ParamConcatenation, Param
|
||||||
from parameter_core import Constrainable, Pickleable, Observable, adjust_name_for_printing, Gradcheckable
|
from parameter_core import Constrainable, Pickleable, Observable, adjust_name_for_printing, Gradcheckable
|
||||||
from index_operations import ParameterIndexOperations,\
|
from transformations import __fixed__, FIXED, UNFIXED
|
||||||
index_empty
|
|
||||||
from array_core import ParamList
|
from array_core import ParamList
|
||||||
|
|
||||||
#===============================================================================
|
|
||||||
# Printing:
|
|
||||||
__fixed__ = "fixed"
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
#===============================================================================
|
|
||||||
# constants
|
|
||||||
FIXED = False
|
|
||||||
UNFIXED = True
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
"""
|
"""
|
||||||
Parameterized class
|
Parameterized class
|
||||||
|
|
@ -69,7 +57,6 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
def __init__(self, name=None):
|
def __init__(self, name=None):
|
||||||
super(Parameterized, self).__init__(name=name)
|
super(Parameterized, self).__init__(name=name)
|
||||||
self._in_init_ = True
|
self._in_init_ = True
|
||||||
self._constraints_ = None#ParameterIndexOperations()
|
|
||||||
self._parameters_ = ParamList()
|
self._parameters_ = ParamList()
|
||||||
self.size = sum(p.size for p in self._parameters_)
|
self.size = sum(p.size for p in self._parameters_)
|
||||||
if not self._has_fixes():
|
if not self._has_fixes():
|
||||||
|
|
@ -79,45 +66,6 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
self._added_names_ = set()
|
self._added_names_ = set()
|
||||||
del self._in_init_
|
del self._in_init_
|
||||||
|
|
||||||
@property
|
|
||||||
def constraints(self):
|
|
||||||
if self._constraints_ is None:
|
|
||||||
self._constraints_ = ParameterIndexOperations()
|
|
||||||
return self._constraints_
|
|
||||||
#===========================================================================
|
|
||||||
# Parameter connection for model creation:
|
|
||||||
#===========================================================================
|
|
||||||
# def set_as_parameter(self, name, array, gradient, index=None, gradient_parent=None):
|
|
||||||
# """
|
|
||||||
# :param name: name of the param (in print and plots), can be callable without parameters
|
|
||||||
# :type name: str, callable
|
|
||||||
# :param array: array which the param consists of
|
|
||||||
# :type array: array-like
|
|
||||||
# :param gradient: gradient method of the param
|
|
||||||
# :type gradient: callable
|
|
||||||
# :param index: (optional) index of the param when printing
|
|
||||||
#
|
|
||||||
# (:param gradient_parent: connect these parameters to this class, but tell
|
|
||||||
# updates to highest_parent, this is needed when parameterized classes
|
|
||||||
# contain parameterized classes, but want to access the parameters
|
|
||||||
# of their children)
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Set array (e.g. self.X) as param with name and gradient.
|
|
||||||
# I.e: self.set_as_parameter('curvature', self.lengthscale, self.dK_dlengthscale)
|
|
||||||
#
|
|
||||||
# Note: the order in which parameters are added can be adjusted by
|
|
||||||
# giving an index, of where to put this param in printing
|
|
||||||
# """
|
|
||||||
# if index is None:
|
|
||||||
# self._parameters_.append(Param(name, array, gradient))
|
|
||||||
# else:
|
|
||||||
# self._parameters_.insert(index, Param(name, array, gradient))
|
|
||||||
# self._connect_parameters(gradient_parent=gradient_parent)
|
|
||||||
|
|
||||||
def _has_fixes(self):
|
|
||||||
return hasattr(self, "_fixes_") and self._fixes_ is not None
|
|
||||||
|
|
||||||
def add_parameter(self, param, index=None):
|
def add_parameter(self, param, index=None):
|
||||||
"""
|
"""
|
||||||
:param parameters: the parameters to add
|
:param parameters: the parameters to add
|
||||||
|
|
@ -128,58 +76,31 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
Add all parameters to this param class, you can insert parameters
|
Add all parameters to this param class, you can insert parameters
|
||||||
at any given index using the :func:`list.insert` syntax
|
at any given index using the :func:`list.insert` syntax
|
||||||
"""
|
"""
|
||||||
|
# if param.has_parent():
|
||||||
|
# raise AttributeError, "parameter {} already in another model, create new object (or copy) for adding".format(param._short())
|
||||||
if param in self._parameters_ and index is not None:
|
if param in self._parameters_ and index is not None:
|
||||||
# make sure fixes and constraints are indexed right
|
self.remove_parameter(param)
|
||||||
if self._has_fixes():
|
self.add_parameter(param, index)
|
||||||
param_slice = slice(self._offset_for(param),self._offset_for(param)+param.size)
|
|
||||||
dest_index = sum((p.size for p in self._parameters_[:index]))
|
|
||||||
dest_slice = slice(dest_index,dest_index+param.size)
|
|
||||||
fixes_param = self._fixes_[param_slice].copy()
|
|
||||||
self._fixes_[param_slice] = self._fixes_[dest_slice]
|
|
||||||
self._fixes_[dest_slice] = fixes_param
|
|
||||||
|
|
||||||
del self._parameters_[param._parent_index_]
|
|
||||||
self._parameters_.insert(index, param)
|
|
||||||
elif param not in self._parameters_:
|
elif param not in self._parameters_:
|
||||||
# make sure the size is set
|
# make sure the size is set
|
||||||
if not hasattr(self, 'size'):
|
|
||||||
self.size = sum(p.size for p in self._parameters_)
|
|
||||||
if index is None:
|
if index is None:
|
||||||
|
self.constraints.update(param.constraints, self.size)
|
||||||
|
self.priors.update(param.priors, self.size)
|
||||||
self._parameters_.append(param)
|
self._parameters_.append(param)
|
||||||
|
|
||||||
# make sure fixes and constraints are indexed right
|
|
||||||
if param._has_fixes(): fixes_param = param._fixes_.copy()
|
|
||||||
else: fixes_param = numpy.ones(param.size, dtype=bool)
|
|
||||||
if self._has_fixes(): self._fixes_ = np.r_[self._fixes_, fixes_param]
|
|
||||||
elif param._has_fixes(): self._fixes_ = np.r_[np.ones(self.size, dtype=bool), fixes_param]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
start = sum(p.size for p in self._parameters_[:index])
|
start = sum(p.size for p in self._parameters_[:index])
|
||||||
self.constraints.shift(start, param.size)
|
self.constraints.shift(start, param.size)
|
||||||
|
self.priors.shift(start, param.size)
|
||||||
|
self.constraints.update(param.constraints, start)
|
||||||
|
self.priors.update(param.priors, start)
|
||||||
self._parameters_.insert(index, param)
|
self._parameters_.insert(index, param)
|
||||||
|
|
||||||
# make sure fixes and constraints are indexed right
|
|
||||||
if param._has_fixes(): fixes_param = param._fixes_.copy()
|
|
||||||
else: fixes_param = numpy.ones(param.size, dtype=bool)
|
|
||||||
ins = sum((p.size for p in self._parameters_[:index]))
|
|
||||||
if self._has_fixes(): self._fixes_ = np.r_[self._fixes_[:ins], fixes_param, self._fixes[ins:]]
|
|
||||||
elif not np.all(fixes_param):
|
|
||||||
self._fixes_ = np.ones(self.size+param.size, dtype=bool)
|
|
||||||
self._fixes_[ins:ins+param.size] = fixes_param
|
|
||||||
self.size += param.size
|
self.size += param.size
|
||||||
else:
|
else:
|
||||||
raise RuntimeError, """Parameter exists already added and no copy made"""
|
raise RuntimeError, """Parameter exists already added and no copy made"""
|
||||||
self._connect_parameters()
|
self._connect_parameters()
|
||||||
# make sure the constraints are pulled over:
|
self._notify_parent_change()
|
||||||
if hasattr(param, "_constraints_") and param._constraints_ is not None:
|
self._connect_fixes()
|
||||||
for t, ind in param._constraints_.iteritems():
|
|
||||||
|
|
||||||
self.constraints.add(t, ind+self._offset_for(param))
|
|
||||||
param._constraints_.clear()
|
|
||||||
if param._default_constraint_ is not None:
|
|
||||||
self._add_constrain(param, param._default_constraint_, False)
|
|
||||||
if self._has_fixes() and np.all(self._fixes_): # ==UNFIXED
|
|
||||||
self._fixes_= None
|
|
||||||
|
|
||||||
def add_parameters(self, *parameters):
|
def add_parameters(self, *parameters):
|
||||||
"""
|
"""
|
||||||
|
|
@ -188,44 +109,44 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
"""
|
"""
|
||||||
[self.add_parameter(p) for p in parameters]
|
[self.add_parameter(p) for p in parameters]
|
||||||
|
|
||||||
def remove_parameter(self, *names_params_indices):
|
def remove_parameter(self, param):
|
||||||
"""
|
"""
|
||||||
:param names_params_indices: mix of parameter_names, param objects, or indices
|
:param param: param object to remove from being a parameter of this parameterized object.
|
||||||
to remove from being a param of this parameterized object.
|
|
||||||
|
|
||||||
note: if it is a string object it will not (!) be regexp-matched
|
|
||||||
automatically.
|
|
||||||
"""
|
"""
|
||||||
self._parameters_ = ParamList([p for p in self._parameters_
|
if not param in self._parameters_:
|
||||||
if not (p._parent_index_ in names_params_indices
|
raise RuntimeError, "Parameter {} does not belong to this object, remove parameters directly from their respective parents".format(param._short())
|
||||||
or p.name in names_params_indices
|
del self._parameters_[param._parent_index_]
|
||||||
or p in names_params_indices)])
|
self.size -= param.size
|
||||||
|
constr = param.constraints.copy()
|
||||||
|
param.constraints.clear()
|
||||||
|
param.constraints = constr
|
||||||
|
param._direct_parent_ = None
|
||||||
|
param._parent_index_ = None
|
||||||
|
param._connect_fixes()
|
||||||
|
param._notify_parent_change()
|
||||||
|
pname = adjust_name_for_printing(param.name)
|
||||||
|
if pname in self._added_names_:
|
||||||
|
del self.__dict__[pname]
|
||||||
self._connect_parameters()
|
self._connect_parameters()
|
||||||
|
#self._notify_parent_change()
|
||||||
def parameters_changed(self):
|
self._connect_fixes()
|
||||||
"""
|
|
||||||
This method gets called when parameters have changed.
|
|
||||||
Another way of listening to param changes is to
|
|
||||||
add self as a listener to the param, such that
|
|
||||||
updates get passed through. See :py:function:``GPy.core.param.Observable.add_observer``
|
|
||||||
"""
|
|
||||||
# will be called as soon as parameters have changed
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _connect_parameters(self):
|
def _connect_parameters(self):
|
||||||
# connect parameterlist to this parameterized object
|
# connect parameterlist to this parameterized object
|
||||||
# This just sets up the right connection for the params objects
|
# This just sets up the right connection for the params objects
|
||||||
# to be used as parameters
|
# to be used as parameters
|
||||||
|
# it also sets the constraints for each parameter to the constraints
|
||||||
|
# of their respective parents
|
||||||
if not hasattr(self, "_parameters_") or len(self._parameters_) < 1:
|
if not hasattr(self, "_parameters_") or len(self._parameters_) < 1:
|
||||||
# no parameters for this class
|
# no parameters for this class
|
||||||
return
|
return
|
||||||
sizes = [0]
|
sizes = [0]
|
||||||
self._param_slices_ = []
|
self._param_slices_ = []
|
||||||
for i,p in enumerate(self._parameters_):
|
for i, p in enumerate(self._parameters_):
|
||||||
p._direct_parent_ = self
|
p._direct_parent_ = self
|
||||||
p._parent_index_ = i
|
p._parent_index_ = i
|
||||||
not_unique = []
|
not_unique = []
|
||||||
sizes.append(p.size+sizes[-1])
|
sizes.append(p.size + sizes[-1])
|
||||||
self._param_slices_.append(slice(sizes[-2], sizes[-1]))
|
self._param_slices_.append(slice(sizes[-2], sizes[-1]))
|
||||||
pname = adjust_name_for_printing(p.name)
|
pname = adjust_name_for_printing(p.name)
|
||||||
# and makes sure to not delete programmatically added parameters
|
# and makes sure to not delete programmatically added parameters
|
||||||
|
|
@ -237,7 +158,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
elif not (pname in not_unique):
|
elif not (pname in not_unique):
|
||||||
self.__dict__[pname] = p
|
self.__dict__[pname] = p
|
||||||
self._added_names_.add(pname)
|
self._added_names_.add(pname)
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Pickling operations
|
# Pickling operations
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -255,16 +176,16 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
cPickle.dump(self, f, protocol)
|
cPickle.dump(self, f, protocol)
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""Returns a (deep) copy of the current model """
|
"""Returns a (deep) copy of the current model """
|
||||||
#dc = dict()
|
# dc = dict()
|
||||||
#for k, v in self.__dict__.iteritems():
|
# for k, v in self.__dict__.iteritems():
|
||||||
#if k not in ['_highest_parent_', '_direct_parent_']:
|
# if k not in ['_highest_parent_', '_direct_parent_']:
|
||||||
#dc[k] = copy.deepcopy(v)
|
# dc[k] = copy.deepcopy(v)
|
||||||
|
|
||||||
#dc = copy.deepcopy(self.__dict__)
|
# dc = copy.deepcopy(self.__dict__)
|
||||||
#dc['_highest_parent_'] = None
|
# dc['_highest_parent_'] = None
|
||||||
#dc['_direct_parent_'] = None
|
# dc['_direct_parent_'] = None
|
||||||
#s = self.__class__.new()
|
# s = self.__class__.new()
|
||||||
#s.__dict__ = dc
|
# s.__dict__ = dc
|
||||||
return copy.deepcopy(self)
|
return copy.deepcopy(self)
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
if self._has_get_set_state():
|
if self._has_get_set_state():
|
||||||
|
|
@ -272,8 +193,8 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
return self.__dict__
|
return self.__dict__
|
||||||
def __setstate__(self, state):
|
def __setstate__(self, state):
|
||||||
if self._has_get_set_state():
|
if self._has_get_set_state():
|
||||||
self._setstate(state) # set state
|
self._setstate(state) # set state
|
||||||
#self._set_params(self._get_params()) # restore all values
|
# self._set_params(self._get_params()) # restore all values
|
||||||
return
|
return
|
||||||
self.__dict__ = state
|
self.__dict__ = state
|
||||||
def _has_get_set_state(self):
|
def _has_get_set_state(self):
|
||||||
|
|
@ -289,7 +210,8 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
"""
|
"""
|
||||||
return [
|
return [
|
||||||
self._fixes_,
|
self._fixes_,
|
||||||
self._constraints_,
|
self.priors,
|
||||||
|
self.constraints,
|
||||||
self._parameters_,
|
self._parameters_,
|
||||||
self._name,
|
self._name,
|
||||||
self._added_names_,
|
self._added_names_,
|
||||||
|
|
@ -299,9 +221,10 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
self._added_names_ = state.pop()
|
self._added_names_ = state.pop()
|
||||||
self._name = state.pop()
|
self._name = state.pop()
|
||||||
self._parameters_ = state.pop()
|
self._parameters_ = state.pop()
|
||||||
self._connect_parameters()
|
self.constraints = state.pop()
|
||||||
self._constraints_ = state.pop()
|
self.priors = state.pop()
|
||||||
self._fixes_ = state.pop()
|
self._fixes_ = state.pop()
|
||||||
|
self._connect_parameters()
|
||||||
self.parameters_changed()
|
self.parameters_changed()
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Gradient control
|
# Gradient control
|
||||||
|
|
@ -310,9 +233,9 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
if self.has_parent():
|
if self.has_parent():
|
||||||
return g
|
return g
|
||||||
x = self._get_params()
|
x = self._get_params()
|
||||||
[numpy.put(g, i, g[i]*c.gradfactor(x[i])) for c,i in self.constraints.iteritems() if c != __fixed__]
|
[numpy.put(g, i, g[i] * c.gradfactor(x[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||||
for p in self.flattened_parameters:
|
for p in self.flattened_parameters:
|
||||||
for t,i in p._tied_to_me_.iteritems():
|
for t, i in p._tied_to_me_.iteritems():
|
||||||
g[self._offset_for(p) + numpy.array(list(i))] += g[self._raveled_index_for(t)]
|
g[self._offset_for(p) + numpy.array(list(i))] += g[self._raveled_index_for(t)]
|
||||||
if self._has_fixes(): return g[self._fixes_]
|
if self._has_fixes(): return g[self._fixes_]
|
||||||
return g
|
return g
|
||||||
|
|
@ -320,27 +243,17 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
# Optimization handles:
|
# Optimization handles:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def _get_param_names(self):
|
def _get_param_names(self):
|
||||||
n = numpy.array([p.name_hirarchical+'['+str(i)+']' for p in self.flattened_parameters for i in p._indices()])
|
n = numpy.array([p.name_hirarchical + '[' + str(i) + ']' for p in self.flattened_parameters for i in p._indices()])
|
||||||
return n
|
return n
|
||||||
def _get_param_names_transformed(self):
|
def _get_param_names_transformed(self):
|
||||||
n = self._get_param_names()
|
n = self._get_param_names()
|
||||||
if self._has_fixes():
|
if self._has_fixes():
|
||||||
return n[self._fixes_]
|
return n[self._fixes_]
|
||||||
return n
|
return n
|
||||||
def _get_params(self):
|
|
||||||
# don't overwrite this anymore!
|
|
||||||
if not self.size:
|
|
||||||
return np.empty(shape=(0,), dtype=np.float64)
|
|
||||||
return numpy.hstack([x._get_params() for x in self._parameters_ if x.size>0])
|
|
||||||
|
|
||||||
def _set_params(self, params, update=True):
|
|
||||||
# don't overwrite this anymore!
|
|
||||||
[p._set_params(params[s], update=update) for p,s in itertools.izip(self._parameters_,self._param_slices_)]
|
|
||||||
self.parameters_changed()
|
|
||||||
def _get_params_transformed(self):
|
def _get_params_transformed(self):
|
||||||
# transformed parameters (apply transformation rules)
|
# transformed parameters (apply transformation rules)
|
||||||
p = self._get_params()
|
p = self._get_params()
|
||||||
[numpy.put(p, ind, c.finv(p[ind])) for c,ind in self.constraints.iteritems() if c != __fixed__]
|
[numpy.put(p, ind, c.finv(p[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||||
if self._has_fixes():
|
if self._has_fixes():
|
||||||
return p[self._fixes_]
|
return p[self._fixes_]
|
||||||
return p
|
return p
|
||||||
|
|
@ -350,7 +263,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
def _untransform_params(self, p):
|
def _untransform_params(self, p):
|
||||||
p = p.copy()
|
p = p.copy()
|
||||||
if self._has_fixes(): tmp = self._get_params(); tmp[self._fixes_] = p; p = tmp; del tmp
|
if self._has_fixes(): tmp = self._get_params(); tmp[self._fixes_] = p; p = tmp; del tmp
|
||||||
[numpy.put(p, ind, c.f(p[ind])) for c,ind in self.constraints.iteritems() if c != __fixed__]
|
[numpy.put(p, ind, c.f(p[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||||
return p
|
return p
|
||||||
def _name_changed(self, param, old_name):
|
def _name_changed(self, param, old_name):
|
||||||
if hasattr(self, old_name) and old_name in self._added_names_:
|
if hasattr(self, old_name) and old_name in self._added_names_:
|
||||||
|
|
@ -361,11 +274,11 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
self._added_names_.add(pname)
|
self._added_names_.add(pname)
|
||||||
self.__dict__[pname] = param
|
self.__dict__[pname] = param
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Index Handling
|
# Indexable Handling
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def _backtranslate_index(self, param, ind):
|
def _backtranslate_index(self, param, ind):
|
||||||
# translate an index in parameterized indexing into the index of param
|
# translate an index in parameterized indexing into the index of param
|
||||||
ind = ind-self._offset_for(param)
|
ind = ind - self._offset_for(param)
|
||||||
ind = ind[ind >= 0]
|
ind = ind[ind >= 0]
|
||||||
internal_offset = param._internal_offset()
|
internal_offset = param._internal_offset()
|
||||||
ind = ind[ind < param.size + internal_offset]
|
ind = ind[ind < param.size + internal_offset]
|
||||||
|
|
@ -377,7 +290,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
return self._param_slices_[param._direct_parent_._get_original(param)._parent_index_].start
|
return self._param_slices_[param._direct_parent_._get_original(param)._parent_index_].start
|
||||||
return self._offset_for(param._direct_parent_) + param._direct_parent_._offset_for(param)
|
return self._offset_for(param._direct_parent_) + param._direct_parent_._offset_for(param)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def _raveled_index_for(self, param):
|
def _raveled_index_for(self, param):
|
||||||
"""
|
"""
|
||||||
get the raveled index for a param
|
get the raveled index for a param
|
||||||
|
|
@ -387,7 +300,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
if isinstance(param, ParamConcatenation):
|
if isinstance(param, ParamConcatenation):
|
||||||
return numpy.hstack((self._raveled_index_for(p) for p in param.params))
|
return numpy.hstack((self._raveled_index_for(p) for p in param.params))
|
||||||
return param._raveled_index() + self._offset_for(param)
|
return param._raveled_index() + self._offset_for(param)
|
||||||
|
|
||||||
def _raveled_index(self):
|
def _raveled_index(self):
|
||||||
"""
|
"""
|
||||||
get the raveled index for this object,
|
get the raveled index for this object,
|
||||||
|
|
@ -397,36 +310,10 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Fixing parameters:
|
# Fixing parameters:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def _set_fixed(self, param_or_index):
|
|
||||||
if not self._has_fixes(): self._fixes_ = numpy.ones(self.size, dtype=bool)
|
|
||||||
try:
|
|
||||||
param_or_index = self._raveled_index_for(param_or_index)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
self._fixes_[param_or_index] = FIXED
|
|
||||||
if numpy.all(self._fixes_): self._fixes_ = None # ==UNFIXED
|
|
||||||
def _set_unfixed(self, param_or_index):
|
|
||||||
if not self._has_fixes(): self._fixes_ = numpy.ones(self.size, dtype=bool)
|
|
||||||
try:
|
|
||||||
param_or_index = self._raveled_index_for(param_or_index)
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
self._fixes_[param_or_index] = UNFIXED
|
|
||||||
for constr, ind in self.constraints.iteritems():
|
|
||||||
if constr is __fixed__:
|
|
||||||
self._fixes_[ind] = FIXED
|
|
||||||
if numpy.all(self._fixes_): self._fixes_ = None # ==UNFIXED
|
|
||||||
def _fixes_for(self, param):
|
def _fixes_for(self, param):
|
||||||
if self._has_fixes():
|
if self._has_fixes():
|
||||||
return self._fixes_[self._raveled_index_for(param)]
|
return self._fixes_[self._raveled_index_for(param)]
|
||||||
return numpy.ones(self.size, dtype=bool)[self._raveled_index_for(param)]
|
return numpy.ones(self.size, dtype=bool)[self._raveled_index_for(param)]
|
||||||
def _fix(self, param, warning=True):
|
|
||||||
f = self._add_constrain(param, __fixed__, warning)
|
|
||||||
self._set_fixed(f)
|
|
||||||
def _unfix(self, param):
|
|
||||||
if self._has_fixes():
|
|
||||||
f = self._remove_constrain(param, __fixed__)
|
|
||||||
self._set_unfixed(f)
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Convenience for fixed, tied checking of param:
|
# Convenience for fixed, tied checking of param:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
@ -437,7 +324,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
if not self._has_fixes():
|
if not self._has_fixes():
|
||||||
return False
|
return False
|
||||||
return not self._fixes_[self._raveled_index_for(param)].any()
|
return not self._fixes_[self._raveled_index_for(param)].any()
|
||||||
#return not self._fixes_[self._offset_for(param): self._offset_for(param)+param._realsize_].any()
|
# return not self._fixes_[self._offset_for(param): self._offset_for(param)+param._realsize_].any()
|
||||||
@property
|
@property
|
||||||
def is_fixed(self):
|
def is_fixed(self):
|
||||||
for p in self._parameters_:
|
for p in self._parameters_:
|
||||||
|
|
@ -453,57 +340,6 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
return self._direct_parent_.hirarchy_name() + adjust_name_for_printing(self.name) + "."
|
return self._direct_parent_.hirarchy_name() + adjust_name_for_printing(self.name) + "."
|
||||||
return ''
|
return ''
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Constraint Handling:
|
|
||||||
#===========================================================================
|
|
||||||
def _add_constrain(self, param, transform, warning=True):
|
|
||||||
rav_i = self._raveled_index_for(param)
|
|
||||||
reconstrained = self._remove_constrain(param, index=rav_i) # remove constraints before
|
|
||||||
# if removing constraints before adding new is not wanted, just delete the above line!
|
|
||||||
self.constraints.add(transform, rav_i)
|
|
||||||
param = self._get_original(param)
|
|
||||||
if not (transform == __fixed__):
|
|
||||||
param._set_params(transform.initialize(param._get_params()), update=False)
|
|
||||||
if warning and any(reconstrained):
|
|
||||||
# if you want to print the whole params object, which was reconstrained use:
|
|
||||||
# m = str(param[self._backtranslate_index(param, reconstrained)])
|
|
||||||
print "Warning: re-constraining parameters:\n{}".format(param._short())
|
|
||||||
return rav_i
|
|
||||||
def _remove_constrain(self, param, *transforms, **kwargs):
|
|
||||||
if not transforms:
|
|
||||||
transforms = self.constraints.properties()
|
|
||||||
removed_indices = numpy.array([]).astype(int)
|
|
||||||
if "index" in kwargs: index = kwargs['index']
|
|
||||||
else: index = self._raveled_index_for(param)
|
|
||||||
for constr in transforms:
|
|
||||||
removed = self.constraints.remove(constr, index)
|
|
||||||
if constr is __fixed__:
|
|
||||||
self._set_unfixed(removed)
|
|
||||||
removed_indices = numpy.union1d(removed_indices, removed)
|
|
||||||
return removed_indices
|
|
||||||
# convienience for iterating over items
|
|
||||||
def _constraints_iter_items(self, param):
|
|
||||||
for constr, ind in self.constraints.iteritems():
|
|
||||||
ind = self._backtranslate_index(param, ind)
|
|
||||||
if not index_empty(ind):
|
|
||||||
yield constr, ind
|
|
||||||
def _constraints_iter(self, param):
|
|
||||||
for constr, _ in self._constraints_iter_items(param):
|
|
||||||
yield constr
|
|
||||||
def _contraints_iter_indices(self, param):
|
|
||||||
# iterate through all constraints belonging to param
|
|
||||||
for _, ind in self._constraints_iter_items(param):
|
|
||||||
yield ind
|
|
||||||
def _constraint_indices(self, param, constraint):
|
|
||||||
# indices in model range for param and constraint
|
|
||||||
return self._backtranslate_index(param, self.constraints[constraint]) + self._offset_for(param)
|
|
||||||
def _constraints_for(self, param, rav_index):
|
|
||||||
# constraint for param given its internal rav_index
|
|
||||||
return self.constraints.properties_for(rav_index+self._offset_for(param))
|
|
||||||
def _constraints_for_collect(self, param, rav_index):
|
|
||||||
# constraint for param given its internal rav_index
|
|
||||||
cs = self._constraints_for(param, rav_index)
|
|
||||||
return set(itertools.chain(*cs))
|
|
||||||
#===========================================================================
|
|
||||||
# Get/set parameters:
|
# Get/set parameters:
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def grep_param_names(self, regexp):
|
def grep_param_names(self, regexp):
|
||||||
|
|
@ -539,7 +375,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
# def __getattribute__(self, name):
|
# def __getattribute__(self, name):
|
||||||
# #try:
|
# #try:
|
||||||
# return object.__getattribute__(self, name)
|
# return object.__getattribute__(self, name)
|
||||||
#except AttributeError:
|
# except AttributeError:
|
||||||
# _, a, tb = sys.exc_info()
|
# _, a, tb = sys.exc_info()
|
||||||
# try:
|
# try:
|
||||||
# return self.__getitem__(name)
|
# return self.__getitem__(name)
|
||||||
|
|
@ -560,13 +396,6 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
return self._direct_parent_.hirarchy_name() + adjust_name_for_printing(self.name)
|
return self._direct_parent_.hirarchy_name() + adjust_name_for_printing(self.name)
|
||||||
else:
|
else:
|
||||||
return adjust_name_for_printing(self.name)
|
return adjust_name_for_printing(self.name)
|
||||||
def _parameter_names(self, add_name=False):
|
|
||||||
if add_name:
|
|
||||||
return [adjust_name_for_printing(self.name) + "." + xi for x in self._parameters_ for xi in x._parameter_names(add_name=True)]
|
|
||||||
return [xi for x in self._parameters_ for xi in x._parameter_names(add_name=True)]
|
|
||||||
parameter_names = property(_parameter_names, doc="Names for all parameters handled by this parameterization object -- will add hirarchy name entries for printing")
|
|
||||||
def _collect_gradient(self, target):
|
|
||||||
[p._collect_gradient(target[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
|
||||||
@property
|
@property
|
||||||
def flattened_parameters(self):
|
def flattened_parameters(self):
|
||||||
return [xi for x in self._parameters_ for xi in x.flattened_parameters]
|
return [xi for x in self._parameters_ for xi in x.flattened_parameters]
|
||||||
|
|
@ -585,6 +414,9 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
def _constraints_str(self):
|
def _constraints_str(self):
|
||||||
return [cs for p in self._parameters_ for cs in p._constraints_str]
|
return [cs for p in self._parameters_ for cs in p._constraints_str]
|
||||||
@property
|
@property
|
||||||
|
def _priors_str(self):
|
||||||
|
return [cs for p in self._parameters_ for cs in p._priors_str]
|
||||||
|
@property
|
||||||
def _description_str(self):
|
def _description_str(self):
|
||||||
return [xi for x in self._parameters_ for xi in x._description_str]
|
return [xi for x in self._parameters_ for xi in x._description_str]
|
||||||
@property
|
@property
|
||||||
|
|
@ -592,22 +424,25 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
|
||||||
return [','.join(x._ties_str) for x in self.flattened_parameters]
|
return [','.join(x._ties_str) for x in self.flattened_parameters]
|
||||||
def __str__(self, header=True):
|
def __str__(self, header=True):
|
||||||
|
|
||||||
name = adjust_name_for_printing(self.name) + "."
|
name = adjust_name_for_printing(self.name) + "."
|
||||||
constrs = self._constraints_str; ts = self._ties_str
|
constrs = self._constraints_str;
|
||||||
desc = self._description_str; names = self.parameter_names
|
ts = self._ties_str
|
||||||
|
prirs = self._priors_str
|
||||||
|
desc = self._description_str; names = self.parameter_names()
|
||||||
nl = max([len(str(x)) for x in names + [name]])
|
nl = max([len(str(x)) for x in names + [name]])
|
||||||
sl = max([len(str(x)) for x in desc + ["Value"]])
|
sl = max([len(str(x)) for x in desc + ["Value"]])
|
||||||
cl = max([len(str(x)) if x else 0 for x in constrs + ["Constraint"]])
|
cl = max([len(str(x)) if x else 0 for x in constrs + ["Constraint"]])
|
||||||
tl = max([len(str(x)) if x else 0 for x in ts + ["Tied to"]])
|
tl = max([len(str(x)) if x else 0 for x in ts + ["Tied to"]])
|
||||||
format_spec = " \033[1m{{name:<{0}s}}\033[0;0m | {{desc:^{1}s}} | {{const:^{2}s}} | {{t:^{3}s}}".format(nl, sl, cl, tl)
|
pl = max([len(str(x)) if x else 0 for x in prirs + ["Prior"]])
|
||||||
|
format_spec = " \033[1m{{name:<{0}s}}\033[0;0m | {{desc:^{1}s}} | {{const:^{2}s}} | {{pri:^{3}s}} | {{t:^{4}s}}".format(nl, sl, cl, pl, tl)
|
||||||
to_print = []
|
to_print = []
|
||||||
for n, d, c, t in itertools.izip(names, desc, constrs, ts):
|
for n, d, c, t, p in itertools.izip(names, desc, constrs, ts, prirs):
|
||||||
to_print.append(format_spec.format(name=n, desc=d, const=c, t=t))
|
to_print.append(format_spec.format(name=n, desc=d, const=c, t=t, pri=p))
|
||||||
#to_print = [format_spec.format(p=p, const=c, t=t) if isinstance(p, Param) else p.__str__(header=False) for p, c, t in itertools.izip(self._parameters_, constrs, ts)]
|
# to_print = [format_spec.format(p=p, const=c, t=t) if isinstance(p, Param) else p.__str__(header=False) for p, c, t in itertools.izip(self._parameters_, constrs, ts)]
|
||||||
sep = '-'*(nl+sl+cl+tl+8*2+3)
|
sep = '-' * (nl + sl + cl + + pl + tl + 8 * 2 + 3)
|
||||||
if header:
|
if header:
|
||||||
header = " {{0:<{0}s}} | {{1:^{1}s}} | {{2:^{2}s}} | {{3:^{3}s}}".format(nl, sl, cl, tl).format(name, "Value", "Constraint", "Tied to")
|
header = " {{0:<{0}s}} | {{1:^{1}s}} | {{2:^{2}s}} | {{3:^{3}s}} | {{4:^{4}s}}".format(nl, sl, cl, pl, tl).format(name, "Value", "Constraint", "Prior", "Tied to")
|
||||||
#header += '\n' + sep
|
# header += '\n' + sep
|
||||||
to_print.insert(0, header)
|
to_print.insert(0, header)
|
||||||
return '\n'.format(sep).join(to_print)
|
return '\n'.format(sep).join(to_print)
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,20 @@ from domains import _REAL, _POSITIVE
|
||||||
import warnings
|
import warnings
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
class Prior:
|
class Prior(object):
|
||||||
domain = None
|
domain = None
|
||||||
|
|
||||||
def pdf(self, x):
|
def pdf(self, x):
|
||||||
return np.exp(self.lnpdf(x))
|
return np.exp(self.lnpdf(x))
|
||||||
|
|
||||||
def plot(self):
|
def plot(self):
|
||||||
|
import sys
|
||||||
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
||||||
from ..plotting.matplot_dep import priors_plots
|
from ...plotting.matplot_dep import priors_plots
|
||||||
priors_plots.univariate_plot(self)
|
priors_plots.univariate_plot(self)
|
||||||
|
|
||||||
|
def __repr__(self, *args, **kwargs):
|
||||||
|
return self.__str__()
|
||||||
|
|
||||||
class Gaussian(Prior):
|
class Gaussian(Prior):
|
||||||
"""
|
"""
|
||||||
|
|
@ -150,6 +153,7 @@ class MultivariateGaussian:
|
||||||
return np.random.multivariate_normal(self.mu, self.var, n)
|
return np.random.multivariate_normal(self.mu, self.var, n)
|
||||||
|
|
||||||
def plot(self):
|
def plot(self):
|
||||||
|
import sys
|
||||||
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
||||||
from ..plotting.matplot_dep import priors_plots
|
from ..plotting.matplot_dep import priors_plots
|
||||||
priors_plots.multivariate_plot(self)
|
priors_plots.multivariate_plot(self)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,17 @@ import numpy as np
|
||||||
from domains import _POSITIVE,_NEGATIVE, _BOUNDED
|
from domains import _POSITIVE,_NEGATIVE, _BOUNDED
|
||||||
import sys
|
import sys
|
||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
_lim_val = -np.log(sys.float_info.epsilon)
|
_lim_val = -np.log(sys.float_info.epsilon)
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Fixing constants
|
||||||
|
__fixed__ = "fixed"
|
||||||
|
FIXED = False
|
||||||
|
UNFIXED = True
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
|
||||||
class Transformation(object):
|
class Transformation(object):
|
||||||
domain = None
|
domain = None
|
||||||
_instance = None
|
_instance = None
|
||||||
|
|
@ -27,11 +36,14 @@ class Transformation(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
def __repr__(self):
|
||||||
|
return self.__class__.__name__
|
||||||
|
|
||||||
class Logexp(Transformation):
|
class Logexp(Transformation):
|
||||||
domain = _POSITIVE
|
domain = _POSITIVE
|
||||||
def f(self, x):
|
def f(self, x):
|
||||||
return np.where(x>_lim_val, x, np.log(1. + np.exp(x)))
|
return np.where(x>_lim_val, x, np.log(1. + np.exp(np.clip(x, -np.inf, _lim_val))))
|
||||||
|
#raises overflow warning: return np.where(x>_lim_val, x, np.log(1. + np.exp(x)))
|
||||||
def finv(self, f):
|
def finv(self, f):
|
||||||
return np.where(f>_lim_val, f, np.log(np.exp(f) - 1.))
|
return np.where(f>_lim_val, f, np.log(np.exp(f) - 1.))
|
||||||
def gradfactor(self, f):
|
def gradfactor(self, f):
|
||||||
|
|
@ -56,7 +68,7 @@ class NegativeLogexp(Transformation):
|
||||||
return -self.logexp.initialize(f) # np.abs(f)
|
return -self.logexp.initialize(f) # np.abs(f)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '-ve'
|
return '-ve'
|
||||||
|
|
||||||
class LogexpClipped(Logexp):
|
class LogexpClipped(Logexp):
|
||||||
max_bound = 1e100
|
max_bound = 1e100
|
||||||
min_bound = 1e-10
|
min_bound = 1e-10
|
||||||
|
|
@ -94,7 +106,6 @@ class LogexpClipped(Logexp):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '+ve_c'
|
return '+ve_c'
|
||||||
|
|
||||||
|
|
||||||
class Exponent(Transformation):
|
class Exponent(Transformation):
|
||||||
# TODO: can't allow this to go to zero, need to set a lower bound. Similar with negative Exponent below. See old MATLAB code.
|
# TODO: can't allow this to go to zero, need to set a lower bound. Similar with negative Exponent below. See old MATLAB code.
|
||||||
domain = _POSITIVE
|
domain = _POSITIVE
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# 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
|
||||||
from ..util.linalg import mdot, tdot, symmetrify, backsub_both_sides, chol_inv, dtrtrs, dpotrs, dpotri
|
from ..util.linalg import mdot, tdot, symmetrify, backsub_both_sides, dtrtrs, dpotrs, dpotri
|
||||||
from gp import GP
|
from gp import GP
|
||||||
from parameterization.param import Param
|
from parameterization.param import Param
|
||||||
from ..inference.latent_function_inference import varDTC
|
from ..inference.latent_function_inference import varDTC
|
||||||
|
|
@ -38,9 +38,9 @@ class SparseGP(GP):
|
||||||
if inference_method is None:
|
if inference_method is None:
|
||||||
if isinstance(likelihood, likelihoods.Gaussian):
|
if isinstance(likelihood, likelihoods.Gaussian):
|
||||||
inference_method = varDTC.VarDTC()
|
inference_method = varDTC.VarDTC()
|
||||||
else:
|
else:
|
||||||
#inference_method = ??
|
#inference_method = ??
|
||||||
raise NotImplementedError, "what to do what to do?"
|
raise NotImplementedError, "what to do what to do?"
|
||||||
print "defaulting to ", inference_method, "for latent function inference"
|
print "defaulting to ", inference_method, "for latent function inference"
|
||||||
|
|
||||||
self.Z = Param('inducing inputs', Z)
|
self.Z = Param('inducing inputs', Z)
|
||||||
|
|
@ -51,19 +51,23 @@ class SparseGP(GP):
|
||||||
self.X_variance = X_variance
|
self.X_variance = X_variance
|
||||||
|
|
||||||
GP.__init__(self, X, Y, kernel, likelihood, inference_method=inference_method, name=name)
|
GP.__init__(self, X, Y, kernel, likelihood, inference_method=inference_method, name=name)
|
||||||
|
|
||||||
self.add_parameter(self.Z, index=0)
|
self.add_parameter(self.Z, index=0)
|
||||||
|
self.parameters_changed()
|
||||||
|
|
||||||
|
def _update_gradients_Z(self, add=False):
|
||||||
|
#The derivative of the bound wrt the inducing inputs Z ( unless they're all fixed)
|
||||||
|
if not self.Z.is_fixed:
|
||||||
|
if add: self.Z.gradient += self.kern.gradients_X(self.grad_dict['dL_dKmm'], self.Z)
|
||||||
|
else: self.Z.gradient = self.kern.gradients_X(self.grad_dict['dL_dKmm'], self.Z)
|
||||||
|
if self.X_variance is None:
|
||||||
|
self.Z.gradient += self.kern.gradients_X(self.grad_dict['dL_dKnm'].T, self.Z, self.X)
|
||||||
|
else:
|
||||||
|
self.Z.gradient += self.kern.dpsi1_dZ(self.grad_dict['dL_dpsi1'], self.Z, self.X, self.X_variance)
|
||||||
|
self.Z.gradient += self.kern.dpsi2_dZ(self.grad_dict['dL_dpsi2'], self.Z, self.X, self.X_variance)
|
||||||
|
|
||||||
def parameters_changed(self):
|
def parameters_changed(self):
|
||||||
self.posterior, self._log_marginal_likelihood, self.grad_dict = self.inference_method.inference(self.kern, self.X, self.X_variance, self.Z, self.likelihood, self.Y)
|
self.posterior, self._log_marginal_likelihood, self.grad_dict = self.inference_method.inference(self.kern, self.X, self.X_variance, self.Z, self.likelihood, self.Y)
|
||||||
|
self._update_gradients_Z(add=False)
|
||||||
#The derivative of the bound wrt the inducing inputs Z
|
|
||||||
self.Z.gradient = self.kern.gradients_X(self.grad_dict['dL_dKmm'], self.Z)
|
|
||||||
if self.X_variance is None:
|
|
||||||
self.Z.gradient += self.kern.gradients_X(self.grad_dict['dL_dKnm'].T, self.Z, self.X)
|
|
||||||
else:
|
|
||||||
self.Z.gradient += self.kern.dpsi1_dZ(self.grad_dict['dL_dpsi1'], self.Z, self.X, self.X_variance)
|
|
||||||
self.Z.gradient += self.kern.dpsi2_dZ(self.grad_dict['dL_dpsi2'], self.Z, self.X, self.X_variance)
|
|
||||||
|
|
||||||
def _raw_predict(self, Xnew, X_variance_new=None, which_parts='all', full_cov=False):
|
def _raw_predict(self, Xnew, X_variance_new=None, which_parts='all', full_cov=False):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -87,18 +87,22 @@ def toy_linear_1d_classification_laplace(seed=default_seed, optimize=True, plot=
|
||||||
Y = data['Y'][:, 0:1]
|
Y = data['Y'][:, 0:1]
|
||||||
Y[Y.flatten() == -1] = 0
|
Y[Y.flatten() == -1] = 0
|
||||||
|
|
||||||
bern_noise_model = GPy.likelihoods.bernoulli()
|
likelihood = GPy.likelihoods.Bernoulli()
|
||||||
laplace_likelihood = GPy.likelihoods.Laplace(Y.copy(), bern_noise_model)
|
laplace_inf = GPy.inference.latent_function_inference.Laplace()
|
||||||
|
kernel = GPy.kern.rbf(1)
|
||||||
|
|
||||||
# Model definition
|
# Model definition
|
||||||
m = GPy.models.GPClassification(data['X'], Y, likelihood=laplace_likelihood)
|
m = GPy.core.GP(data['X'], Y, kernel=kernel, likelihood=likelihood, inference_method=laplace_inf)
|
||||||
print m
|
|
||||||
|
|
||||||
# Optimize
|
# Optimize
|
||||||
if optimize:
|
if optimize:
|
||||||
#m.update_likelihood_approximation()
|
#m.update_likelihood_approximation()
|
||||||
# Parameters optimization:
|
# Parameters optimization:
|
||||||
m.optimize('bfgs', messages=1)
|
try:
|
||||||
|
m.optimize('scg', messages=1)
|
||||||
|
except Exception as e:
|
||||||
|
return m
|
||||||
|
|
||||||
#m.pseudo_EM()
|
#m.pseudo_EM()
|
||||||
|
|
||||||
# Plot
|
# Plot
|
||||||
|
|
|
||||||
|
|
@ -42,38 +42,35 @@ def student_t_approx(optimize=True, plot=True):
|
||||||
kernel4 = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
kernel4 = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
||||||
|
|
||||||
#Gaussian GP model on clean data
|
#Gaussian GP model on clean data
|
||||||
m1 = GPy.models.GPRegression(X, Y.copy(), kernel=kernel1)
|
#m1 = GPy.models.GPRegression(X, Y.copy(), kernel=kernel1)
|
||||||
# optimize
|
## optimize
|
||||||
m1.ensure_default_constraints()
|
#m1['white'].constrain_fixed(1e-5)
|
||||||
m1['white'] = 1e-5
|
#m1.randomize()
|
||||||
m1['white'].constrain_fixed('white')
|
|
||||||
m1.randomize()
|
|
||||||
|
|
||||||
#Gaussian GP model on corrupt data
|
##Gaussian GP model on corrupt data
|
||||||
m2 = GPy.models.GPRegression(X, Yc.copy(), kernel=kernel2)
|
#m2 = GPy.models.GPRegression(X, Yc.copy(), kernel=kernel2)
|
||||||
m2.ensure_default_constraints()
|
#m1['white'].constrain_fixed(1e-5)
|
||||||
m1['white'] = 1e-5
|
#m2.randomize()
|
||||||
m1['white'].constrain_fixed('white')
|
|
||||||
m2.randomize()
|
|
||||||
|
|
||||||
#Student t GP model on clean data
|
#Student t GP model on clean data
|
||||||
t_distribution = GPy.likelihoods.StudentT(deg_free=deg_free, sigma2=edited_real_sd)
|
t_distribution = GPy.likelihoods.StudentT(deg_free=deg_free, sigma2=edited_real_sd)
|
||||||
laplace_inf = GPy.inference.latent_function_inference.LaplaceInference()
|
laplace_inf = GPy.inference.latent_function_inference.Laplace()
|
||||||
m3 = GPy.core.GP(X, Y.copy(), kernel3, likelihood=t_distribution, inference_method=laplace_inf)
|
m3 = GPy.core.GP(X, Y.copy(), kernel3, likelihood=t_distribution, inference_method=laplace_inf)
|
||||||
m3.ensure_default_constraints()
|
|
||||||
m3['t_noise'].constrain_bounded(1e-6, 10.)
|
m3['t_noise'].constrain_bounded(1e-6, 10.)
|
||||||
m3['white'] = 1e-5
|
m3['white'].constrain_fixed(1e-5)
|
||||||
m3['white'].constrain_fixed()
|
|
||||||
m3.randomize()
|
m3.randomize()
|
||||||
|
debug = True
|
||||||
|
print m3
|
||||||
|
if debug:
|
||||||
|
m3.optimize(messages=1)
|
||||||
|
return m3
|
||||||
|
|
||||||
#Student t GP model on corrupt data
|
#Student t GP model on corrupt data
|
||||||
t_distribution = GPy.likelihoods.StudentT(deg_free=deg_free, sigma2=edited_real_sd)
|
t_distribution = GPy.likelihoods.StudentT(deg_free=deg_free, sigma2=edited_real_sd)
|
||||||
laplace_inf = GPy.inference.latent_function_inference.LaplaceInference()
|
laplace_inf = GPy.inference.latent_function_inference.Laplace()
|
||||||
m4 = GPy.core.GP(X, Yc.copy(), kernel4, likelihood=t_distribution, inference_method=laplace_inf)
|
m4 = GPy.core.GP(X, Yc.copy(), kernel4, likelihood=t_distribution, inference_method=laplace_inf)
|
||||||
m4.ensure_default_constraints()
|
|
||||||
m4['t_noise'].constrain_bounded(1e-6, 10.)
|
m4['t_noise'].constrain_bounded(1e-6, 10.)
|
||||||
m4['white'] = 1e-5
|
m4['white'].constrain_fixed(1e-5)
|
||||||
m4['white'].constrain_fixed()
|
|
||||||
m4.randomize()
|
m4.randomize()
|
||||||
|
|
||||||
if optimize:
|
if optimize:
|
||||||
|
|
@ -156,7 +153,6 @@ def boston_example(optimize=True, plot=True):
|
||||||
#Gaussian GP
|
#Gaussian GP
|
||||||
print "Gauss GP"
|
print "Gauss GP"
|
||||||
mgp = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelgp.copy())
|
mgp = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelgp.copy())
|
||||||
mgp.ensure_default_constraints()
|
|
||||||
mgp.constrain_fixed('white', 1e-5)
|
mgp.constrain_fixed('white', 1e-5)
|
||||||
mgp['rbf_len'] = rbf_len
|
mgp['rbf_len'] = rbf_len
|
||||||
mgp['noise'] = noise
|
mgp['noise'] = noise
|
||||||
|
|
@ -174,7 +170,6 @@ def boston_example(optimize=True, plot=True):
|
||||||
g_distribution = GPy.likelihoods.noise_model_constructors.gaussian(variance=noise, N=N, D=D)
|
g_distribution = GPy.likelihoods.noise_model_constructors.gaussian(variance=noise, N=N, D=D)
|
||||||
g_likelihood = GPy.likelihoods.Laplace(Y_train.copy(), g_distribution)
|
g_likelihood = GPy.likelihoods.Laplace(Y_train.copy(), g_distribution)
|
||||||
mg = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelstu.copy(), likelihood=g_likelihood)
|
mg = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelstu.copy(), likelihood=g_likelihood)
|
||||||
mg.ensure_default_constraints()
|
|
||||||
mg.constrain_positive('noise_variance')
|
mg.constrain_positive('noise_variance')
|
||||||
mg.constrain_fixed('white', 1e-5)
|
mg.constrain_fixed('white', 1e-5)
|
||||||
mg['rbf_len'] = rbf_len
|
mg['rbf_len'] = rbf_len
|
||||||
|
|
@ -194,7 +189,6 @@ def boston_example(optimize=True, plot=True):
|
||||||
t_distribution = GPy.likelihoods.noise_model_constructors.student_t(deg_free=df, sigma2=noise)
|
t_distribution = GPy.likelihoods.noise_model_constructors.student_t(deg_free=df, sigma2=noise)
|
||||||
stu_t_likelihood = GPy.likelihoods.Laplace(Y_train.copy(), t_distribution)
|
stu_t_likelihood = GPy.likelihoods.Laplace(Y_train.copy(), t_distribution)
|
||||||
mstu_t = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelstu.copy(), likelihood=stu_t_likelihood)
|
mstu_t = GPy.models.GPRegression(X_train.copy(), Y_train.copy(), kernel=kernelstu.copy(), likelihood=stu_t_likelihood)
|
||||||
mstu_t.ensure_default_constraints()
|
|
||||||
mstu_t.constrain_fixed('white', 1e-5)
|
mstu_t.constrain_fixed('white', 1e-5)
|
||||||
mstu_t.constrain_bounded('t_noise', 0.0001, 1000)
|
mstu_t.constrain_bounded('t_noise', 0.0001, 1000)
|
||||||
mstu_t['rbf_len'] = rbf_len
|
mstu_t['rbf_len'] = rbf_len
|
||||||
|
|
|
||||||
|
|
@ -473,7 +473,6 @@ def uncertain_inputs_sparse_regression(max_iters=200, optimize=True, plot=True):
|
||||||
Z = np.random.uniform(-3., 3., (7, 1))
|
Z = np.random.uniform(-3., 3., (7, 1))
|
||||||
|
|
||||||
k = GPy.kern.rbf(1)
|
k = GPy.kern.rbf(1)
|
||||||
import ipdb;ipdb.set_trace()
|
|
||||||
# create simple GP Model - no input uncertainty on this one
|
# create simple GP Model - no input uncertainty on this one
|
||||||
m = GPy.models.SparseGPRegression(X, Y, kernel=GPy.kern.rbf(1), Z=Z)
|
m = GPy.models.SparseGPRegression(X, Y, kernel=GPy.kern.rbf(1), Z=Z)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ prior over a finite set of points f. This prior is
|
||||||
where K is the kernel matrix.
|
where K is the kernel matrix.
|
||||||
|
|
||||||
We also have a likelihood (see GPy.likelihoods) which defines how the data are
|
We also have a likelihood (see GPy.likelihoods) which defines how the data are
|
||||||
related to the latent function: p(y | f). If the likelihood is also a Gaussian,
|
related to the latent function: p(y | f). If the likelihood is also a Gaussian,
|
||||||
the inference over f is tractable (see exact_gaussian_inference.py).
|
the inference over f is tractable (see exact_gaussian_inference.py).
|
||||||
|
|
||||||
If the likelihood object is something other than Gaussian, then exact inference
|
If the likelihood object is something other than Gaussian, then exact inference
|
||||||
is not tractable. We then resort to a Laplace approximation (laplace.py) or
|
is not tractable. We then resort to a Laplace approximation (laplace.py) or
|
||||||
expectation propagation (ep.py).
|
expectation propagation (ep.py).
|
||||||
|
|
||||||
The inference methods return a "Posterior" instance, which is a simple
|
The inference methods return a "Posterior" instance, which is a simple
|
||||||
structure which contains a summary of the posterior. The model classes can then
|
structure which contains a summary of the posterior. The model classes can then
|
||||||
|
|
@ -24,5 +24,8 @@ etc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from exact_gaussian_inference import ExactGaussianInference
|
from exact_gaussian_inference import ExactGaussianInference
|
||||||
from laplace import LaplaceInference
|
from laplace import Laplace
|
||||||
expectation_propagation = 'foo' # TODO
|
expectation_propagation = 'foo' # TODO
|
||||||
|
from varDTC import VarDTC
|
||||||
|
from dtc import DTC
|
||||||
|
from fitc import FITC
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ class DTC(object):
|
||||||
def inference(self, kern, X, X_variance, Z, likelihood, Y):
|
def inference(self, kern, X, X_variance, Z, likelihood, Y):
|
||||||
assert X_variance is None, "cannot use X_variance with DTC. Try varDTC."
|
assert X_variance is None, "cannot use X_variance with DTC. Try varDTC."
|
||||||
|
|
||||||
|
#TODO: MAX! fix this!
|
||||||
|
from ...util.misc import param_to_array
|
||||||
|
Y = param_to_array(Y)
|
||||||
|
|
||||||
num_inducing, _ = Z.shape
|
num_inducing, _ = Z.shape
|
||||||
num_data, output_dim = Y.shape
|
num_data, output_dim = Y.shape
|
||||||
|
|
||||||
|
|
@ -40,9 +44,8 @@ class DTC(object):
|
||||||
Kmmi, L, Li, _ = pdinv(Kmm)
|
Kmmi, L, Li, _ = pdinv(Kmm)
|
||||||
|
|
||||||
# Compute A
|
# Compute A
|
||||||
LiUT, _ = dtrtrs(L, U.T*np.sqrt(beta), lower=1)
|
LiUTbeta = np.dot(Li, U.T)*np.sqrt(beta)
|
||||||
A_I = tdot(LiUT)
|
A = tdot(LiUTbeta) + np.eye(num_inducing)
|
||||||
A = A_I + np.eye(num_inducing)
|
|
||||||
|
|
||||||
# factor A
|
# factor A
|
||||||
LA = jitchol(A)
|
LA = jitchol(A)
|
||||||
|
|
@ -52,44 +55,37 @@ class DTC(object):
|
||||||
b, _ = dtrtrs(LA, tmp*beta, lower=1)
|
b, _ = dtrtrs(LA, tmp*beta, lower=1)
|
||||||
tmp, _ = dtrtrs(LA, b, lower=1, trans=1)
|
tmp, _ = dtrtrs(LA, b, lower=1, trans=1)
|
||||||
v, _ = dtrtrs(L, tmp, lower=1, trans=1)
|
v, _ = dtrtrs(L, tmp, lower=1, trans=1)
|
||||||
tmp = tdrtrs(LA, Li, lower=1, trans=0)
|
tmp, _ = dtrtrs(LA, Li, lower=1, trans=0)
|
||||||
P = tdot(tmp.T)
|
P = tdot(tmp.T)
|
||||||
|
|
||||||
#compute log marginal
|
#compute log marginal
|
||||||
log_marginal = -0.5*num_data*output_dim*np.log(2*np.pi) + \
|
log_marginal = -0.5*num_data*output_dim*np.log(2*np.pi) + \
|
||||||
-np.sum(np.log(np.diag(LA)))*output_dim + \
|
-np.sum(np.log(np.diag(LA)))*output_dim + \
|
||||||
0.5*num_data*output_dim*np.log(beta) + \
|
0.5*num_data*output_dim*np.log(beta) + \
|
||||||
-0.5*beta*np.sum(np.square(Y)) +
|
-0.5*beta*np.sum(np.square(Y)) + \
|
||||||
0.5*np.sum(np.square(b))
|
0.5*np.sum(np.square(b))
|
||||||
|
|
||||||
# Compute dL_dKmm
|
# Compute dL_dKmm
|
||||||
tmp, _ = dtrtrs(L, A_I, lower=1, trans=1)
|
vvT_P = tdot(v.reshape(-1,1)) + P
|
||||||
dL_dK, _ = dtrtrs(L, tmp.T, lower=1, trans=0)
|
dL_dK = 0.5*(Kmmi - vvT_P)
|
||||||
tmp, _ = dtrtrs(LA, tmp.T. lower=1, trans=1)
|
|
||||||
dL_dK -= tdot(tmp.T)
|
|
||||||
dL_dK *= output_dim
|
|
||||||
dL_dK -= tdot(v)
|
|
||||||
dL_dK /=2.
|
|
||||||
|
|
||||||
# Compute dL_dU
|
# Compute dL_dU
|
||||||
vvT_P = tdot(v.reshape(-1,1)) + P
|
|
||||||
vY = np.dot(v.reshape(-1,1),Y.T)
|
vY = np.dot(v.reshape(-1,1),Y.T)
|
||||||
dL_dU = vY + np.dot(vvT_P, U.T)
|
dL_dU = vY - np.dot(vvT_P, U.T)
|
||||||
dL_dU *= beta
|
dL_dU *= beta
|
||||||
|
|
||||||
#compute dL_dR
|
#compute dL_dR
|
||||||
Uv = np.dot(U, v)
|
Uv = np.dot(U, v)
|
||||||
dL_dR = 0.5*(np.sum(U*np.dot(P, U.T), 1) - beta * np.sum(np.square(Y, 1)) - 2.*np.sum(Uv*Y, 1) + np.sum(np.square(Uv), 1)
|
dL_dR = 0.5*(np.sum(U*np.dot(U,P), 1) - 1./beta + np.sum(np.square(Y), 1) - 2.*np.sum(Uv*Y, 1) + np.sum(np.square(Uv), 1))*beta**2
|
||||||
)*beta**2
|
|
||||||
|
|
||||||
grad_dict = {'dL_dKmm': dL_dKmm, 'dL_dKdiag':np.zeros_like(Knn), 'dL_dKnm':dL_dU}
|
grad_dict = {'dL_dKmm': dL_dK, 'dL_dKdiag':np.zeros_like(Knn), 'dL_dKnm':dL_dU.T}
|
||||||
|
|
||||||
#update gradients
|
#update gradients
|
||||||
kern.update_gradients_sparse(X=X, Z=Z, **grad_dict)
|
kern.update_gradients_sparse(X=X, Z=Z, **grad_dict)
|
||||||
likelihood.update_gradients(dL_dR)
|
likelihood.update_gradients(dL_dR)
|
||||||
|
|
||||||
#construct a posterior object
|
#construct a posterior object
|
||||||
post = Posterior(woodbury_inv=Kmmi-P, woodbury_vector=v, K=Kmm, mean=None, cov=None, K_chol=Lm)
|
post = Posterior(woodbury_inv=Kmmi-P, woodbury_vector=v, K=Kmm, mean=None, cov=None, K_chol=L)
|
||||||
|
|
||||||
return post, log_marginal, grad_dict
|
return post, log_marginal, grad_dict
|
||||||
|
|
||||||
|
|
@ -1,225 +1,95 @@
|
||||||
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
# Copyright (c) 2012, James Hensman
|
||||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
|
|
||||||
class VarDTC(object):
|
from posterior import Posterior
|
||||||
|
from ...util.linalg import jitchol, tdot, dtrtrs, dpotri, pdinv
|
||||||
|
import numpy as np
|
||||||
|
log_2_pi = np.log(2*np.pi)
|
||||||
|
|
||||||
|
class FITC(object):
|
||||||
|
"""
|
||||||
|
An object for inference when the likelihood is Gaussian, but we want to do sparse inference.
|
||||||
|
|
||||||
|
The function self.inference returns a Posterior object, which summarizes
|
||||||
|
the posterior.
|
||||||
|
|
||||||
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.const_jitter = 1e-6
|
self.const_jitter = 1e-6
|
||||||
|
|
||||||
def inference(self, kern, X, X_variance, Z, likelihood, Y):
|
def inference(self, kern, X, X_variance, Z, likelihood, Y):
|
||||||
|
assert X_variance is None, "cannot use X_variance with FITC. Try varDTC."
|
||||||
|
|
||||||
|
#TODO: MAX! fix this!
|
||||||
|
from ...util.misc import param_to_array
|
||||||
|
Y = param_to_array(Y)
|
||||||
|
|
||||||
num_inducing, _ = Z.shape
|
num_inducing, _ = Z.shape
|
||||||
num_data, output_dim = Y.shape
|
num_data, output_dim = Y.shape
|
||||||
|
|
||||||
#make sure we're not using variational uncertain inputs
|
#make sure the noise is not hetero
|
||||||
assert = X_variance is None, "variational inducing inputs only for use with varDTC inference"
|
sigma_n = np.squeeze(likelihood.variance)
|
||||||
#Note: we can;t do the variational thing after making the GITC conditional approximation because K~ appears in the log determinant.
|
if sigma_n.size <1:
|
||||||
|
raise NotImplementedError, "no hetero noise with this implementation of FITC"
|
||||||
|
|
||||||
#see whether we've got a different noise variance for each datum
|
|
||||||
sigma2 = np.squeeze(likelihood.variance)
|
|
||||||
het_noise = False
|
|
||||||
if sigma2.size <1:
|
|
||||||
het_noise = True
|
|
||||||
|
|
||||||
# kernel computations, using BGPLVM notation
|
|
||||||
Kmm = kern.K(Z)
|
Kmm = kern.K(Z)
|
||||||
Kdiag = kern.Kdiag(X)
|
Knn = kern.Kdiag(X)
|
||||||
Kmn = kern.K(X, Z)
|
Knm = kern.K(X, Z)
|
||||||
|
U = Knm
|
||||||
|
|
||||||
#factor Kmm
|
#factor Kmm
|
||||||
Lm = jitchol(Kmm)
|
Kmmi, L, Li, _ = pdinv(Kmm)
|
||||||
V = dtrtrs(Lm, Kmn, lower=1)
|
|
||||||
|
|
||||||
#compute effective noise
|
#compute beta_star, the effective noise precision
|
||||||
g_sn2 = sigma2 + Kdiag - np.sum(V*V, 0)
|
LiUT = np.dot(Li, U.T)
|
||||||
|
sigma_star = Knn + sigma_n - np.sum(np.square(LiUT),0)
|
||||||
|
beta_star = 1./sigma_star
|
||||||
|
|
||||||
#compute and factor B
|
# Compute and factor A
|
||||||
tmp = Kmn / np.sqrt(g_snd)
|
A = tdot(LiUT*np.sqrt(beta_star)) + np.eye(num_inducing)
|
||||||
tmp, _ = dtrtrs(Lm, tmp, lower=1)
|
LA = jitchol(A)
|
||||||
A = tdot(tmp)
|
|
||||||
B = np.eye(num_inducing) + A
|
|
||||||
Bi, Lb, LBi, log_det_B = pdinv(B)
|
|
||||||
|
|
||||||
#compute posterior parameters
|
# back substutue to get b, P, v
|
||||||
tmp, _ = dtrtrs()
|
URiy = np.dot(U.T*beta_star,Y)
|
||||||
woodbury_vec =
|
tmp, _ = dtrtrs(L, URiy, lower=1)
|
||||||
|
b, _ = dtrtrs(LA, tmp, lower=1)
|
||||||
|
tmp, _ = dtrtrs(LA, b, lower=1, trans=1)
|
||||||
|
v, _ = dtrtrs(L, tmp, lower=1, trans=1)
|
||||||
|
tmp, _ = dtrtrs(LA, Li, lower=1, trans=0)
|
||||||
|
P = tdot(tmp.T)
|
||||||
|
|
||||||
|
#compute log marginal
|
||||||
|
log_marginal = -0.5*num_data*output_dim*np.log(2*np.pi) + \
|
||||||
|
-np.sum(np.log(np.diag(LA)))*output_dim + \
|
||||||
|
0.5*output_dim*np.sum(np.log(beta_star)) + \
|
||||||
|
-0.5*np.sum(np.square(Y.T*np.sqrt(beta_star))) + \
|
||||||
|
0.5*np.sum(np.square(b))
|
||||||
|
#compute dL_dR
|
||||||
|
Uv = np.dot(U, v)
|
||||||
|
dL_dR = 0.5*(np.sum(U*np.dot(U,P), 1) - 1./beta_star + np.sum(np.square(Y), 1) - 2.*np.sum(Uv*Y, 1) + np.sum(np.square(Uv), 1))*beta_star**2
|
||||||
|
|
||||||
|
|
||||||
psi1V = np.dot(self.psi1, self.V_star)
|
# Compute dL_dKmm
|
||||||
Lmi_psi1V, _ = dtrtrs(Lm, self.psi1V, lower=1, trans=0)
|
vvT_P = tdot(v.reshape(-1,1)) + P
|
||||||
LBi_Lmi_psi1V, _ = dtrtrs(LB, Lmi_psi1V, lower=1, trans=0)
|
dL_dK = 0.5*(Kmmi - vvT_P)
|
||||||
|
KiU = np.dot(Kmmi, U.T)
|
||||||
|
dL_dK += np.dot(KiU*dL_dR, KiU.T)
|
||||||
|
|
||||||
Kmmipsi1 = np.dot(self.Lmi.T,Lmipsi1)
|
# Compute dL_dU
|
||||||
b_psi1_Ki = self.beta_star * Kmmipsi1.T
|
vY = np.dot(v.reshape(-1,1),Y.T)
|
||||||
Ki_pbp_Ki = np.dot(Kmmipsi1,b_psi1_Ki)
|
dL_dU = vY - np.dot(vvT_P, U.T)
|
||||||
Kmmi = np.dot(self.Lmi.T,self.Lmi)
|
dL_dU *= beta_star
|
||||||
LBiLmi = np.dot(self.LBi,self.Lmi)
|
dL_dU -= 2.*KiU*dL_dR
|
||||||
LBL_inv = np.dot(LBiLmi.T,LBiLmi)
|
|
||||||
VVT = np.outer(self.V_star,self.V_star)
|
|
||||||
VV_p_Ki = np.dot(VVT,Kmmipsi1.T)
|
|
||||||
Ki_pVVp_Ki = np.dot(Kmmipsi1,VV_p_Ki)
|
|
||||||
psi1beta = self.psi1*self.beta_star.T
|
|
||||||
H = self.Kmm + mdot(self.psi1,psi1beta.T)
|
|
||||||
LH = jitchol(H)
|
|
||||||
LHi = chol_inv(LH)
|
|
||||||
Hi = np.dot(LHi.T,LHi)
|
|
||||||
|
|
||||||
betapsi1TLmiLBi = np.dot(psi1beta.T,LBiLmi.T)
|
grad_dict = {'dL_dKmm': dL_dK, 'dL_dKdiag':dL_dR, 'dL_dKnm':dL_dU.T}
|
||||||
alpha = np.array([np.dot(a.T,a) for a in betapsi1TLmiLBi])[:,None]
|
|
||||||
gamma_1 = mdot(VVT,self.psi1.T,Hi)
|
|
||||||
pHip = mdot(self.psi1.T,Hi,self.psi1)
|
|
||||||
gamma_2 = mdot(self.beta_star*pHip,self.V_star)
|
|
||||||
gamma_3 = self.V_star * gamma_2
|
|
||||||
|
|
||||||
self._dL_dpsi0 = -0.5 * self.beta_star#dA_dpsi0: logdet(self.beta_star)
|
#update gradients
|
||||||
self._dL_dpsi0 += .5 * self.V_star**2 #dA_psi0: yT*beta_star*y
|
kern.update_gradients_sparse(X=X, Z=Z, **grad_dict)
|
||||||
self._dL_dpsi0 += .5 *alpha #dC_dpsi0
|
likelihood.update_gradients(dL_dR)
|
||||||
self._dL_dpsi0 += 0.5*mdot(self.beta_star*pHip,self.V_star)**2 - self.V_star * mdot(self.V_star.T,pHip*self.beta_star).T #dD_dpsi0
|
|
||||||
|
|
||||||
self._dL_dpsi1 = b_psi1_Ki.copy() #dA_dpsi1: logdet(self.beta_star)
|
#construct a posterior object
|
||||||
self._dL_dpsi1 += -np.dot(psi1beta.T,LBL_inv) #dC_dpsi1
|
post = Posterior(woodbury_inv=Kmmi-P, woodbury_vector=v, K=Kmm, mean=None, cov=None, K_chol=L)
|
||||||
self._dL_dpsi1 += gamma_1 - mdot(psi1beta.T,Hi,self.psi1,gamma_1) #dD_dpsi1
|
|
||||||
|
|
||||||
self._dL_dKmm = -0.5 * np.dot(Kmmipsi1,b_psi1_Ki) #dA_dKmm: logdet(self.beta_star)
|
return post, log_marginal, grad_dict
|
||||||
self._dL_dKmm += .5*(LBL_inv - Kmmi) + mdot(LBL_inv,psi1beta,Kmmipsi1.T) #dC_dKmm
|
|
||||||
self._dL_dKmm += -.5 * mdot(Hi,self.psi1,gamma_1) #dD_dKmm
|
|
||||||
|
|
||||||
self._dpsi1_dtheta = 0
|
|
||||||
self._dpsi1_dX = 0
|
|
||||||
self._dKmm_dtheta = 0
|
|
||||||
self._dKmm_dX = 0
|
|
||||||
|
|
||||||
self._dpsi1_dX_jkj = 0
|
|
||||||
self._dpsi1_dtheta_jkj = 0
|
|
||||||
|
|
||||||
for i,V_n,alpha_n,gamma_n,gamma_k in zip(range(self.num_data),self.V_star,alpha,gamma_2,gamma_3):
|
|
||||||
K_pp_K = np.dot(Kmmipsi1[:,i:(i+1)],Kmmipsi1[:,i:(i+1)].T)
|
|
||||||
_dpsi1 = (-V_n**2 - alpha_n + 2.*gamma_k - gamma_n**2) * Kmmipsi1.T[i:(i+1),:]
|
|
||||||
_dKmm = .5*(V_n**2 + alpha_n + gamma_n**2 - 2.*gamma_k) * K_pp_K #Diag_dD_dKmm
|
|
||||||
self._dpsi1_dtheta += self.kern._param_grad_helper(_dpsi1,self.X[i:i+1,:],self.Z)
|
|
||||||
self._dKmm_dtheta += self.kern._param_grad_helper(_dKmm,self.Z)
|
|
||||||
self._dKmm_dX += self.kern.gradients_X(_dKmm ,self.Z)
|
|
||||||
self._dpsi1_dX += self.kern.gradients_X(_dpsi1.T,self.Z,self.X[i:i+1,:])
|
|
||||||
|
|
||||||
# the partial derivative vector for the likelihood
|
|
||||||
if self.likelihood.num_params == 0:
|
|
||||||
# save computation here.
|
|
||||||
self.partial_for_likelihood = None
|
|
||||||
elif self.likelihood.is_heteroscedastic:
|
|
||||||
raise NotImplementedError, "heteroscedatic derivates not implemented."
|
|
||||||
else:
|
|
||||||
# likelihood is not heterscedatic
|
|
||||||
dbstar_dnoise = self.likelihood.precision * (self.beta_star**2 * self.Diag0[:,None] - self.beta_star)
|
|
||||||
Lmi_psi1 = mdot(self.Lmi,self.psi1)
|
|
||||||
LBiLmipsi1 = np.dot(self.LBi,Lmi_psi1)
|
|
||||||
aux_0 = np.dot(self._LBi_Lmi_psi1V.T,LBiLmipsi1)
|
|
||||||
aux_1 = self.likelihood.Y.T * np.dot(self._LBi_Lmi_psi1V.T,LBiLmipsi1)
|
|
||||||
aux_2 = np.dot(LBiLmipsi1.T,self._LBi_Lmi_psi1V)
|
|
||||||
|
|
||||||
dA_dnoise = 0.5 * self.input_dim * (dbstar_dnoise/self.beta_star).sum() - 0.5 * self.input_dim * np.sum(self.likelihood.Y**2 * dbstar_dnoise)
|
|
||||||
dC_dnoise = -0.5 * np.sum(mdot(self.LBi.T,self.LBi,Lmi_psi1) * Lmi_psi1 * dbstar_dnoise.T)
|
|
||||||
|
|
||||||
dD_dnoise_1 = mdot(self.V_star*LBiLmipsi1.T,LBiLmipsi1*dbstar_dnoise.T*self.likelihood.Y.T)
|
|
||||||
alpha = mdot(LBiLmipsi1,self.V_star)
|
|
||||||
alpha_ = mdot(LBiLmipsi1.T,alpha)
|
|
||||||
dD_dnoise_2 = -0.5 * self.input_dim * np.sum(alpha_**2 * dbstar_dnoise )
|
|
||||||
|
|
||||||
dD_dnoise_1 = mdot(self.V_star.T,self.psi1.T,self.Lmi.T,self.LBi.T,self.LBi,self.Lmi,self.psi1,dbstar_dnoise*self.likelihood.Y)
|
|
||||||
dD_dnoise_2 = 0.5*mdot(self.V_star.T,self.psi1.T,Hi,self.psi1,dbstar_dnoise*self.psi1.T,Hi,self.psi1,self.V_star)
|
|
||||||
dD_dnoise = dD_dnoise_1 + dD_dnoise_2
|
|
||||||
|
|
||||||
self.partial_for_likelihood = dA_dnoise + dC_dnoise + dD_dnoise
|
|
||||||
|
|
||||||
def log_likelihood(self):
|
|
||||||
""" Compute the (lower bound on the) log marginal likelihood """
|
|
||||||
A = -0.5 * self.num_data * self.output_dim * np.log(2.*np.pi) + 0.5 * np.sum(np.log(self.beta_star)) - 0.5 * np.sum(self.V_star * self.likelihood.Y)
|
|
||||||
C = -self.output_dim * (np.sum(np.log(np.diag(self.LB))))
|
|
||||||
D = 0.5 * np.sum(np.square(self._LBi_Lmi_psi1V))
|
|
||||||
return A + C + D
|
|
||||||
|
|
||||||
def _log_likelihood_gradients(self):
|
|
||||||
pass
|
|
||||||
return np.hstack((self.dL_dZ().flatten(), self.dL_dtheta(), self.likelihood._gradients(partial=self.partial_for_likelihood)))
|
|
||||||
|
|
||||||
def dL_dtheta(self):
|
|
||||||
dL_dtheta = self.kern.dKdiag_dtheta(self._dL_dpsi0,self.X)
|
|
||||||
dL_dtheta += self.kern._param_grad_helper(self._dL_dpsi1,self.X,self.Z)
|
|
||||||
dL_dtheta += self.kern._param_grad_helper(self._dL_dKmm,X=self.Z)
|
|
||||||
dL_dtheta += self._dKmm_dtheta
|
|
||||||
dL_dtheta += self._dpsi1_dtheta
|
|
||||||
return dL_dtheta
|
|
||||||
|
|
||||||
def dL_dZ(self):
|
|
||||||
dL_dZ = self.kern.gradients_X(self._dL_dpsi1.T,self.Z,self.X)
|
|
||||||
dL_dZ += self.kern.gradients_X(self._dL_dKmm,X=self.Z)
|
|
||||||
dL_dZ += self._dpsi1_dX
|
|
||||||
dL_dZ += self._dKmm_dX
|
|
||||||
return dL_dZ
|
|
||||||
|
|
||||||
def _raw_predict(self, Xnew, X_variance_new=None, which_parts='all', full_cov=False):
|
|
||||||
assert X_variance_new is None, "FITC model is not defined for handling uncertain inputs."
|
|
||||||
|
|
||||||
if self.likelihood.is_heteroscedastic:
|
|
||||||
Iplus_Dprod_i = 1./(1.+ self.Diag0 * self.likelihood.precision.flatten())
|
|
||||||
self.Diag = self.Diag0 * Iplus_Dprod_i
|
|
||||||
self.P = Iplus_Dprod_i[:,None] * self.psi1.T
|
|
||||||
self.RPT0 = np.dot(self.Lmi,self.psi1)
|
|
||||||
self.L = np.linalg.cholesky(np.eye(self.num_inducing) + np.dot(self.RPT0,((1. - Iplus_Dprod_i)/self.Diag0)[:,None]*self.RPT0.T))
|
|
||||||
self.R,info = dtrtrs(self.L,self.Lmi,lower=1)
|
|
||||||
self.RPT = np.dot(self.R,self.P.T)
|
|
||||||
self.Sigma = np.diag(self.Diag) + np.dot(self.RPT.T,self.RPT)
|
|
||||||
self.w = self.Diag * self.likelihood.v_tilde
|
|
||||||
self.Gamma = np.dot(self.R.T, np.dot(self.RPT,self.likelihood.v_tilde))
|
|
||||||
self.mu = self.w + np.dot(self.P,self.Gamma)
|
|
||||||
|
|
||||||
"""
|
|
||||||
Make a prediction for the generalized FITC model
|
|
||||||
|
|
||||||
Arguments
|
|
||||||
---------
|
|
||||||
X : Input prediction data - Nx1 numpy array (floats)
|
|
||||||
"""
|
|
||||||
# q(u|f) = N(u| R0i*mu_u*f, R0i*C*R0i.T)
|
|
||||||
|
|
||||||
# Ci = I + (RPT0)Di(RPT0).T
|
|
||||||
# C = I - [RPT0] * (input_dim+[RPT0].T*[RPT0])^-1*[RPT0].T
|
|
||||||
# = I - [RPT0] * (input_dim + self.Qnn)^-1 * [RPT0].T
|
|
||||||
# = I - [RPT0] * (U*U.T)^-1 * [RPT0].T
|
|
||||||
# = I - V.T * V
|
|
||||||
U = np.linalg.cholesky(np.diag(self.Diag0) + self.Qnn)
|
|
||||||
V,info = dtrtrs(U,self.RPT0.T,lower=1)
|
|
||||||
C = np.eye(self.num_inducing) - np.dot(V.T,V)
|
|
||||||
mu_u = np.dot(C,self.RPT0)*(1./self.Diag0[None,:])
|
|
||||||
#self.C = C
|
|
||||||
#self.RPT0 = np.dot(self.R0,self.Knm.T) P0.T
|
|
||||||
#self.mu_u = mu_u
|
|
||||||
#self.U = U
|
|
||||||
# q(u|y) = N(u| R0i*mu_H,R0i*Sigma_H*R0i.T)
|
|
||||||
mu_H = np.dot(mu_u,self.mu)
|
|
||||||
self.mu_H = mu_H
|
|
||||||
Sigma_H = C + np.dot(mu_u,np.dot(self.Sigma,mu_u.T))
|
|
||||||
# q(f_star|y) = N(f_star|mu_star,sigma2_star)
|
|
||||||
Kx = self.kern.K(self.Z, Xnew, which_parts=which_parts)
|
|
||||||
KR0T = np.dot(Kx.T,self.Lmi.T)
|
|
||||||
mu_star = np.dot(KR0T,mu_H)
|
|
||||||
if full_cov:
|
|
||||||
Kxx = self.kern.K(Xnew,which_parts=which_parts)
|
|
||||||
var = Kxx + np.dot(KR0T,np.dot(Sigma_H - np.eye(self.num_inducing),KR0T.T))
|
|
||||||
else:
|
|
||||||
Kxx = self.kern.Kdiag(Xnew,which_parts=which_parts)
|
|
||||||
var = (Kxx + np.sum(KR0T.T*np.dot(Sigma_H - np.eye(self.num_inducing),KR0T.T),0))[:,None]
|
|
||||||
return mu_star[:,None],var
|
|
||||||
else:
|
|
||||||
raise NotImplementedError, "Heteroscedastic case not implemented."
|
|
||||||
"""
|
|
||||||
Kx = self.kern.K(self.Z, Xnew)
|
|
||||||
mu = mdot(Kx.T, self.C/self.scale_factor, self.psi1V)
|
|
||||||
if full_cov:
|
|
||||||
Kxx = self.kern.K(Xnew)
|
|
||||||
var = Kxx - mdot(Kx.T, (self.Kmmi - self.C/self.scale_factor**2), Kx) #NOTE this won't work for plotting
|
|
||||||
else:
|
|
||||||
Kxx = self.kern.Kdiag(Xnew)
|
|
||||||
var = Kxx - np.sum(Kx*np.dot(self.Kmmi - self.C/self.scale_factor**2, Kx),0)
|
|
||||||
return mu,var[:,None]
|
|
||||||
"""
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from posterior import Posterior
|
||||||
import warnings
|
import warnings
|
||||||
from scipy import optimize
|
from scipy import optimize
|
||||||
|
|
||||||
class LaplaceInference(object):
|
class Laplace(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -52,6 +52,7 @@ class LaplaceInference(object):
|
||||||
|
|
||||||
f_hat, Ki_fhat = self.rasm_mode(K, Y, likelihood, Ki_f_init, Y_metadata=Y_metadata)
|
f_hat, Ki_fhat = self.rasm_mode(K, Y, likelihood, Ki_f_init, Y_metadata=Y_metadata)
|
||||||
|
|
||||||
|
self.f_hat = f_hat
|
||||||
#Compute hessian and other variables at mode
|
#Compute hessian and other variables at mode
|
||||||
log_marginal, woodbury_vector, woodbury_inv, dL_dK, dL_dthetaL = self.mode_computations(f_hat, Ki_fhat, K, Y, likelihood, kern, Y_metadata)
|
log_marginal, woodbury_vector, woodbury_inv, dL_dK, dL_dthetaL = self.mode_computations(f_hat, Ki_fhat, K, Y, likelihood, kern, Y_metadata)
|
||||||
|
|
||||||
|
|
@ -92,12 +93,11 @@ class LaplaceInference(object):
|
||||||
iteration = 0
|
iteration = 0
|
||||||
while difference > self._mode_finding_tolerance and iteration < self._mode_finding_max_iter:
|
while difference > self._mode_finding_tolerance and iteration < self._mode_finding_max_iter:
|
||||||
W = -likelihood.d2logpdf_df2(f, Y, extra_data=Y_metadata)
|
W = -likelihood.d2logpdf_df2(f, Y, extra_data=Y_metadata)
|
||||||
|
|
||||||
W_f = W*f
|
|
||||||
grad = likelihood.dlogpdf_df(f, Y, extra_data=Y_metadata)
|
grad = likelihood.dlogpdf_df(f, Y, extra_data=Y_metadata)
|
||||||
|
|
||||||
|
W_f = W*f
|
||||||
|
|
||||||
b = W_f + grad # R+W p46 line 6.
|
b = W_f + grad # R+W p46 line 6.
|
||||||
#W12BiW12Kb, B_logdet = self._compute_B_statistics(K, W.copy(), np.dot(K, b), likelihood.log_concave)
|
|
||||||
W12BiW12, _, _ = self._compute_B_statistics(K, W, likelihood.log_concave)
|
W12BiW12, _, _ = self._compute_B_statistics(K, W, likelihood.log_concave)
|
||||||
W12BiW12Kb = np.dot(W12BiW12, np.dot(K, b))
|
W12BiW12Kb = np.dot(W12BiW12, np.dot(K, b))
|
||||||
|
|
||||||
|
|
@ -216,7 +216,9 @@ class LaplaceInference(object):
|
||||||
"""
|
"""
|
||||||
if not log_concave:
|
if not log_concave:
|
||||||
#print "Under 1e-10: {}".format(np.sum(W < 1e-6))
|
#print "Under 1e-10: {}".format(np.sum(W < 1e-6))
|
||||||
W[W < 1e-6] = 1e-6 # FIXME-HACK: This is a hack since GPy can't handle negative variances which can occur
|
# W[W<1e-6] = 1e-6
|
||||||
|
# NOTE: when setting a parameter inside parameters_changed it will allways come to closed update circles!!!
|
||||||
|
W.__setitem__(W < 1e-6, 1e-6, update=False) # FIXME-HACK: This is a hack since GPy can't handle negative variances which can occur
|
||||||
# If the likelihood is non-log-concave. We wan't to say that there is a negative variance
|
# If the likelihood is non-log-concave. We wan't to say that there is a negative variance
|
||||||
# To cause the posterior to become less certain than the prior and likelihood,
|
# To cause the posterior to become less certain than the prior and likelihood,
|
||||||
# This is a property only held by non-log-concave likelihoods
|
# This is a property only held by non-log-concave likelihoods
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# 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
|
||||||
from ...util.linalg import pdinv, dpotrs, tdot, dtrtrs, dpotri, symmetrify
|
from ...util.linalg import pdinv, dpotrs, tdot, dtrtrs, dpotri, symmetrify, jitchol, dtrtri
|
||||||
|
|
||||||
class Posterior(object):
|
class Posterior(object):
|
||||||
"""
|
"""
|
||||||
|
|
@ -80,8 +80,8 @@ class Posterior(object):
|
||||||
@property
|
@property
|
||||||
def covariance(self):
|
def covariance(self):
|
||||||
if self._covariance is None:
|
if self._covariance is None:
|
||||||
LiK, _ = dtrtrs(self.woodbury_chol, self._K, lower=1)
|
#LiK, _ = dtrtrs(self.woodbury_chol, self._K, lower=1)
|
||||||
self._covariance = self._K - tdot(LiK.T)
|
self._covariance = self._K - self._K.dot(self.woodbury_inv).dot(self._K)
|
||||||
return self._covariance
|
return self._covariance
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -93,20 +93,30 @@ class Posterior(object):
|
||||||
@property
|
@property
|
||||||
def woodbury_chol(self):
|
def woodbury_chol(self):
|
||||||
if self._woodbury_chol is None:
|
if self._woodbury_chol is None:
|
||||||
#try computing woodbury chol from cov
|
#compute woodbury chol from
|
||||||
if self._woodbury_inv is not None:
|
if self._woodbury_inv is not None:
|
||||||
_, _, self._woodbury_chol, _ = pdinv(self._woodbury_inv)
|
_, _, self._woodbury_chol, _ = pdinv(self._woodbury_inv)
|
||||||
|
#Li = jitchol(self._woodbury_inv)
|
||||||
|
#self._woodbury_chol, _ = dtrtri(Li)
|
||||||
|
#W, _, _, _, = pdinv(self._woodbury_inv)
|
||||||
|
#symmetrify(W)
|
||||||
|
#self._woodbury_chol = jitchol(W)
|
||||||
|
#try computing woodbury chol from cov
|
||||||
elif self._covariance is not None:
|
elif self._covariance is not None:
|
||||||
|
raise NotImplementedError, "TODO: check code here"
|
||||||
B = self._K - self._covariance
|
B = self._K - self._covariance
|
||||||
tmp, _ = dpotrs(self.K_chol, B)
|
tmp, _ = dpotrs(self.K_chol, B)
|
||||||
self._woodbury_inv, _ = dpotrs(self.K_chol, tmp.T)
|
self._woodbury_inv, _ = dpotrs(self.K_chol, tmp.T)
|
||||||
_, _, self._woodbury_chol, _ = pdinv(self._woodbury_inv)
|
_, _, self._woodbury_chol, _ = pdinv(self._woodbury_inv)
|
||||||
|
else:
|
||||||
|
raise ValueError, "insufficient information to compute posterior"
|
||||||
return self._woodbury_chol
|
return self._woodbury_chol
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def woodbury_inv(self):
|
def woodbury_inv(self):
|
||||||
if self._woodbury_inv is None:
|
if self._woodbury_inv is None:
|
||||||
self._woodbury_inv, _ = dpotri(self.woodbury_chol)
|
self._woodbury_inv, _ = dpotri(self.woodbury_chol, lower=1)
|
||||||
|
#self._woodbury_inv, _ = dpotrs(self.woodbury_chol, np.eye(self.woodbury_chol.shape[0]), lower=1)
|
||||||
symmetrify(self._woodbury_inv)
|
symmetrify(self._woodbury_inv)
|
||||||
return self._woodbury_inv
|
return self._woodbury_inv
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ class VarDTC(object):
|
||||||
Note that L may have fewer columns than Y.
|
Note that L may have fewer columns than Y.
|
||||||
"""
|
"""
|
||||||
N, D = Y.shape
|
N, D = Y.shape
|
||||||
if (N>D):
|
if (N>=D):
|
||||||
return param_to_array(Y)
|
return param_to_array(Y)
|
||||||
else:
|
else:
|
||||||
return jitchol(tdot(Y))
|
return jitchol(tdot(Y))
|
||||||
|
|
@ -91,7 +91,7 @@ class VarDTC(object):
|
||||||
tmp = psi1 * (np.sqrt(beta.reshape(num_data, 1)))
|
tmp = psi1 * (np.sqrt(beta.reshape(num_data, 1)))
|
||||||
else:
|
else:
|
||||||
tmp = psi1 * (np.sqrt(beta))
|
tmp = psi1 * (np.sqrt(beta))
|
||||||
tmp, _ = dtrtrs(Lm, np.asfortranarray(tmp.T), lower=1)
|
tmp, _ = dtrtrs(Lm, tmp.T, lower=1)
|
||||||
A = tdot(tmp)
|
A = tdot(tmp)
|
||||||
|
|
||||||
# factor B
|
# factor B
|
||||||
|
|
@ -100,14 +100,16 @@ class VarDTC(object):
|
||||||
LB = jitchol(B)
|
LB = jitchol(B)
|
||||||
|
|
||||||
# VVT_factor is a matrix such that tdot(VVT_factor) = VVT...this is for efficiency!
|
# VVT_factor is a matrix such that tdot(VVT_factor) = VVT...this is for efficiency!
|
||||||
self.YYTfactor = self.get_YYTfactor(Y)
|
#self.YYTfactor = self.get_YYTfactor(Y)
|
||||||
VVT_factor = self.get_VVTfactor(self.YYTfactor, beta)
|
#VVT_factor = self.get_VVTfactor(self.YYTfactor, beta)
|
||||||
|
VVT_factor = beta*param_to_array(Y)
|
||||||
trYYT = self.get_trYYT(Y)
|
trYYT = self.get_trYYT(Y)
|
||||||
|
|
||||||
psi1Vf = np.dot(psi1.T, VVT_factor)
|
psi1Vf = np.dot(psi1.T, VVT_factor)
|
||||||
|
|
||||||
# back substutue C into psi1Vf
|
# back substutue C into psi1Vf
|
||||||
tmp, info1 = dtrtrs(Lm, np.asfortranarray(psi1Vf), lower=1, trans=0)
|
tmp, info1 = dtrtrs(Lm, psi1Vf, lower=1, trans=0)
|
||||||
_LBi_Lmi_psi1Vf, _ = dtrtrs(LB, np.asfortranarray(tmp), lower=1, trans=0)
|
_LBi_Lmi_psi1Vf, _ = dtrtrs(LB, tmp, lower=1, trans=0)
|
||||||
tmp, info2 = dtrtrs(LB, _LBi_Lmi_psi1Vf, lower=1, trans=1)
|
tmp, info2 = dtrtrs(LB, _LBi_Lmi_psi1Vf, lower=1, trans=1)
|
||||||
Cpsi1Vf, info3 = dtrtrs(Lm, tmp, lower=1, trans=1)
|
Cpsi1Vf, info3 = dtrtrs(Lm, tmp, lower=1, trans=1)
|
||||||
|
|
||||||
|
|
@ -152,8 +154,8 @@ class VarDTC(object):
|
||||||
raise NotImplementedError, "heteroscedatic derivates with uncertain inputs not implemented"
|
raise NotImplementedError, "heteroscedatic derivates with uncertain inputs not implemented"
|
||||||
else:
|
else:
|
||||||
LBi = chol_inv(LB)
|
LBi = chol_inv(LB)
|
||||||
Lmi_psi1, nil = dtrtrs(Lm, np.asfortranarray(psi1.T), lower=1, trans=0)
|
Lmi_psi1, nil = dtrtrs(Lm, psi1.T, lower=1, trans=0)
|
||||||
_LBi_Lmi_psi1, _ = dtrtrs(LB, np.asfortranarray(Lmi_psi1), lower=1, trans=0)
|
_LBi_Lmi_psi1, _ = dtrtrs(LB, Lmi_psi1, lower=1, trans=0)
|
||||||
|
|
||||||
partial_for_likelihood = -0.5 * beta + 0.5 * likelihood.V**2
|
partial_for_likelihood = -0.5 * beta + 0.5 * likelihood.V**2
|
||||||
partial_for_likelihood += 0.5 * output_dim * (psi0 - np.sum(Lmi_psi1**2,0))[:,None] * beta**2
|
partial_for_likelihood += 0.5 * output_dim * (psi0 - np.sum(Lmi_psi1**2,0))[:,None] * beta**2
|
||||||
|
|
@ -195,12 +197,14 @@ class VarDTC(object):
|
||||||
if VVT_factor.shape[1] == Y.shape[1]:
|
if VVT_factor.shape[1] == Y.shape[1]:
|
||||||
woodbury_vector = Cpsi1Vf # == Cpsi1V
|
woodbury_vector = Cpsi1Vf # == Cpsi1V
|
||||||
else:
|
else:
|
||||||
|
print 'foobar'
|
||||||
psi1V = np.dot(Y.T*beta, psi1).T
|
psi1V = np.dot(Y.T*beta, psi1).T
|
||||||
tmp, _ = dtrtrs(Lm, np.asfortranarray(psi1V), lower=1, trans=0)
|
tmp, _ = dtrtrs(Lm, psi1V, lower=1, trans=0)
|
||||||
tmp, _ = dpotrs(LB, tmp, lower=1)
|
tmp, _ = dpotrs(LB, tmp, lower=1)
|
||||||
woodbury_vector, _ = dtrtrs(Lm, tmp, lower=1, trans=1)
|
woodbury_vector, _ = dtrtrs(Lm, tmp, lower=1, trans=1)
|
||||||
Bi, _ = dpotri(LB, lower=0)
|
Bi, _ = dpotri(LB, lower=1)
|
||||||
symmetrify(Bi)
|
symmetrify(Bi)
|
||||||
|
Bi = dpotri(LB, lower=1)[0]
|
||||||
woodbury_inv = backsub_both_sides(Lm, np.eye(num_inducing) - Bi)
|
woodbury_inv = backsub_both_sides(Lm, np.eye(num_inducing) - Bi)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,9 @@ class Optimizer():
|
||||||
"""
|
"""
|
||||||
See GPy.plotting.matplot_dep.inference_plots
|
See GPy.plotting.matplot_dep.inference_plots
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
||||||
from ..plotting.matplot_dep import inference_plots
|
from ...plotting.matplot_dep import inference_plots
|
||||||
inference_plots.plot_optimizer(self)
|
inference_plots.plot_optimizer(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ class Bias(Kernpart):
|
||||||
:type variance: float
|
:type variance: float
|
||||||
"""
|
"""
|
||||||
super(Bias, self).__init__(input_dim, name)
|
super(Bias, self).__init__(input_dim, name)
|
||||||
self.variance = Param("variance", variance)
|
from ...core.parameterization.transformations import Logexp
|
||||||
|
self.variance = Param("variance", variance, Logexp())
|
||||||
self.add_parameter(self.variance)
|
self.add_parameter(self.variance)
|
||||||
|
|
||||||
def K(self,X,X2,target):
|
def K(self,X,X2,target):
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class Linear(Kernpart):
|
||||||
|
|
||||||
def update_gradients_full(self, dL_dK, X):
|
def update_gradients_full(self, dL_dK, X):
|
||||||
#self.variances.gradient[:] = 0
|
#self.variances.gradient[:] = 0
|
||||||
self._param_grad_helper(dL_dK, X, self.variances.gradient)
|
self._param_grad_helper(dL_dK, X, None, self.variances.gradient)
|
||||||
|
|
||||||
def update_gradients_sparse(self, dL_dKmm, dL_dKnm, dL_dKdiag, X, Z):
|
def update_gradients_sparse(self, dL_dKmm, dL_dKnm, dL_dKdiag, X, Z):
|
||||||
tmp = dL_dKdiag[:, None] * X ** 2
|
tmp = dL_dKdiag[:, None] * X ** 2
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class RBF(Kernpart):
|
||||||
|
|
||||||
self.variance = Param('variance', variance, Logexp())
|
self.variance = Param('variance', variance, Logexp())
|
||||||
|
|
||||||
self.lengthscale = Param('lengthscale', lengthscale)
|
self.lengthscale = Param('lengthscale', lengthscale, Logexp())
|
||||||
self.lengthscale.add_observer(self, self.update_lengthscale)
|
self.lengthscale.add_observer(self, self.update_lengthscale)
|
||||||
self.update_lengthscale(self.lengthscale)
|
self.update_lengthscale(self.lengthscale)
|
||||||
|
|
||||||
|
|
@ -264,7 +264,7 @@ class RBF(Kernpart):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
num_data, num_inducing, input_dim = X.shape[0], X.shape[0], self.input_dim
|
num_data, num_inducing, input_dim = X.shape[0], X.shape[0], self.input_dim
|
||||||
X, dvardLdK = param_to_array(X, dvardLdK)
|
X, dvardLdK, var_len3 = param_to_array(X, dvardLdK, var_len3)
|
||||||
weave.inline(code, arg_names=['num_data', 'num_inducing', 'input_dim', 'X', 'target', 'dvardLdK', 'var_len3'], type_converters=weave.converters.blitz, **self.weave_options)
|
weave.inline(code, arg_names=['num_data', 'num_inducing', 'input_dim', 'X', 'target', 'dvardLdK', 'var_len3'], type_converters=weave.converters.blitz, **self.weave_options)
|
||||||
else:
|
else:
|
||||||
code = """
|
code = """
|
||||||
|
|
@ -281,7 +281,7 @@ class RBF(Kernpart):
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
num_data, num_inducing, input_dim = X.shape[0], X2.shape[0], self.input_dim
|
num_data, num_inducing, input_dim = X.shape[0], X2.shape[0], self.input_dim
|
||||||
X, X2, dvardLdK = param_to_array(X, X2, dvardLdK)
|
X, X2, dvardLdK, var_len3 = param_to_array(X, X2, dvardLdK, var_len3)
|
||||||
weave.inline(code, arg_names=['num_data', 'num_inducing', 'input_dim', 'X', 'X2', 'target', 'dvardLdK', 'var_len3'], type_converters=weave.converters.blitz, **self.weave_options)
|
weave.inline(code, arg_names=['num_data', 'num_inducing', 'input_dim', 'X', 'X2', 'target', 'dvardLdK', 'var_len3'], type_converters=weave.converters.blitz, **self.weave_options)
|
||||||
return target
|
return target
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,8 @@ class Bernoulli(Likelihood):
|
||||||
Each y_i must be in {0, 1}
|
Each y_i must be in {0, 1}
|
||||||
"""
|
"""
|
||||||
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
||||||
objective = (link_f**y) * ((1.-link_f)**(1.-y))
|
#objective = (link_f**y) * ((1.-link_f)**(1.-y))
|
||||||
|
objective = np.where(y, link_f, 1.-link_f)
|
||||||
return np.exp(np.sum(np.log(objective)))
|
return np.exp(np.sum(np.log(objective)))
|
||||||
|
|
||||||
def logpdf_link(self, link_f, y, extra_data=None):
|
def logpdf_link(self, link_f, y, extra_data=None):
|
||||||
|
|
@ -136,7 +137,9 @@ class Bernoulli(Likelihood):
|
||||||
"""
|
"""
|
||||||
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
||||||
#objective = y*np.log(link_f) + (1.-y)*np.log(link_f)
|
#objective = y*np.log(link_f) + (1.-y)*np.log(link_f)
|
||||||
|
state = np.seterr(divide='ignore')
|
||||||
objective = np.where(y==1, np.log(link_f), np.log(1-link_f))
|
objective = np.where(y==1, np.log(link_f), np.log(1-link_f))
|
||||||
|
np.seterr(**state)
|
||||||
return np.sum(objective)
|
return np.sum(objective)
|
||||||
|
|
||||||
def dlogpdf_dlink(self, link_f, y, extra_data=None):
|
def dlogpdf_dlink(self, link_f, y, extra_data=None):
|
||||||
|
|
@ -155,7 +158,10 @@ class Bernoulli(Likelihood):
|
||||||
:rtype: Nx1 array
|
:rtype: Nx1 array
|
||||||
"""
|
"""
|
||||||
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
||||||
grad = (y/link_f) - (1.-y)/(1-link_f)
|
#grad = (y/link_f) - (1.-y)/(1-link_f)
|
||||||
|
state = np.seterr(divide='ignore')
|
||||||
|
grad = np.where(y, 1./link_f, -1./(1-link_f))
|
||||||
|
np.seterr(**state)
|
||||||
return grad
|
return grad
|
||||||
|
|
||||||
def d2logpdf_dlink2(self, link_f, y, extra_data=None):
|
def d2logpdf_dlink2(self, link_f, y, extra_data=None):
|
||||||
|
|
@ -180,7 +186,10 @@ class Bernoulli(Likelihood):
|
||||||
(the distribution for y_i depends only on link(f_i) not on link(f_(j!=i))
|
(the distribution for y_i depends only on link(f_i) not on link(f_(j!=i))
|
||||||
"""
|
"""
|
||||||
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
||||||
d2logpdf_dlink2 = -y/(link_f**2) - (1-y)/((1-link_f)**2)
|
#d2logpdf_dlink2 = -y/(link_f**2) - (1-y)/((1-link_f)**2)
|
||||||
|
state = np.seterr(divide='ignore')
|
||||||
|
d2logpdf_dlink2 = np.where(y, -1./np.square(link_f), -1./np.square(1.-link_f))
|
||||||
|
np.seterr(**state)
|
||||||
return d2logpdf_dlink2
|
return d2logpdf_dlink2
|
||||||
|
|
||||||
def d3logpdf_dlink3(self, link_f, y, extra_data=None):
|
def d3logpdf_dlink3(self, link_f, y, extra_data=None):
|
||||||
|
|
@ -199,7 +208,10 @@ class Bernoulli(Likelihood):
|
||||||
:rtype: Nx1 array
|
:rtype: Nx1 array
|
||||||
"""
|
"""
|
||||||
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
assert np.atleast_1d(link_f).shape == np.atleast_1d(y).shape
|
||||||
d3logpdf_dlink3 = 2*(y/(link_f**3) - (1-y)/((1-link_f)**3))
|
#d3logpdf_dlink3 = 2*(y/(link_f**3) - (1-y)/((1-link_f)**3))
|
||||||
|
state = np.seterr(divide='ignore')
|
||||||
|
d3logpdf_dlink3 = np.where(y, 2./(link_f**3), -2./((1.-link_f)**3))
|
||||||
|
np.seterr(**state)
|
||||||
return d3logpdf_dlink3
|
return d3logpdf_dlink3
|
||||||
|
|
||||||
def samples(self, gp):
|
def samples(self, gp):
|
||||||
|
|
|
||||||
|
|
@ -88,12 +88,9 @@ class Gaussian(Likelihood):
|
||||||
return mu, var, low, up
|
return mu, var, low, up
|
||||||
|
|
||||||
def predictive_mean(self, mu, sigma):
|
def predictive_mean(self, mu, sigma):
|
||||||
#new_sigma2 = self.predictive_variance(mu, sigma)
|
|
||||||
#return new_sigma2*(mu/sigma**2 + self.gp_link.transf(mu)/self.variance)
|
|
||||||
return mu
|
return mu
|
||||||
|
|
||||||
def predictive_variance(self, mu, sigma, predictive_mean=None):
|
def predictive_variance(self, mu, sigma, predictive_mean=None):
|
||||||
#what on earth was the sum of precisions doing here? JH
|
|
||||||
return self.variance + sigma**2
|
return self.variance + sigma**2
|
||||||
|
|
||||||
def pdf_link(self, link_f, y, extra_data=None):
|
def pdf_link(self, link_f, y, extra_data=None):
|
||||||
|
|
@ -305,3 +302,11 @@ class Gaussian(Likelihood):
|
||||||
gp = gp.flatten()
|
gp = gp.flatten()
|
||||||
Ysim = np.array([np.random.normal(self.gp_link.transf(gpj), scale=np.sqrt(self.variance), size=1) for gpj in gp])
|
Ysim = np.array([np.random.normal(self.gp_link.transf(gpj), scale=np.sqrt(self.variance), size=1) for gpj in gp])
|
||||||
return Ysim.reshape(orig_shape)
|
return Ysim.reshape(orig_shape)
|
||||||
|
|
||||||
|
def log_predictive_density(self, y_test, mu_star, var_star):
|
||||||
|
"""
|
||||||
|
assumes independence
|
||||||
|
"""
|
||||||
|
v = var_star + self.variance
|
||||||
|
return -0.5*np.log(2*np.pi) -0.5*np.log(v) - 0.5*np.square(y_test - mu_star)/v
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class BayesianGPLVM(SparseGP, GPLVM):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
|
def __init__(self, Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
|
||||||
Z=None, kernel=None, inference_method=None, likelihood=Gaussian(), name='bayesian gplvm', **kwargs):
|
Z=None, kernel=None, inference_method=None, likelihood=None, name='bayesian gplvm', **kwargs):
|
||||||
if X == None:
|
if X == None:
|
||||||
X = self.initialise_latent(init, input_dim, Y)
|
X = self.initialise_latent(init, input_dim, Y)
|
||||||
self.init = init
|
self.init = init
|
||||||
|
|
@ -37,7 +37,9 @@ class BayesianGPLVM(SparseGP, GPLVM):
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
if likelihood is None:
|
||||||
|
likelihood = Gaussian()
|
||||||
self.q = Normal(X, X_variance)
|
self.q = Normal(X, X_variance)
|
||||||
SparseGP.__init__(self, X, Y, Z, kernel, likelihood, inference_method, X_variance, name, **kwargs)
|
SparseGP.__init__(self, X, Y, Z, kernel, likelihood, inference_method, X_variance, name, **kwargs)
|
||||||
self.add_parameter(self.q, index=0)
|
self.add_parameter(self.q, index=0)
|
||||||
|
|
@ -70,9 +72,10 @@ class BayesianGPLVM(SparseGP, GPLVM):
|
||||||
return 0.5 * (var_mean + var_S) - 0.5 * self.input_dim * self.num_data
|
return 0.5 * (var_mean + var_S) - 0.5 * self.input_dim * self.num_data
|
||||||
|
|
||||||
def parameters_changed(self):
|
def parameters_changed(self):
|
||||||
super(BayesianGPLVM, self).parameters_changed()
|
self.posterior, self._log_marginal_likelihood, self.grad_dict = self.inference_method.inference(self.kern, self.X, self.X_variance, self.Z, self.likelihood, self.Y)
|
||||||
self._log_marginal_likelihood -= self.KL_divergence()
|
self._update_gradients_Z(add=False)
|
||||||
|
|
||||||
|
self._log_marginal_likelihood -= self.KL_divergence()
|
||||||
dL_dmu, dL_dS = self.dL_dmuS()
|
dL_dmu, dL_dS = self.dL_dmuS()
|
||||||
|
|
||||||
# dL:
|
# dL:
|
||||||
|
|
@ -159,6 +162,38 @@ class BayesianGPLVM(SparseGP, GPLVM):
|
||||||
|
|
||||||
return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs)
|
return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs)
|
||||||
|
|
||||||
|
class BayesianGPLVMWithMissingData(BayesianGPLVM):
|
||||||
|
def __init__(self, Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
|
||||||
|
Z=None, kernel=None, inference_method=None, likelihood=None, name='bayesian gplvm', **kwargs):
|
||||||
|
from ..util.subarray_and_sorting import common_subarrays
|
||||||
|
self.subarrays = common_subarrays(Y)
|
||||||
|
import ipdb;ipdb.set_trace()
|
||||||
|
BayesianGPLVM.__init__(self, Y, input_dim, X=X, X_variance=X_variance, init=init, num_inducing=num_inducing, Z=Z, kernel=kernel, inference_method=inference_method, likelihood=likelihood, name=name, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def parameters_changed(self):
|
||||||
|
super(BayesianGPLVM, self).parameters_changed()
|
||||||
|
self._log_marginal_likelihood -= self.KL_divergence()
|
||||||
|
|
||||||
|
dL_dmu, dL_dS = self.dL_dmuS()
|
||||||
|
|
||||||
|
# dL:
|
||||||
|
self.q.mean.gradient = dL_dmu
|
||||||
|
self.q.variance.gradient = dL_dS
|
||||||
|
|
||||||
|
# dKL:
|
||||||
|
self.q.mean.gradient -= self.X
|
||||||
|
self.q.variance.gradient -= (1. - (1. / (self.X_variance))) * 0.5
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import numpy as np
|
||||||
|
X = np.random.randn(20,2)
|
||||||
|
W = np.linspace(0,1,10)[None,:]
|
||||||
|
Y = (X*W).sum(1)
|
||||||
|
missing = np.random.binomial(1,.1,size=Y.shape)
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
def latent_cost_and_grad(mu_S, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2):
|
def latent_cost_and_grad(mu_S, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2):
|
||||||
"""
|
"""
|
||||||
objective function for fitting the latent variables for test points
|
objective function for fitting the latent variables for test points
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import numpy as np
|
||||||
from ..core import SparseGP
|
from ..core import SparseGP
|
||||||
from .. import likelihoods
|
from .. import likelihoods
|
||||||
from .. import kern
|
from .. import kern
|
||||||
|
from ..inference.latent_function_inference import VarDTC
|
||||||
|
|
||||||
class SparseGPRegression(SparseGP):
|
class SparseGPRegression(SparseGP):
|
||||||
"""
|
"""
|
||||||
|
|
@ -43,8 +44,7 @@ class SparseGPRegression(SparseGP):
|
||||||
|
|
||||||
likelihood = likelihoods.Gaussian()
|
likelihood = likelihoods.Gaussian()
|
||||||
|
|
||||||
SparseGP.__init__(self, X, Y, Z, kernel, likelihood, X_variance=X_variance)
|
SparseGP.__init__(self, X, Y, Z, kernel, likelihood, X_variance=X_variance, inference_method=VarDTC())
|
||||||
#self.ensure_default_constraints()
|
|
||||||
|
|
||||||
def _getstate(self):
|
def _getstate(self):
|
||||||
return SparseGP._getstate(self)
|
return SparseGP._getstate(self)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||||
|
|
||||||
import pylab as pb
|
import pylab as pb
|
||||||
|
import sys
|
||||||
#import numpy as np
|
#import numpy as np
|
||||||
#import Tango
|
#import Tango
|
||||||
#from base_plots import gpplot, x_frame1D, x_frame2D
|
#from base_plots import gpplot, x_frame1D, x_frame2D
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,7 @@ def plot_fit(model, plot_limits=None, which_data_rows='all',
|
||||||
ax.plot(Xnew, yi[:,None], Tango.colorsHex['darkBlue'], linewidth=0.25)
|
ax.plot(Xnew, yi[:,None], Tango.colorsHex['darkBlue'], linewidth=0.25)
|
||||||
#ax.plot(Xnew, yi[:,None], marker='x', linestyle='--',color=Tango.colorsHex['darkBlue']) #TODO apply this line for discrete outputs.
|
#ax.plot(Xnew, yi[:,None], marker='x', linestyle='--',color=Tango.colorsHex['darkBlue']) #TODO apply this line for discrete outputs.
|
||||||
|
|
||||||
#add inducing inputs (if a sparse model is used)
|
|
||||||
if hasattr(model,"Z"):
|
|
||||||
#Zu = model.Z[:,free_dims] * model._Xscale[:,free_dims] + model._Xoffset[:,free_dims]
|
|
||||||
Zu = param_to_array(model.Z[:,free_dims])
|
|
||||||
z_height = ax.get_ylim()[0]
|
|
||||||
ax.plot(Zu, np.zeros_like(Zu) + z_height, 'r|', mew=1.5, markersize=12)
|
|
||||||
|
|
||||||
|
|
||||||
#add error bars for uncertain (if input uncertainty is being modelled)
|
#add error bars for uncertain (if input uncertainty is being modelled)
|
||||||
if hasattr(model,"has_uncertain_inputs"):
|
if hasattr(model,"has_uncertain_inputs"):
|
||||||
ax.errorbar(model.X[which_data, free_dims], model.likelihood.data[which_data, 0],
|
ax.errorbar(model.X[which_data, free_dims], model.likelihood.data[which_data, 0],
|
||||||
|
|
@ -115,6 +108,15 @@ def plot_fit(model, plot_limits=None, which_data_rows='all',
|
||||||
ax.set_xlim(xmin, xmax)
|
ax.set_xlim(xmin, xmax)
|
||||||
ax.set_ylim(ymin, ymax)
|
ax.set_ylim(ymin, ymax)
|
||||||
|
|
||||||
|
#add inducing inputs (if a sparse model is used)
|
||||||
|
if hasattr(model,"Z"):
|
||||||
|
#Zu = model.Z[:,free_dims] * model._Xscale[:,free_dims] + model._Xoffset[:,free_dims]
|
||||||
|
Zu = param_to_array(model.Z[:,free_dims])
|
||||||
|
z_height = ax.get_ylim()[0]
|
||||||
|
ax.plot(Zu, np.zeros_like(Zu) + z_height, 'r|', mew=1.5, markersize=12)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#2D plotting
|
#2D plotting
|
||||||
elif len(free_dims) == 2:
|
elif len(free_dims) == 2:
|
||||||
|
|
||||||
|
|
@ -132,7 +134,7 @@ def plot_fit(model, plot_limits=None, which_data_rows='all',
|
||||||
m, _ = model._raw_predict(Xgrid, which_parts=which_parts)
|
m, _ = model._raw_predict(Xgrid, which_parts=which_parts)
|
||||||
Y = model.likelihood.Y
|
Y = model.likelihood.Y
|
||||||
else:
|
else:
|
||||||
m, _, _, _ = model.predict(Xgrid, which_parts=which_parts,sampling=False)
|
m, _, _, _ = model.predict(Xgrid, which_parts=which_parts)
|
||||||
Y = model.likelihood.data
|
Y = model.likelihood.data
|
||||||
for d in which_data_ycols:
|
for d in which_data_ycols:
|
||||||
m_d = m[:,d].reshape(resolution, resolution).T
|
m_d = m[:,d].reshape(resolution, resolution).T
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import GPy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import matplotlib as mpl
|
import matplotlib as mpl
|
||||||
import time
|
import time
|
||||||
import Image
|
|
||||||
try:
|
try:
|
||||||
import visual
|
import visual
|
||||||
visual_available = True
|
visual_available = True
|
||||||
|
|
@ -324,6 +323,7 @@ class image_show(matplotlib_show):
|
||||||
else:
|
else:
|
||||||
self.vals = 255*(self.vals - self.vals.min())/(self.vals.max() - self.vals.min())
|
self.vals = 255*(self.vals - self.vals.min())/(self.vals.max() - self.vals.min())
|
||||||
if not self.palette == []: # applying using an image palette (e.g. if the image has been quantized)
|
if not self.palette == []: # applying using an image palette (e.g. if the image has been quantized)
|
||||||
|
from PIL import Image
|
||||||
self.vals = Image.fromarray(self.vals.astype('uint8'))
|
self.vals = Image.fromarray(self.vals.astype('uint8'))
|
||||||
self.vals.putpalette(self.palette) # palette is a list, must be loaded before calling this function
|
self.vals.putpalette(self.palette) # palette is a list, must be loaded before calling this function
|
||||||
|
|
||||||
|
|
|
||||||
60
GPy/testing/index_operations_tests.py
Normal file
60
GPy/testing/index_operations_tests.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
'''
|
||||||
|
Created on 12 Feb 2014
|
||||||
|
|
||||||
|
@author: maxz
|
||||||
|
'''
|
||||||
|
import unittest
|
||||||
|
import numpy as np
|
||||||
|
from GPy.core.parameterization.index_operations import ParameterIndexOperations,\
|
||||||
|
ParameterIndexOperationsView
|
||||||
|
|
||||||
|
one, two, three = 'one', 'two', 'three'
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.param_index = ParameterIndexOperations()
|
||||||
|
self.param_index.add(one, [3])
|
||||||
|
self.param_index.add(two, [0,5])
|
||||||
|
self.param_index.add(three, [2,4,7])
|
||||||
|
|
||||||
|
def test_remove(self):
|
||||||
|
self.param_index.remove(three, np.r_[3:10])
|
||||||
|
self.assertListEqual(self.param_index[three].tolist(), [2])
|
||||||
|
self.param_index.remove(one, [1])
|
||||||
|
self.assertListEqual(self.param_index[one].tolist(), [3])
|
||||||
|
|
||||||
|
def test_index_view(self):
|
||||||
|
#=======================================================================
|
||||||
|
# 0 1 2 3 4 5 6 7 8 9
|
||||||
|
# one
|
||||||
|
# two two
|
||||||
|
# three three three
|
||||||
|
# view: [0 1 2 3 4 5 ]
|
||||||
|
#=======================================================================
|
||||||
|
view = ParameterIndexOperationsView(self.param_index, 2, 6)
|
||||||
|
self.assertSetEqual(set(view.properties()), set([one, two, three]))
|
||||||
|
for v,p in zip(view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])):
|
||||||
|
self.assertEqual(v, p)
|
||||||
|
self.assertSetEqual(set(view[two]), set([3]))
|
||||||
|
self.assertSetEqual(set(self.param_index[two]), set([0, 5]))
|
||||||
|
view.add(two, np.array([0]))
|
||||||
|
self.assertSetEqual(set(view[two]), set([0,3]))
|
||||||
|
self.assertSetEqual(set(self.param_index[two]), set([0, 2, 5]))
|
||||||
|
view.clear()
|
||||||
|
for v,p in zip(view.properties_for(np.r_[:6]), self.param_index.properties_for(np.r_[2:2+6])):
|
||||||
|
self.assertEqual(v, p)
|
||||||
|
self.assertEqual(v, [])
|
||||||
|
param_index = ParameterIndexOperations()
|
||||||
|
param_index.add(one, [3])
|
||||||
|
param_index.add(two, [0,5])
|
||||||
|
param_index.add(three, [2,4,7])
|
||||||
|
view2 = ParameterIndexOperationsView(param_index, 2, 6)
|
||||||
|
view.update(view2)
|
||||||
|
for [i,v],[i2,v2] in zip(sorted(param_index.items()), sorted(self.param_index.items())):
|
||||||
|
self.assertEqual(i, i2)
|
||||||
|
self.assertTrue(np.all(v == v2))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#import sys;sys.argv = ['', 'Test.test_index_view']
|
||||||
|
unittest.main()
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import unittest
|
import unittest
|
||||||
import GPy
|
import GPy
|
||||||
from GPy.models import GradientChecker
|
from ..models import GradientChecker
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
from GPy.likelihoods import link_functions
|
from ..likelihoods import link_functions
|
||||||
from ..core.parameterization import Param
|
from ..core.parameterization import Param
|
||||||
from functools import partial
|
from functools import partial
|
||||||
#np.random.seed(300)
|
#np.random.seed(300)
|
||||||
|
|
@ -516,9 +516,8 @@ class TestNoiseModels(object):
|
||||||
Y = Y/Y.max()
|
Y = Y/Y.max()
|
||||||
white_var = 1e-6
|
white_var = 1e-6
|
||||||
kernel = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
kernel = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
||||||
laplace_likelihood = GPy.inference.latent_function_inference.LaplaceInference()
|
laplace_likelihood = GPy.inference.latent_function_inference.Laplace()
|
||||||
m = GPy.core.GP(X.copy(), Y.copy(), kernel, likelihood=model, inference_method=laplace_likelihood)
|
m = GPy.core.GP(X.copy(), Y.copy(), kernel, likelihood=model, inference_method=laplace_likelihood)
|
||||||
m.ensure_default_constraints()
|
|
||||||
m['white'].constrain_fixed(white_var)
|
m['white'].constrain_fixed(white_var)
|
||||||
|
|
||||||
#Set constraints
|
#Set constraints
|
||||||
|
|
@ -541,6 +540,10 @@ class TestNoiseModels(object):
|
||||||
#import ipdb; ipdb.set_trace()
|
#import ipdb; ipdb.set_trace()
|
||||||
#NOTE this test appears to be stochastic for some likelihoods (student t?)
|
#NOTE this test appears to be stochastic for some likelihoods (student t?)
|
||||||
# appears to all be working in test mode right now...
|
# appears to all be working in test mode right now...
|
||||||
|
|
||||||
|
if not m.checkgrad():
|
||||||
|
import ipdb; ipdb.set_trace() # XXX BREAKPOINT
|
||||||
|
|
||||||
assert m.checkgrad(step=step)
|
assert m.checkgrad(step=step)
|
||||||
|
|
||||||
###########
|
###########
|
||||||
|
|
@ -555,7 +558,6 @@ class TestNoiseModels(object):
|
||||||
kernel = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
kernel = GPy.kern.rbf(X.shape[1]) + GPy.kern.white(X.shape[1])
|
||||||
ep_inf = GPy.inference.latent_function_inference.EP()
|
ep_inf = GPy.inference.latent_function_inference.EP()
|
||||||
m = GPy.core.GP(X.copy(), Y.copy(), kernel=kernel, likelihood=model, inference_method=ep_inf)
|
m = GPy.core.GP(X.copy(), Y.copy(), kernel=kernel, likelihood=model, inference_method=ep_inf)
|
||||||
m.ensure_default_constraints()
|
|
||||||
m['white'].constrain_fixed(white_var)
|
m['white'].constrain_fixed(white_var)
|
||||||
|
|
||||||
for param_num in range(len(param_names)):
|
for param_num in range(len(param_names)):
|
||||||
|
|
@ -644,13 +646,11 @@ class LaplaceTests(unittest.TestCase):
|
||||||
m1['variance'] = initial_var_guess
|
m1['variance'] = initial_var_guess
|
||||||
m1['variance'].constrain_bounded(1e-4, 10)
|
m1['variance'].constrain_bounded(1e-4, 10)
|
||||||
m1['rbf'].constrain_bounded(1e-4, 10)
|
m1['rbf'].constrain_bounded(1e-4, 10)
|
||||||
m1.ensure_default_constraints()
|
|
||||||
m1.randomize()
|
m1.randomize()
|
||||||
|
|
||||||
gauss_distr2 = GPy.likelihoods.Gaussian(variance=initial_var_guess)
|
gauss_distr2 = GPy.likelihoods.Gaussian(variance=initial_var_guess)
|
||||||
laplace_inf = GPy.inference.latent_function_inference.LaplaceInference()
|
laplace_inf = GPy.inference.latent_function_inference.Laplace()
|
||||||
m2 = GPy.core.GP(X, Y.copy(), kernel=kernel2, likelihood=gauss_distr2, inference_method=laplace_inf)
|
m2 = GPy.core.GP(X, Y.copy(), kernel=kernel2, likelihood=gauss_distr2, inference_method=laplace_inf)
|
||||||
m2.ensure_default_constraints()
|
|
||||||
m2['white'].constrain_fixed(1e-6)
|
m2['white'].constrain_fixed(1e-6)
|
||||||
m2['rbf'].constrain_bounded(1e-4, 10)
|
m2['rbf'].constrain_bounded(1e-4, 10)
|
||||||
m2['variance'].constrain_bounded(1e-4, 10)
|
m2['variance'].constrain_bounded(1e-4, 10)
|
||||||
|
|
|
||||||
93
GPy/testing/parameterized_tests.py
Normal file
93
GPy/testing/parameterized_tests.py
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
'''
|
||||||
|
Created on Feb 13, 2014
|
||||||
|
|
||||||
|
@author: maxzwiessele
|
||||||
|
'''
|
||||||
|
import unittest
|
||||||
|
import GPy
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.rbf = GPy.kern.rbf(1)
|
||||||
|
self.white = GPy.kern.white(1)
|
||||||
|
from GPy.core.parameterization import Param
|
||||||
|
from GPy.core.parameterization.transformations import Logistic
|
||||||
|
self.param = Param('param', np.random.rand(25,2), Logistic(0, 1))
|
||||||
|
|
||||||
|
self.test1 = GPy.core.Parameterized("test model")
|
||||||
|
self.test1.add_parameter(self.white)
|
||||||
|
self.test1.add_parameter(self.rbf, 0)
|
||||||
|
self.test1.add_parameter(self.param)
|
||||||
|
|
||||||
|
def test_add_parameter(self):
|
||||||
|
self.assertEquals(self.rbf._parent_index_, 0)
|
||||||
|
self.assertEquals(self.white._parent_index_, 1)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_fixes(self):
|
||||||
|
self.white.fix(warning=False)
|
||||||
|
self.test1.remove_parameter(self.test1.param)
|
||||||
|
self.assertTrue(self.test1._has_fixes())
|
||||||
|
|
||||||
|
from GPy.core.parameterization.transformations import FIXED, UNFIXED
|
||||||
|
self.assertListEqual(self.test1._fixes_.tolist(),[UNFIXED,UNFIXED,FIXED])
|
||||||
|
|
||||||
|
self.test1.add_parameter(self.white, 0)
|
||||||
|
self.assertListEqual(self.test1._fixes_.tolist(),[FIXED,UNFIXED,UNFIXED])
|
||||||
|
|
||||||
|
|
||||||
|
def test_remove_parameter(self):
|
||||||
|
from GPy.core.parameterization.transformations import FIXED, UNFIXED, __fixed__
|
||||||
|
self.white.fix()
|
||||||
|
self.test1.remove_parameter(self.white)
|
||||||
|
self.assertIs(self.test1._fixes_,None)
|
||||||
|
|
||||||
|
self.assertListEqual(self.white._fixes_.tolist(), [FIXED])
|
||||||
|
self.assertIs(self.white.constraints,self.white.white.constraints._param_index_ops)
|
||||||
|
self.assertEquals(self.white.white.constraints._offset, 0)
|
||||||
|
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops)
|
||||||
|
|
||||||
|
self.test1.add_parameter(self.white, 0)
|
||||||
|
self.assertIs(self.test1.constraints, self.white.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops)
|
||||||
|
self.assertListEqual(self.test1.constraints[__fixed__].tolist(), [0])
|
||||||
|
self.assertIs(self.white._fixes_,None)
|
||||||
|
self.assertListEqual(self.test1._fixes_.tolist(),[FIXED] + [UNFIXED] * 52)
|
||||||
|
self.test1.remove_parameter(self.white)
|
||||||
|
self.assertIs(self.test1._fixes_,None)
|
||||||
|
self.assertListEqual(self.white._fixes_.tolist(), [FIXED])
|
||||||
|
self.assertIs(self.white.constraints,self.white.white.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.param.constraints._param_index_ops)
|
||||||
|
|
||||||
|
def test_add_parameter_already_in_hirarchy(self):
|
||||||
|
self.test1.add_parameter(self.white._parameters_[0])
|
||||||
|
|
||||||
|
def test_default_constraints(self):
|
||||||
|
self.assertIs(self.rbf.rbf.variance.constraints._param_index_ops, self.rbf.constraints._param_index_ops)
|
||||||
|
self.assertIs(self.test1.constraints, self.rbf.constraints._param_index_ops)
|
||||||
|
self.assertListEqual(self.rbf.constraints.indices()[0].tolist(), range(2))
|
||||||
|
from GPy.core.parameterization.transformations import Logexp
|
||||||
|
kern = self.rbf+self.white
|
||||||
|
self.assertListEqual(kern.constraints[Logexp()].tolist(), range(3))
|
||||||
|
|
||||||
|
def test_constraints(self):
|
||||||
|
self.rbf.constrain(GPy.transformations.Square(), False)
|
||||||
|
self.assertListEqual(self.test1.constraints[GPy.transformations.Square()].tolist(), range(2))
|
||||||
|
self.assertListEqual(self.test1.constraints[GPy.transformations.Logexp()].tolist(), [2])
|
||||||
|
|
||||||
|
self.test1.remove_parameter(self.rbf)
|
||||||
|
self.assertListEqual(self.test1.constraints[GPy.transformations.Square()].tolist(), [])
|
||||||
|
|
||||||
|
def test_constraints_views(self):
|
||||||
|
self.assertEqual(self.white.constraints._offset, 2)
|
||||||
|
self.assertEqual(self.rbf.constraints._offset, 0)
|
||||||
|
self.assertEqual(self.param.constraints._offset, 3)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#import sys;sys.argv = ['', 'Test.test_add_parameter']
|
||||||
|
unittest.main()
|
||||||
|
|
@ -10,6 +10,7 @@ import datasets
|
||||||
import mocap
|
import mocap
|
||||||
import decorators
|
import decorators
|
||||||
import classification
|
import classification
|
||||||
|
import subarray_and_sorting
|
||||||
import caching
|
import caching
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class Cacher(object):
|
||||||
return self.cached_outputs[-1]
|
return self.cached_outputs[-1]
|
||||||
|
|
||||||
def on_cache_changed(self, X):
|
def on_cache_changed(self, X):
|
||||||
print id(X)
|
#print id(X)
|
||||||
i = self.cached_inputs.index(X)
|
i = self.cached_inputs.index(X)
|
||||||
self.inputs_changed[i] = True
|
self.inputs_changed[i] = True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ import os
|
||||||
from config import *
|
from config import *
|
||||||
|
|
||||||
if np.all(np.float64((scipy.__version__).split('.')[:2]) >= np.array([0, 12])):
|
if np.all(np.float64((scipy.__version__).split('.')[:2]) >= np.array([0, 12])):
|
||||||
import scipy.linalg.lapack as lapack
|
#import scipy.linalg.lapack.clapack as lapack
|
||||||
|
from scipy.linalg import lapack
|
||||||
else:
|
else:
|
||||||
from scipy.linalg.lapack import flapack as lapack
|
from scipy.linalg.lapack import flapack as lapack
|
||||||
|
|
||||||
|
|
@ -41,42 +42,103 @@ else:
|
||||||
_blas_available = False
|
_blas_available = False
|
||||||
warnings.warn("warning: caught this exception:" + str(e))
|
warnings.warn("warning: caught this exception:" + str(e))
|
||||||
|
|
||||||
def dtrtri(L, lower=0):
|
def force_F_ordered_symmetric(A):
|
||||||
"""
|
"""
|
||||||
Wrapper for lapack dtrtrs function
|
return a F ordered version of A, assuming A is symmetric
|
||||||
|
"""
|
||||||
|
if A.flags['F_CONTIGUOUS']:
|
||||||
|
return A
|
||||||
|
if A.flags['C_CONTIGUOUS']:
|
||||||
|
return A.T
|
||||||
|
else:
|
||||||
|
return np.asfortranarray(A)
|
||||||
|
|
||||||
|
def force_F_ordered(A):
|
||||||
|
"""
|
||||||
|
return a F ordered version of A, assuming A is triangular
|
||||||
|
"""
|
||||||
|
if A.flags['F_CONTIGUOUS']:
|
||||||
|
return A
|
||||||
|
print "why are your arrays not F order?"
|
||||||
|
return np.asfortranarray(A)
|
||||||
|
|
||||||
|
def jitchol(A, maxtries=5):
|
||||||
|
A = force_F_ordered_symmetric(A)
|
||||||
|
L, info = lapack.dpotrf(A, lower=1)
|
||||||
|
if info == 0:
|
||||||
|
return L
|
||||||
|
else:
|
||||||
|
if maxtries==0:
|
||||||
|
raise linalg.LinAlgError, "not positive definite, even with jitter."
|
||||||
|
diagA = np.diag(A)
|
||||||
|
if np.any(diagA <= 0.):
|
||||||
|
raise linalg.LinAlgError, "not pd: non-positive diagonal elements"
|
||||||
|
jitter = diagA.mean() * 1e-6
|
||||||
|
|
||||||
|
return jitchol(A+np.eye(A.shape[0])*jitter, maxtries-1)
|
||||||
|
|
||||||
|
#def jitchol(A, maxtries=5):
|
||||||
|
# A = np.ascontiguousarray(A)
|
||||||
|
# L, info = lapack.dpotrf(A, lower=1)
|
||||||
|
# if info == 0:
|
||||||
|
# return L
|
||||||
|
# else:
|
||||||
|
# diagA = np.diag(A)
|
||||||
|
# if np.any(diagA <= 0.):
|
||||||
|
# raise linalg.LinAlgError, "not pd: non-positive diagonal elements"
|
||||||
|
# jitter = diagA.mean() * 1e-6
|
||||||
|
# while maxtries > 0 and np.isfinite(jitter):
|
||||||
|
# print 'Warning: adding jitter of {:.10e}'.format(jitter)
|
||||||
|
# try:
|
||||||
|
# return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
|
||||||
|
# except:
|
||||||
|
# jitter *= 10
|
||||||
|
# finally:
|
||||||
|
# maxtries -= 1
|
||||||
|
# raise linalg.LinAlgError, "not positive definite, even with jitter."
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def dtrtri(L, lower=1):
|
||||||
|
"""
|
||||||
|
Wrapper for lapack dtrtri function
|
||||||
Inverse of L
|
Inverse of L
|
||||||
|
|
||||||
:param L: Triangular Matrix L
|
:param L: Triangular Matrix L
|
||||||
:param lower: is matrix lower (true) or upper (false)
|
:param lower: is matrix lower (true) or upper (false)
|
||||||
:returns: Li, info
|
:returns: Li, info
|
||||||
"""
|
"""
|
||||||
|
L = force_F_ordered(L)
|
||||||
return lapack.dtrtri(L, lower=lower)
|
return lapack.dtrtri(L, lower=lower)
|
||||||
|
|
||||||
def dtrtrs(A, B, lower=0, trans=0, unitdiag=0):
|
def dtrtrs(A, B, lower=1, trans=0, unitdiag=0):
|
||||||
"""
|
"""
|
||||||
Wrapper for lapack dtrtrs function
|
Wrapper for lapack dtrtrs function
|
||||||
|
|
||||||
:param A: Matrix A
|
:param A: Matrix A(triangular)
|
||||||
:param B: Matrix B
|
:param B: Matrix B
|
||||||
:param lower: is matrix lower (true) or upper (false)
|
:param lower: is matrix lower (true) or upper (false)
|
||||||
:returns:
|
:returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
A = force_F_ordered(A)
|
||||||
|
#Note: B does not seem to need to be F ordered!
|
||||||
return lapack.dtrtrs(A, B, lower=lower, trans=trans, unitdiag=unitdiag)
|
return lapack.dtrtrs(A, B, lower=lower, trans=trans, unitdiag=unitdiag)
|
||||||
|
|
||||||
def dpotrs(A, B, lower=0):
|
def dpotrs(A, B, lower=1):
|
||||||
"""
|
"""
|
||||||
Wrapper for lapack dpotrs function
|
Wrapper for lapack dpotrs function
|
||||||
|
|
||||||
:param A: Matrix A
|
:param A: Matrix A
|
||||||
:param B: Matrix B
|
:param B: Matrix B
|
||||||
:param lower: is matrix lower (true) or upper (false)
|
:param lower: is matrix lower (true) or upper (false)
|
||||||
:returns:
|
:returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
A = force_F_ordered(A)
|
||||||
return lapack.dpotrs(A, B, lower=lower)
|
return lapack.dpotrs(A, B, lower=lower)
|
||||||
|
|
||||||
def dpotri(A, lower=0):
|
def dpotri(A, lower=1):
|
||||||
"""
|
"""
|
||||||
Wrapper for lapack dpotri function
|
Wrapper for lapack dpotri function
|
||||||
|
|
||||||
|
|
@ -85,7 +147,12 @@ def dpotri(A, lower=0):
|
||||||
:returns: A inverse
|
:returns: A inverse
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return lapack.dpotri(A, lower=lower)
|
assert lower==1, "scipy linalg behaviour is very weird. please use lower, fortran ordered arrays"
|
||||||
|
|
||||||
|
A = force_F_ordered(A)
|
||||||
|
R, info = lapack.dpotri(A, lower=0)
|
||||||
|
symmetrify(R)
|
||||||
|
return R, info
|
||||||
|
|
||||||
def pddet(A):
|
def pddet(A):
|
||||||
"""
|
"""
|
||||||
|
|
@ -133,60 +200,8 @@ def _mdot_r(a, b):
|
||||||
b = b[0]
|
b = b[0]
|
||||||
return np.dot(a, b)
|
return np.dot(a, b)
|
||||||
|
|
||||||
def jitchol(A, maxtries=5):
|
|
||||||
A = np.asfortranarray(A)
|
|
||||||
L, info = lapack.dpotrf(A, lower=1)
|
|
||||||
if info == 0:
|
|
||||||
return L
|
|
||||||
else:
|
|
||||||
diagA = np.diag(A)
|
|
||||||
if np.any(diagA <= 0.):
|
|
||||||
raise linalg.LinAlgError, "not pd: non-positive diagonal elements"
|
|
||||||
jitter = diagA.mean() * 1e-6
|
|
||||||
while maxtries > 0 and np.isfinite(jitter):
|
|
||||||
print 'Warning: adding jitter of {:.10e}'.format(jitter)
|
|
||||||
try:
|
|
||||||
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
|
|
||||||
except:
|
|
||||||
jitter *= 10
|
|
||||||
finally:
|
|
||||||
maxtries -= 1
|
|
||||||
raise linalg.LinAlgError, "not positive definite, even with jitter."
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def jitchol_old(A, maxtries=5):
|
|
||||||
"""
|
|
||||||
:param A: An almost pd square matrix
|
|
||||||
|
|
||||||
:rval L: the Cholesky decomposition of A
|
|
||||||
|
|
||||||
.. note:
|
|
||||||
|
|
||||||
Adds jitter to K, to enforce positive-definiteness
|
|
||||||
if stuff breaks, please check:
|
|
||||||
np.allclose(sp.linalg.cholesky(XXT, lower = True), np.triu(sp.linalg.cho_factor(XXT)[0]).T)
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return linalg.cholesky(A, lower=True)
|
|
||||||
except linalg.LinAlgError:
|
|
||||||
diagA = np.diag(A)
|
|
||||||
if np.any(diagA < 0.):
|
|
||||||
raise linalg.LinAlgError, "not pd: negative diagonal elements"
|
|
||||||
jitter = diagA.mean() * 1e-6
|
|
||||||
for i in range(1, maxtries + 1):
|
|
||||||
print '\rWarning: adding jitter of {:.10e} '.format(jitter),
|
|
||||||
try:
|
|
||||||
return linalg.cholesky(A + np.eye(A.shape[0]).T * jitter, lower=True)
|
|
||||||
except:
|
|
||||||
jitter *= 10
|
|
||||||
|
|
||||||
raise linalg.LinAlgError, "not positive definite, even with jitter."
|
|
||||||
|
|
||||||
def pdinv(A, *args):
|
def pdinv(A, *args):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param A: A DxD pd numpy array
|
:param A: A DxD pd numpy array
|
||||||
|
|
||||||
:rval Ai: the inverse of A
|
:rval Ai: the inverse of A
|
||||||
|
|
@ -201,7 +216,7 @@ def pdinv(A, *args):
|
||||||
"""
|
"""
|
||||||
L = jitchol(A, *args)
|
L = jitchol(A, *args)
|
||||||
logdet = 2.*np.sum(np.log(np.diag(L)))
|
logdet = 2.*np.sum(np.log(np.diag(L)))
|
||||||
Li = chol_inv(L)
|
Li = dtrtri(L)
|
||||||
Ai, _ = lapack.dpotri(L)
|
Ai, _ = lapack.dpotri(L)
|
||||||
# Ai = np.tril(Ai) + np.tril(Ai,-1).T
|
# Ai = np.tril(Ai) + np.tril(Ai,-1).T
|
||||||
symmetrify(Ai)
|
symmetrify(Ai)
|
||||||
|
|
@ -209,7 +224,7 @@ def pdinv(A, *args):
|
||||||
return Ai, L, Li, logdet
|
return Ai, L, Li, logdet
|
||||||
|
|
||||||
|
|
||||||
def chol_inv(L):
|
def dtrtri(L):
|
||||||
"""
|
"""
|
||||||
Inverts a Cholesky lower triangular matrix
|
Inverts a Cholesky lower triangular matrix
|
||||||
|
|
||||||
|
|
@ -218,7 +233,8 @@ def chol_inv(L):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return lapack.dtrtri(L, lower=True)[0]
|
L = force_F_ordered(L)
|
||||||
|
return lapack.dtrtri(L, lower=1)[0]
|
||||||
|
|
||||||
|
|
||||||
def multiple_pdinv(A):
|
def multiple_pdinv(A):
|
||||||
|
|
@ -234,7 +250,7 @@ def multiple_pdinv(A):
|
||||||
N = A.shape[-1]
|
N = A.shape[-1]
|
||||||
chols = [jitchol(A[:, :, i]) for i in range(N)]
|
chols = [jitchol(A[:, :, i]) for i in range(N)]
|
||||||
halflogdets = [np.sum(np.log(np.diag(L[0]))) for L in chols]
|
halflogdets = [np.sum(np.log(np.diag(L[0]))) for L in chols]
|
||||||
invs = [lapack.dpotri(L[0], True)[0] for L in chols]
|
invs = [dpotri(L[0], True)[0] for L in chols]
|
||||||
invs = [np.triu(I) + np.triu(I, 1).T for I in invs]
|
invs = [np.triu(I) + np.triu(I, 1).T for I in invs]
|
||||||
return np.dstack(invs), np.array(halflogdets)
|
return np.dstack(invs), np.array(halflogdets)
|
||||||
|
|
||||||
|
|
@ -425,7 +441,8 @@ def tdot_blas(mat, out=None):
|
||||||
|
|
||||||
symmetrify(out, upper=True)
|
symmetrify(out, upper=True)
|
||||||
|
|
||||||
return out
|
|
||||||
|
return np.ascontiguousarray(out)
|
||||||
|
|
||||||
def tdot(*args, **kwargs):
|
def tdot(*args, **kwargs):
|
||||||
if _blas_available:
|
if _blas_available:
|
||||||
|
|
@ -557,24 +574,24 @@ def cholupdate(L, x):
|
||||||
def backsub_both_sides(L, X, transpose='left'):
|
def backsub_both_sides(L, X, transpose='left'):
|
||||||
""" Return L^-T * X * L^-1, assumuing X is symmetrical and L is lower cholesky"""
|
""" Return L^-T * X * L^-1, assumuing X is symmetrical and L is lower cholesky"""
|
||||||
if transpose == 'left':
|
if transpose == 'left':
|
||||||
tmp, _ = lapack.dtrtrs(L, np.asfortranarray(X), lower=1, trans=1)
|
tmp, _ = dtrtrs(L, X, lower=1, trans=1)
|
||||||
return lapack.dtrtrs(L, np.asfortranarray(tmp.T), lower=1, trans=1)[0].T
|
return dtrtrs(L, tmp.T, lower=1, trans=1)[0].T
|
||||||
else:
|
else:
|
||||||
tmp, _ = lapack.dtrtrs(L, np.asfortranarray(X), lower=1, trans=0)
|
tmp, _ = dtrtrs(L, X, lower=1, trans=0)
|
||||||
return lapack.dtrtrs(L, np.asfortranarray(tmp.T), lower=1, trans=0)[0].T
|
return dtrtrs(L, tmp.T, lower=1, trans=0)[0].T
|
||||||
|
|
||||||
def PCA(Y, input_dim):
|
def PCA(Y, input_dim):
|
||||||
"""
|
"""
|
||||||
Principal component analysis: maximum likelihood solution by SVD
|
Principal component analysis: maximum likelihood solution by SVD
|
||||||
|
|
||||||
:param Y: NxD np.array of data
|
:param Y: NxD np.array of data
|
||||||
:param input_dim: int, dimension of projection
|
:param input_dim: int, dimension of projection
|
||||||
|
|
||||||
|
|
||||||
:rval X: - Nxinput_dim np.array of dimensionality reduced data
|
:rval X: - Nxinput_dim np.array of dimensionality reduced data
|
||||||
:rval W: - input_dimxD mapping from X to Y
|
:rval W: - input_dimxD mapping from X to Y
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not np.allclose(Y.mean(axis=0), 0.0):
|
if not np.allclose(Y.mean(axis=0), 0.0):
|
||||||
print "Y is not zero mean, centering it locally (GPy.util.linalg.PCA)"
|
print "Y is not zero mean, centering it locally (GPy.util.linalg.PCA)"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue