From ebb919bb8b99f708d76b7a0d0bd5a53eb9627add Mon Sep 17 00:00:00 2001 From: mzwiessele Date: Wed, 26 Mar 2014 14:59:08 +0000 Subject: [PATCH 1/5] array list now working with index --- GPy/core/parameterization/lists_and_dicts.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GPy/core/parameterization/lists_and_dicts.py b/GPy/core/parameterization/lists_and_dicts.py index ca0589c9..31235952 100644 --- a/GPy/core/parameterization/lists_and_dicts.py +++ b/GPy/core/parameterization/lists_and_dicts.py @@ -28,4 +28,11 @@ class ArrayList(list): return True return False + def index(self, item): + index = 0 + for el in self: + if el is item: + return index + index += 1 + raise ValueError, "{} is not in list".format(item) pass From a126f288d2c111b5a22e9b634e498d4f74786652 Mon Sep 17 00:00:00 2001 From: mzwiessele Date: Wed, 26 Mar 2014 14:59:38 +0000 Subject: [PATCH 2/5] slice operations now bound functions, not added after the fact --- GPy/kern/_src/kernel_slice_operations.py | 72 ++++++++++++------------ 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/GPy/kern/_src/kernel_slice_operations.py b/GPy/kern/_src/kernel_slice_operations.py index 9beb40ab..b3a1c2a7 100644 --- a/GPy/kern/_src/kernel_slice_operations.py +++ b/GPy/kern/_src/kernel_slice_operations.py @@ -6,24 +6,26 @@ Created on 11 Mar 2014 from ...core.parameterization.parameterized import ParametersChangedMeta import numpy as np +def put_clean(dct, name, *args, **kw): + if name in dct: + dct['_clean_{}'.format(name)] = dct[name] + dct[name] = _slice_wrapper(None, dct[name], *args, **kw) + class KernCallsViaSlicerMeta(ParametersChangedMeta): - def __call__(self, *args, **kw): - instance = super(ParametersChangedMeta, self).__call__(*args, **kw) - instance.K = _slice_wrapper(instance, instance.K) - instance.Kdiag = _slice_wrapper(instance, instance.Kdiag, diag=True) - instance.update_gradients_full = _slice_wrapper(instance, instance.update_gradients_full, diag=False, derivative=True) - instance.update_gradients_diag = _slice_wrapper(instance, instance.update_gradients_diag, diag=True, derivative=True) - instance.gradients_X = _slice_wrapper(instance, instance.gradients_X, diag=False, derivative=True, ret_X=True) - instance.gradients_X_diag = _slice_wrapper(instance, instance.gradients_X_diag, diag=True, derivative=True, ret_X=True) - instance.psi0 = _slice_wrapper(instance, instance.psi0, diag=False, derivative=False) - instance.psi1 = _slice_wrapper(instance, instance.psi1, diag=False, derivative=False) - instance.psi2 = _slice_wrapper(instance, instance.psi2, diag=False, derivative=False) - instance.update_gradients_expectations = _slice_wrapper(instance, instance.update_gradients_expectations, derivative=True, psi_stat=True) - instance.gradients_Z_expectations = _slice_wrapper(instance, instance.gradients_Z_expectations, derivative=True, psi_stat_Z=True, ret_X=True) - instance.gradients_qX_expectations = _slice_wrapper(instance, instance.gradients_qX_expectations, derivative=True, psi_stat=True, ret_X=True) - instance.parameters_changed() - return instance - + def __new__(cls, name, bases, dct): + put_clean(dct, 'K') + put_clean(dct, 'Kdiag', diag=True) + put_clean(dct, 'update_gradients_full', diag=False, derivative=True) + put_clean(dct, 'gradients_X', diag=False, derivative=True, ret_X=True) + put_clean(dct, 'gradients_X_diag', diag=True, derivative=True, ret_X=True) + put_clean(dct, 'psi0', diag=False, derivative=False) + put_clean(dct, 'psi1', diag=False, derivative=False) + put_clean(dct, 'psi2', diag=False, derivative=False) + put_clean(dct, 'update_gradients_expectations', derivative=True, psi_stat=True) + put_clean(dct, 'gradients_Z_expectations', derivative=True, psi_stat_Z=True, ret_X=True) + put_clean(dct, 'gradients_qX_expectations', derivative=True, psi_stat=True, ret_X=True) + return super(KernCallsViaSlicerMeta, cls).__new__(cls, name, bases, dct) + def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False, psi_stat_Z=False, ret_X=False): """ This method wraps the functions in kernel to make sure all kernels allways see their respective input dimension. @@ -35,7 +37,7 @@ def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False """ if derivative: if diag: - def x_slice_wrapper(dL_dKdiag, X): + def x_slice_wrapper(kern, dL_dKdiag, X): ret_X_not_sliced = ret_X and kern._sliced_X == 0 if ret_X_not_sliced: ret = np.zeros(X.shape) @@ -43,15 +45,15 @@ def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False # if the return value is of shape X.shape, we need to make sure to return the right shape kern._sliced_X += 1 try: - if ret_X_not_sliced: ret[:, kern.active_dims] = operation(dL_dKdiag, X) - else: ret = operation(dL_dKdiag, X) + if ret_X_not_sliced: ret[:, kern.active_dims] = operation(kern, dL_dKdiag, X) + else: ret = operation(kern, dL_dKdiag, X) except: raise finally: kern._sliced_X -= 1 return ret elif psi_stat: - def x_slice_wrapper(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + def x_slice_wrapper(kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): ret_X_not_sliced = ret_X and kern._sliced_X == 0 if ret_X_not_sliced: ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) @@ -60,44 +62,44 @@ def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False # if the return value is of shape X.shape, we need to make sure to return the right shape try: if ret_X_not_sliced: - ret = list(operation(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) + ret = list(operation(kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) r2 = ret[:2] ret[0] = ret1 ret[1] = ret2 ret[0][:, kern.active_dims] = r2[0] ret[1][:, kern.active_dims] = r2[1] del r2 - else: ret = operation(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior) + else: ret = operation(kern, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior) except: raise finally: kern._sliced_X -= 1 return ret elif psi_stat_Z: - def x_slice_wrapper(dL_dpsi1, dL_dpsi2, Z, variational_posterior): + def x_slice_wrapper(kern, dL_dpsi1, dL_dpsi2, Z, variational_posterior): ret_X_not_sliced = ret_X and kern._sliced_X == 0 if ret_X_not_sliced: ret = np.zeros(Z.shape) Z, variational_posterior = kern._slice_X(Z) if not kern._sliced_X else Z, kern._slice_X(variational_posterior) if not kern._sliced_X else variational_posterior kern._sliced_X += 1 try: if ret_X_not_sliced: - ret[:, kern.active_dims] = operation(dL_dpsi1, dL_dpsi2, Z, variational_posterior) - else: ret = operation(dL_dpsi1, dL_dpsi2, Z, variational_posterior) + ret[:, kern.active_dims] = operation(kern, dL_dpsi1, dL_dpsi2, Z, variational_posterior) + else: ret = operation(kern, dL_dpsi1, dL_dpsi2, Z, variational_posterior) except: raise finally: kern._sliced_X -= 1 return ret else: - def x_slice_wrapper(dL_dK, X, X2=None): + def x_slice_wrapper(kern, dL_dK, X, X2=None): ret_X_not_sliced = ret_X and kern._sliced_X == 0 if ret_X_not_sliced: ret = np.zeros(X.shape) X, X2 = kern._slice_X(X) if not kern._sliced_X else X, kern._slice_X(X2) if X2 is not None and not kern._sliced_X else X2 kern._sliced_X += 1 try: - if ret_X_not_sliced: ret[:, kern.active_dims] = operation(dL_dK, X, X2) - else: ret = operation(dL_dK, X, X2) + if ret_X_not_sliced: ret[:, kern.active_dims] = operation(kern, dL_dK, X, X2) + else: ret = operation(kern, dL_dK, X, X2) except: raise finally: @@ -105,30 +107,30 @@ def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False return ret else: if diag: - def x_slice_wrapper(X, *args, **kw): + def x_slice_wrapper(kern, X, *args, **kw): X = kern._slice_X(X) if not kern._sliced_X else X kern._sliced_X += 1 try: - ret = operation(X, *args, **kw) + ret = operation(kern, X, *args, **kw) except: raise finally: kern._sliced_X -= 1 return ret else: - def x_slice_wrapper(X, X2=None, *args, **kw): + def x_slice_wrapper(kern, X, X2=None, *args, **kw): X, X2 = kern._slice_X(X) if not kern._sliced_X else X, kern._slice_X(X2) if X2 is not None and not kern._sliced_X else X2 kern._sliced_X += 1 try: - ret = operation(X, X2, *args, **kw) + ret = operation(kern, X, X2, *args, **kw) except: raise finally: kern._sliced_X -= 1 return ret x_slice_wrapper._operation = operation x_slice_wrapper.__name__ = ("slicer("+str(operation) - +(","+str(bool(diag)) if diag else'') - +(','+str(bool(derivative)) if derivative else '') + +(","+str('diag') if diag else'') + +(','+str('derivative') if derivative else '') +')') x_slice_wrapper.__doc__ = "**sliced**\n" + (operation.__doc__ or "") return x_slice_wrapper \ No newline at end of file From 9cf37ff10441f04f4d7fea6a2267b926fb695ad3 Mon Sep 17 00:00:00 2001 From: mzwiessele Date: Wed, 26 Mar 2014 15:03:06 +0000 Subject: [PATCH 3/5] started copy implementation, have to get rid of _getstate_ and _setstate_ --- GPy/core/gp.py | 15 ++++++++------- GPy/core/parameterization/parameter_core.py | 13 +++++++++---- GPy/core/parameterization/parameterized.py | 18 ++---------------- GPy/util/caching.py | 2 +- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/GPy/core/gp.py b/GPy/core/gp.py index 5be3e944..5b41f6d0 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -216,15 +216,16 @@ class GP(Model): """ - return Model._getstate(self) + [self.X, - self.num_data, - self.input_dim, - self.kern, - self.likelihood, - self.output_dim, - ] + return []#Model._getstate(self) + [self.X, +# self.num_data, +# self.input_dim, +# self.kern, +# self.likelihood, +# self.output_dim, +# ] def _setstate(self, state): + return self.output_dim = state.pop() self.likelihood = state.pop() self.kern = state.pop() diff --git a/GPy/core/parameterization/parameter_core.py b/GPy/core/parameterization/parameter_core.py index 1cdeee0b..b804a61a 100644 --- a/GPy/core/parameterization/parameter_core.py +++ b/GPy/core/parameterization/parameter_core.py @@ -902,15 +902,19 @@ class Parameterizable(OptimizationHandlable): #=========================================================================== def copy(self): """Returns a (deep) copy of the current model""" - raise NotImplementedError, "Copy is not yet implemented, TODO: Observable hierarchy" + #raise NotImplementedError, "Copy is not yet implemented, TODO: Observable hierarchy" import copy from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView from .lists_and_dicts import ArrayList + + param_mapping = [[] for _ in range(self.num_params)] dc = dict() for k, v in self.__dict__.iteritems(): if k not in ['_parent_', '_parameters_', '_parent_index_', '_observer_callables_'] + self.parameter_names(recursive=False): - if isinstance(v, (Constrainable, ParameterIndexOperations, ParameterIndexOperationsView)): + if v in self._parameters_: + param_mapping[self._parameters_.index(v)] += [k] + elif isinstance(v, (Constrainable, ParameterIndexOperations, ParameterIndexOperationsView)): dc[k] = v.copy() else: dc[k] = copy.deepcopy(v) @@ -928,9 +932,10 @@ class Parameterizable(OptimizationHandlable): s = self.__new__(self.__class__) s.__dict__ = dc - for p in params: + for p, mlist in zip(params, param_mapping): s.add_parameter(p, _ignore_added_names=True) - + for m in mlist: + setattr(s, m, p) return s #=========================================================================== diff --git a/GPy/core/parameterization/parameterized.py b/GPy/core/parameterization/parameterized.py index bc83d8c8..529d3733 100644 --- a/GPy/core/parameterization/parameterized.py +++ b/GPy/core/parameterization/parameterized.py @@ -110,29 +110,15 @@ class Parameterized(Parameterizable, Pickleable): Allways append the state of the inherited object and call down to the inherited object in _setstate!! """ - return [ - self._fixes_, - self.priors, - self.constraints, - self._parameters_, - self._name, - self._added_names_, - ] + return [] def _setstate(self, state): - self._added_names_ = state.pop() - self._name = state.pop() - self._parameters_ = state.pop() - self.constraints = state.pop() - self.priors = state.pop() - self._fixes_ = state.pop() - self._connect_parameters() self.parameters_changed() #=========================================================================== # Override copy to handle programmatically added observers #=========================================================================== def copy(self): - c = super(Pickleable, self).copy() + c = super(Parameterized, self).copy() c.add_observer(c, c._parameters_changed_notification, -100) return c diff --git a/GPy/util/caching.py b/GPy/util/caching.py index 282c9f8c..fcb0b726 100644 --- a/GPy/util/caching.py +++ b/GPy/util/caching.py @@ -48,7 +48,7 @@ class Cacher(object): if k in kw and kw[k] is not None: return self.operation(*args, **kw) # TODO: WARNING !!! Cache OFFSWITCH !!! WARNING - #return self.operation(*args) + # return self.operation(*args, **kw) #if the result is cached, return the cached computation state = [all(a is b for a, b in itertools.izip_longest(args, cached_i)) for cached_i in self.cached_inputs] From f8ff2c7df247e62c9451f523172f9691335fbbb0 Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 27 Mar 2014 08:05:22 +0000 Subject: [PATCH 4/5] kern merge commencing --- GPy/kern/_src/kernel_slice_operations.py | 231 +++++++++++------------ 1 file changed, 111 insertions(+), 120 deletions(-) diff --git a/GPy/kern/_src/kernel_slice_operations.py b/GPy/kern/_src/kernel_slice_operations.py index 9beb40ab..7fa98763 100644 --- a/GPy/kern/_src/kernel_slice_operations.py +++ b/GPy/kern/_src/kernel_slice_operations.py @@ -5,130 +5,121 @@ Created on 11 Mar 2014 ''' from ...core.parameterization.parameterized import ParametersChangedMeta import numpy as np +import functools class KernCallsViaSlicerMeta(ParametersChangedMeta): def __call__(self, *args, **kw): instance = super(ParametersChangedMeta, self).__call__(*args, **kw) - instance.K = _slice_wrapper(instance, instance.K) - instance.Kdiag = _slice_wrapper(instance, instance.Kdiag, diag=True) - instance.update_gradients_full = _slice_wrapper(instance, instance.update_gradients_full, diag=False, derivative=True) - instance.update_gradients_diag = _slice_wrapper(instance, instance.update_gradients_diag, diag=True, derivative=True) - instance.gradients_X = _slice_wrapper(instance, instance.gradients_X, diag=False, derivative=True, ret_X=True) - instance.gradients_X_diag = _slice_wrapper(instance, instance.gradients_X_diag, diag=True, derivative=True, ret_X=True) - instance.psi0 = _slice_wrapper(instance, instance.psi0, diag=False, derivative=False) - instance.psi1 = _slice_wrapper(instance, instance.psi1, diag=False, derivative=False) - instance.psi2 = _slice_wrapper(instance, instance.psi2, diag=False, derivative=False) - instance.update_gradients_expectations = _slice_wrapper(instance, instance.update_gradients_expectations, derivative=True, psi_stat=True) - instance.gradients_Z_expectations = _slice_wrapper(instance, instance.gradients_Z_expectations, derivative=True, psi_stat_Z=True, ret_X=True) - instance.gradients_qX_expectations = _slice_wrapper(instance, instance.gradients_qX_expectations, derivative=True, psi_stat=True, ret_X=True) + instance.K = _Slice_wrapper(instance, instance.K) + instance.Kdiag = _Slice_wrapper_diag(instance, instance.Kdiag) + + instance.update_gradients_full = _Slice_wrapper_derivative(instance, instance.update_gradients_full) + instance.update_gradients_diag = _Slice_wrapper_diag_derivative(instance, instance.update_gradients_diag) + + instance.gradients_X = _Slice_wrapper_grad_X(instance, instance.gradients_X) + instance.gradients_X_diag = _Slice_wrapper_grad_X_diag(instance, instance.gradients_X_diag) + + instance.psi0 = _Slice_wrapper(instance, instance.psi0) + instance.psi1 = _Slice_wrapper(instance, instance.psi1) + instance.psi2 = _Slice_wrapper(instance, instance.psi2) + + instance.update_gradients_expectations = _Slice_wrapper_psi_stat_derivative_no_ret(instance, instance.update_gradients_expectations) + instance.gradients_Z_expectations = _Slice_wrapper_psi_stat_derivative_Z(instance, instance.gradients_Z_expectations) + instance.gradients_qX_expectations = _Slice_wrapper_psi_stat_derivative(instance, instance.gradients_qX_expectations) instance.parameters_changed() return instance -def _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False, psi_stat_Z=False, ret_X=False): - """ - This method wraps the functions in kernel to make sure all kernels allways see their respective input dimension. - The different switches are: - diag: if X2 exists - derivative: if first arg is dL_dK - psi_stat: if first 3 args are dL_dpsi0..2 - psi_stat_Z: if first 2 args are dL_dpsi1..2 - """ - if derivative: - if diag: - def x_slice_wrapper(dL_dKdiag, X): - ret_X_not_sliced = ret_X and kern._sliced_X == 0 - if ret_X_not_sliced: - ret = np.zeros(X.shape) - X = kern._slice_X(X) if not kern._sliced_X else X - # if the return value is of shape X.shape, we need to make sure to return the right shape - kern._sliced_X += 1 - try: - if ret_X_not_sliced: ret[:, kern.active_dims] = operation(dL_dKdiag, X) - else: ret = operation(dL_dKdiag, X) - except: - raise - finally: - kern._sliced_X -= 1 - return ret - elif psi_stat: - def x_slice_wrapper(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): - ret_X_not_sliced = ret_X and kern._sliced_X == 0 - if ret_X_not_sliced: - ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) - Z, variational_posterior = kern._slice_X(Z) if not kern._sliced_X else Z, kern._slice_X(variational_posterior) if not kern._sliced_X else variational_posterior - kern._sliced_X += 1 - # if the return value is of shape X.shape, we need to make sure to return the right shape - try: - if ret_X_not_sliced: - ret = list(operation(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) - r2 = ret[:2] - ret[0] = ret1 - ret[1] = ret2 - ret[0][:, kern.active_dims] = r2[0] - ret[1][:, kern.active_dims] = r2[1] - del r2 - else: ret = operation(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior) - except: - raise - finally: - kern._sliced_X -= 1 - return ret - elif psi_stat_Z: - def x_slice_wrapper(dL_dpsi1, dL_dpsi2, Z, variational_posterior): - ret_X_not_sliced = ret_X and kern._sliced_X == 0 - if ret_X_not_sliced: ret = np.zeros(Z.shape) - Z, variational_posterior = kern._slice_X(Z) if not kern._sliced_X else Z, kern._slice_X(variational_posterior) if not kern._sliced_X else variational_posterior - kern._sliced_X += 1 - try: - if ret_X_not_sliced: - ret[:, kern.active_dims] = operation(dL_dpsi1, dL_dpsi2, Z, variational_posterior) - else: ret = operation(dL_dpsi1, dL_dpsi2, Z, variational_posterior) - except: - raise - finally: - kern._sliced_X -= 1 - return ret - else: - def x_slice_wrapper(dL_dK, X, X2=None): - ret_X_not_sliced = ret_X and kern._sliced_X == 0 - if ret_X_not_sliced: - ret = np.zeros(X.shape) - X, X2 = kern._slice_X(X) if not kern._sliced_X else X, kern._slice_X(X2) if X2 is not None and not kern._sliced_X else X2 - kern._sliced_X += 1 - try: - if ret_X_not_sliced: ret[:, kern.active_dims] = operation(dL_dK, X, X2) - else: ret = operation(dL_dK, X, X2) - except: - raise - finally: - kern._sliced_X -= 1 - return ret - else: - if diag: - def x_slice_wrapper(X, *args, **kw): - X = kern._slice_X(X) if not kern._sliced_X else X - kern._sliced_X += 1 - try: - ret = operation(X, *args, **kw) - except: - raise - finally: - kern._sliced_X -= 1 - return ret - else: - def x_slice_wrapper(X, X2=None, *args, **kw): - X, X2 = kern._slice_X(X) if not kern._sliced_X else X, kern._slice_X(X2) if X2 is not None and not kern._sliced_X else X2 - kern._sliced_X += 1 - try: - ret = operation(X, X2, *args, **kw) - except: raise - finally: - kern._sliced_X -= 1 - return ret - x_slice_wrapper._operation = operation - x_slice_wrapper.__name__ = ("slicer("+str(operation) - +(","+str(bool(diag)) if diag else'') - +(','+str(bool(derivative)) if derivative else '') - +')') - x_slice_wrapper.__doc__ = "**sliced**\n" + (operation.__doc__ or "") - return x_slice_wrapper \ No newline at end of file +class _Slice_wrap(object): + def __init__(self, instance, f): + self.k = instance + self.f = f + def copy_to(self, new_instance): + return self.__class__(new_instance, self.f) + def _slice_X(self, X): + return self.k._slice_X(X) if not self.k._sliced_X else X + def _slice_X_X2(self, X, X2): + return self.k._slice_X(X) if not self.k._sliced_X else X, self.k._slice_X(X2) if X2 is not None and not self.k._sliced_X else X2 + def __enter__(self): + self.k._sliced_X += 1 + return self + def __exit__(self, *a): + self.k._sliced_X -= 1 + +class _Slice_wrapper(_Slice_wrap): + def __call__(self, X, X2 = None, *a, **kw): + X, X2 = self._slice_X_X2(X, X2) + with self: + ret = self.f(X, X2, *a, **kw) + return ret + +class _Slice_wrapper_diag(_Slice_wrap): + def __call__(self, X, *a, **kw): + X = self._slice_X(X) + with self: + ret = self.f(X, *a, **kw) + return ret + +class _Slice_wrapper_derivative(_Slice_wrap): + def __call__(self, dL_dK, X, X2=None): + self._slice_X(X) + with self: + ret = self.f(dL_dK, X, X2) + return ret + +class _Slice_wrapper_diag_derivative(_Slice_wrap): + def __call__(self, dL_dKdiag, X): + X = self._slice_X(X) + with self: + ret = self.f(dL_dKdiag, X) + return ret + +class _Slice_wrapper_grad_X(_Slice_wrap): + def __call__(self, dL_dK, X, X2=None): + ret = np.zeros(X.shape) + X, X2 = self._slice_X_X2(X, X2) + with self: + ret[:, self.k.active_dims] = self.f(dL_dK, X, X2) + return ret + +class _Slice_wrapper_grad_X_diag(_Slice_wrap): + def __call__(self, dL_dKdiag, X): + ret = np.zeros(X.shape) + X = self._slice_X(X) + with self: + ret[:, self.k.active_dims] = self.f(dL_dKdiag, X) + return ret + +class _Slice_wrapper_psi_stat_derivative_no_ret(_Slice_wrap): + def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) + with self: + ret = self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior) + return ret + +class _Slice_wrapper_psi_stat_derivative(_Slice_wrap): + def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) + Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) + with self: + ret = list(self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) + r2 = ret[:2] + ret[0] = ret1 + ret[1] = ret2 + ret[0][:, self.k.active_dims] = r2[0] + ret[1][:, self.k.active_dims] = r2[1] + del r2 + return ret + +class _Slice_wrapper_psi_stat_derivative_Z(_Slice_wrap): + def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) + Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) + with self: + ret = list(self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) + r2 = ret[:2] + ret[0] = ret1 + ret[1] = ret2 + ret[0][:, self.k.active_dims] = r2[0] + ret[1][:, self.k.active_dims] = r2[1] + del r2 + return ret From e26e7370141113c5ac5ecbac34824819a6c941ab Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Thu, 27 Mar 2014 09:28:44 +0000 Subject: [PATCH 5/5] new slicing done and first attempts at copy and pickling full models --- GPy/kern/_src/kernel_slice_operations.py | 186 ++++++++++++----------- GPy/util/caching.py | 3 +- 2 files changed, 103 insertions(+), 86 deletions(-) diff --git a/GPy/kern/_src/kernel_slice_operations.py b/GPy/kern/_src/kernel_slice_operations.py index 6620f28c..21421cc0 100644 --- a/GPy/kern/_src/kernel_slice_operations.py +++ b/GPy/kern/_src/kernel_slice_operations.py @@ -5,118 +5,134 @@ Created on 11 Mar 2014 ''' from ...core.parameterization.parameterized import ParametersChangedMeta import numpy as np +from functools import wraps -def put_clean(dct, name, *args, **kw): +def put_clean(dct, name, func): if name in dct: dct['_clean_{}'.format(name)] = dct[name] - dct[name] = _slice_wrapper(None, dct[name], *args, **kw) - + dct[name] = func(dct[name]) + class KernCallsViaSlicerMeta(ParametersChangedMeta): def __new__(cls, name, bases, dct): - put_clean(dct, 'K') - put_clean(dct, 'Kdiag', diag=True) - put_clean(dct, 'update_gradients_full', diag=False, derivative=True) - put_clean(dct, 'gradients_X', diag=False, derivative=True, ret_X=True) - put_clean(dct, 'gradients_X_diag', diag=True, derivative=True, ret_X=True) - put_clean(dct, 'psi0', diag=False, derivative=False) - put_clean(dct, 'psi1', diag=False, derivative=False) - put_clean(dct, 'psi2', diag=False, derivative=False) - put_clean(dct, 'update_gradients_expectations', derivative=True, psi_stat=True) - put_clean(dct, 'gradients_Z_expectations', derivative=True, psi_stat_Z=True, ret_X=True) - put_clean(dct, 'gradients_qX_expectations', derivative=True, psi_stat=True, ret_X=True) + put_clean(dct, 'K', _slice_K) + put_clean(dct, 'Kdiag', _slice_Kdiag) + put_clean(dct, 'update_gradients_full', _slice_update_gradients_full) + put_clean(dct, 'update_gradients_diag', _slice_update_gradients_diag) + put_clean(dct, 'gradients_X', _slice_gradients_X) + put_clean(dct, 'gradients_X_diag', _slice_gradients_X_diag) + + put_clean(dct, 'psi0', _slice_psi) + put_clean(dct, 'psi1', _slice_psi) + put_clean(dct, 'psi2', _slice_psi) + put_clean(dct, 'update_gradients_expectations', _slice_update_gradients_expectations) + put_clean(dct, 'gradients_Z_expectations', _slice_gradients_Z_expectations) + put_clean(dct, 'gradients_qX_expectations', _slice_gradients_qX_expectations) return super(KernCallsViaSlicerMeta, cls).__new__(cls, name, bases, dct) - + class _Slice_wrap(object): - def __init__(self, instance, f): - self.k = instance - self.f = f - def copy_to(self, new_instance): - return self.__class__(new_instance, self.f) - def _slice_X(self, X): - return self.k._slice_X(X) if not self.k._sliced_X else X - def _slice_X_X2(self, X, X2): - return self.k._slice_X(X) if not self.k._sliced_X else X, self.k._slice_X(X2) if X2 is not None and not self.k._sliced_X else X2 + def __init__(self, k, X, X2=None): + self.k = k + self.shape = X.shape + if self.k._sliced_X == 0: + self.X = self.k._slice_X(X) + self.X2 = self.k._slice_X(X2) if X2 is not None else None + self.ret = True + else: + self.X = X + self.X2 = X2 + self.ret = False def __enter__(self): self.k._sliced_X += 1 return self def __exit__(self, *a): self.k._sliced_X -= 1 + def handle_return_array(self, return_val): + if self.ret: + ret = np.zeros(self.shape) + ret[:, self.k.active_dims] = return_val + return ret + return return_val -class _Slice_wrapper(_Slice_wrap): - def __call__(self, X, X2 = None, *a, **kw): - X, X2 = self._slice_X_X2(X, X2) - with self: - ret = self.f(X, X2, *a, **kw) +def _slice_K(f): + @wraps(f) + def wrap(self, X, X2 = None, *a, **kw): + with _Slice_wrap(self, X, X2) as s: + ret = f(self, s.X, s.X2, *a, **kw) return ret + return wrap -class _Slice_wrapper_diag(_Slice_wrap): - def __call__(self, X, *a, **kw): - X = self._slice_X(X) - with self: - ret = self.f(X, *a, **kw) +def _slice_Kdiag(f): + @wraps(f) + def wrap(self, X, *a, **kw): + with _Slice_wrap(self, X, None) as s: + ret = f(self, s.X, *a, **kw) return ret + return wrap -class _Slice_wrapper_derivative(_Slice_wrap): - def __call__(self, dL_dK, X, X2=None): - self._slice_X(X) - with self: - ret = self.f(dL_dK, X, X2) +def _slice_update_gradients_full(f): + @wraps(f) + def wrap(self, dL_dK, X, X2=None): + with _Slice_wrap(self, X, X2) as s: + ret = f(self, dL_dK, s.X, s.X2) return ret + return wrap -class _Slice_wrapper_diag_derivative(_Slice_wrap): - def __call__(self, dL_dKdiag, X): - X = self._slice_X(X) - with self: - ret = self.f(dL_dKdiag, X) +def _slice_update_gradients_diag(f): + @wraps(f) + def wrap(self, dL_dKdiag, X): + with _Slice_wrap(self, X, None) as s: + ret = f(self, dL_dKdiag, s.X) return ret + return wrap -class _Slice_wrapper_grad_X(_Slice_wrap): - def __call__(self, dL_dK, X, X2=None): - ret = np.zeros(X.shape) - X, X2 = self._slice_X_X2(X, X2) - with self: - ret[:, self.k.active_dims] = self.f(dL_dK, X, X2) +def _slice_gradients_X(f): + @wraps(f) + def wrap(self, dL_dK, X, X2=None): + with _Slice_wrap(self, X, X2) as s: + ret = s.handle_return_array(f(self, dL_dK, s.X, s.X2)) return ret + return wrap -class _Slice_wrapper_grad_X_diag(_Slice_wrap): - def __call__(self, dL_dKdiag, X): - ret = np.zeros(X.shape) - X = self._slice_X(X) - with self: - ret[:, self.k.active_dims] = self.f(dL_dKdiag, X) +def _slice_gradients_X_diag(f): + @wraps(f) + def wrap(self, dL_dKdiag, X): + with _Slice_wrap(self, X, None) as s: + ret = s.handle_return_array(f(self, dL_dKdiag, s.X)) return ret + return wrap -class _Slice_wrapper_psi_stat_derivative_no_ret(_Slice_wrap): - def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): - Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) - with self: - ret = self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior) +def _slice_psi(f): + @wraps(f) + def wrap(self, Z, variational_posterior): + with _Slice_wrap(self, Z, variational_posterior) as s: + ret = f(self, s.X, s.X2) return ret + return wrap -class _Slice_wrapper_psi_stat_derivative(_Slice_wrap): - def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): - ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) - Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) - with self: - ret = list(self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) +def _slice_update_gradients_expectations(f): + @wraps(f) + def wrap(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + with _Slice_wrap(self, Z, variational_posterior) as s: + ret = f(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, s.X, s.X2) + return ret + return wrap + +def _slice_gradients_Z_expectations(f): + @wraps(f) + def wrap(self, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + with _Slice_wrap(self, Z, variational_posterior) as s: + ret = s.handle_return_array(f(self, dL_dpsi1, dL_dpsi2, s.X, s.X2)) + return ret + return wrap + +def _slice_gradients_qX_expectations(f): + @wraps(f) + def wrap(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): + with _Slice_wrap(self, variational_posterior, Z) as s: + ret = list(f(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, s.X2, s.X)) r2 = ret[:2] - ret[0] = ret1 - ret[1] = ret2 - ret[0][:, self.k.active_dims] = r2[0] - ret[1][:, self.k.active_dims] = r2[1] - del r2 - return ret - -class _Slice_wrapper_psi_stat_derivative_Z(_Slice_wrap): - def __call__(self, dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior): - ret1, ret2 = np.zeros(variational_posterior.shape), np.zeros(variational_posterior.shape) - Z, variational_posterior = self._slice_X_X2(Z, variational_posterior) - with self: - ret = list(self.f(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, variational_posterior)) - r2 = ret[:2] - ret[0] = ret1 - ret[1] = ret2 - ret[0][:, self.k.active_dims] = r2[0] - ret[1][:, self.k.active_dims] = r2[1] + ret[0] = s.handle_return_array(r2[0]) + ret[1] = s.handle_return_array(r2[1]) del r2 return ret + return wrap diff --git a/GPy/util/caching.py b/GPy/util/caching.py index fcb0b726..0886d0c6 100644 --- a/GPy/util/caching.py +++ b/GPy/util/caching.py @@ -101,7 +101,7 @@ class Cacher(object): def __name__(self): return self.operation.__name__ -from functools import partial +from functools import partial, update_wrapper class Cacher_wrap(object): def __init__(self, f, limit, ignore_args, force_kwargs): @@ -109,6 +109,7 @@ class Cacher_wrap(object): self.ignore_args = ignore_args self.force_kwargs = force_kwargs self.f = f + update_wrapper(self, self.f) def __get__(self, obj, objtype=None): return partial(self, obj) def __call__(self, *args, **kwargs):