mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-05-27 14:25:16 +02:00
Merge branch 'params' of github.com:SheffieldML/GPy into params
This commit is contained in:
commit
34ec8e08bf
6 changed files with 156 additions and 152 deletions
|
|
@ -222,15 +222,16 @@ class GP(Model):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return Model._getstate(self) + [self.X,
|
return []#Model._getstate(self) + [self.X,
|
||||||
self.num_data,
|
# self.num_data,
|
||||||
self.input_dim,
|
# self.input_dim,
|
||||||
self.kern,
|
# self.kern,
|
||||||
self.likelihood,
|
# self.likelihood,
|
||||||
self.output_dim,
|
# self.output_dim,
|
||||||
]
|
# ]
|
||||||
|
|
||||||
def _setstate(self, state):
|
def _setstate(self, state):
|
||||||
|
return
|
||||||
self.output_dim = state.pop()
|
self.output_dim = state.pop()
|
||||||
self.likelihood = state.pop()
|
self.likelihood = state.pop()
|
||||||
self.kern = state.pop()
|
self.kern = state.pop()
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,11 @@ class ArrayList(list):
|
||||||
return True
|
return True
|
||||||
return False
|
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
|
pass
|
||||||
|
|
|
||||||
|
|
@ -902,15 +902,19 @@ class Parameterizable(OptimizationHandlable):
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""Returns a (deep) copy of the current model"""
|
"""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
|
import copy
|
||||||
from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView
|
from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView
|
||||||
from .lists_and_dicts import ArrayList
|
from .lists_and_dicts import ArrayList
|
||||||
|
|
||||||
|
param_mapping = [[] for _ in range(self.num_params)]
|
||||||
|
|
||||||
dc = dict()
|
dc = dict()
|
||||||
for k, v in self.__dict__.iteritems():
|
for k, v in self.__dict__.iteritems():
|
||||||
if k not in ['_parent_', '_parameters_', '_parent_index_', '_observer_callables_'] + self.parameter_names(recursive=False):
|
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()
|
dc[k] = v.copy()
|
||||||
else:
|
else:
|
||||||
dc[k] = copy.deepcopy(v)
|
dc[k] = copy.deepcopy(v)
|
||||||
|
|
@ -928,9 +932,10 @@ class Parameterizable(OptimizationHandlable):
|
||||||
s = self.__new__(self.__class__)
|
s = self.__new__(self.__class__)
|
||||||
s.__dict__ = dc
|
s.__dict__ = dc
|
||||||
|
|
||||||
for p in params:
|
for p, mlist in zip(params, param_mapping):
|
||||||
s.add_parameter(p, _ignore_added_names=True)
|
s.add_parameter(p, _ignore_added_names=True)
|
||||||
|
for m in mlist:
|
||||||
|
setattr(s, m, p)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
|
|
|
||||||
|
|
@ -110,29 +110,15 @@ class Parameterized(Parameterizable, Pickleable):
|
||||||
Allways append the state of the inherited object
|
Allways append the state of the inherited object
|
||||||
and call down to the inherited object in _setstate!!
|
and call down to the inherited object in _setstate!!
|
||||||
"""
|
"""
|
||||||
return [
|
return []
|
||||||
self._fixes_,
|
|
||||||
self.priors,
|
|
||||||
self.constraints,
|
|
||||||
self._parameters_,
|
|
||||||
self._name,
|
|
||||||
self._added_names_,
|
|
||||||
]
|
|
||||||
|
|
||||||
def _setstate(self, state):
|
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()
|
self.parameters_changed()
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
# Override copy to handle programmatically added observers
|
# Override copy to handle programmatically added observers
|
||||||
#===========================================================================
|
#===========================================================================
|
||||||
def copy(self):
|
def copy(self):
|
||||||
c = super(Pickleable, self).copy()
|
c = super(Parameterized, self).copy()
|
||||||
c.add_observer(c, c._parameters_changed_notification, -100)
|
c.add_observer(c, c._parameters_changed_notification, -100)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,130 +5,134 @@ Created on 11 Mar 2014
|
||||||
'''
|
'''
|
||||||
from ...core.parameterization.parameterized import ParametersChangedMeta
|
from ...core.parameterization.parameterized import ParametersChangedMeta
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
def put_clean(dct, name, func):
|
||||||
|
if name in dct:
|
||||||
|
dct['_clean_{}'.format(name)] = dct[name]
|
||||||
|
dct[name] = func(dct[name])
|
||||||
|
|
||||||
class KernCallsViaSlicerMeta(ParametersChangedMeta):
|
class KernCallsViaSlicerMeta(ParametersChangedMeta):
|
||||||
def __call__(self, *args, **kw):
|
def __new__(cls, name, bases, dct):
|
||||||
instance = super(ParametersChangedMeta, self).__call__(*args, **kw)
|
put_clean(dct, 'K', _slice_K)
|
||||||
instance.K = _slice_wrapper(instance, instance.K)
|
put_clean(dct, 'Kdiag', _slice_Kdiag)
|
||||||
instance.Kdiag = _slice_wrapper(instance, instance.Kdiag, diag=True)
|
put_clean(dct, 'update_gradients_full', _slice_update_gradients_full)
|
||||||
instance.update_gradients_full = _slice_wrapper(instance, instance.update_gradients_full, diag=False, derivative=True)
|
put_clean(dct, 'update_gradients_diag', _slice_update_gradients_diag)
|
||||||
instance.update_gradients_diag = _slice_wrapper(instance, instance.update_gradients_diag, diag=True, derivative=True)
|
put_clean(dct, 'gradients_X', _slice_gradients_X)
|
||||||
instance.gradients_X = _slice_wrapper(instance, instance.gradients_X, diag=False, derivative=True, ret_X=True)
|
put_clean(dct, 'gradients_X_diag', _slice_gradients_X_diag)
|
||||||
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 _slice_wrapper(kern, operation, diag=False, derivative=False, psi_stat=False, psi_stat_Z=False, ret_X=False):
|
put_clean(dct, 'psi0', _slice_psi)
|
||||||
"""
|
put_clean(dct, 'psi1', _slice_psi)
|
||||||
This method wraps the functions in kernel to make sure all kernels allways see their respective input dimension.
|
put_clean(dct, 'psi2', _slice_psi)
|
||||||
The different switches are:
|
put_clean(dct, 'update_gradients_expectations', _slice_update_gradients_expectations)
|
||||||
diag: if X2 exists
|
put_clean(dct, 'gradients_Z_expectations', _slice_gradients_Z_expectations)
|
||||||
derivative: if first arg is dL_dK
|
put_clean(dct, 'gradients_qX_expectations', _slice_gradients_qX_expectations)
|
||||||
psi_stat: if first 3 args are dL_dpsi0..2
|
return super(KernCallsViaSlicerMeta, cls).__new__(cls, name, bases, dct)
|
||||||
psi_stat_Z: if first 2 args are dL_dpsi1..2
|
|
||||||
"""
|
class _Slice_wrap(object):
|
||||||
if derivative:
|
def __init__(self, k, X, X2=None):
|
||||||
if diag:
|
self.k = k
|
||||||
def x_slice_wrapper(dL_dKdiag, X):
|
self.shape = X.shape
|
||||||
ret_X_not_sliced = ret_X and kern._sliced_X == 0
|
if self.k._sliced_X == 0:
|
||||||
if ret_X_not_sliced:
|
self.X = self.k._slice_X(X)
|
||||||
ret = np.zeros(X.shape)
|
self.X2 = self.k._slice_X(X2) if X2 is not None else None
|
||||||
X = kern._slice_X(X) if not kern._sliced_X else X
|
self.ret = True
|
||||||
# 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:
|
else:
|
||||||
def x_slice_wrapper(dL_dK, X, X2=None):
|
self.X = X
|
||||||
ret_X_not_sliced = ret_X and kern._sliced_X == 0
|
self.X2 = X2
|
||||||
if ret_X_not_sliced:
|
self.ret = False
|
||||||
ret = np.zeros(X.shape)
|
def __enter__(self):
|
||||||
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
|
self.k._sliced_X += 1
|
||||||
kern._sliced_X += 1
|
return self
|
||||||
try:
|
def __exit__(self, *a):
|
||||||
if ret_X_not_sliced: ret[:, kern.active_dims] = operation(dL_dK, X, X2)
|
self.k._sliced_X -= 1
|
||||||
else: ret = operation(dL_dK, X, X2)
|
def handle_return_array(self, return_val):
|
||||||
except:
|
if self.ret:
|
||||||
raise
|
ret = np.zeros(self.shape)
|
||||||
finally:
|
ret[:, self.k.active_dims] = return_val
|
||||||
kern._sliced_X -= 1
|
return ret
|
||||||
return ret
|
return return_val
|
||||||
else:
|
|
||||||
if diag:
|
def _slice_K(f):
|
||||||
def x_slice_wrapper(X, *args, **kw):
|
@wraps(f)
|
||||||
X = kern._slice_X(X) if not kern._sliced_X else X
|
def wrap(self, X, X2 = None, *a, **kw):
|
||||||
kern._sliced_X += 1
|
with _Slice_wrap(self, X, X2) as s:
|
||||||
try:
|
ret = f(self, s.X, s.X2, *a, **kw)
|
||||||
ret = operation(X, *args, **kw)
|
return ret
|
||||||
except:
|
return wrap
|
||||||
raise
|
|
||||||
finally:
|
def _slice_Kdiag(f):
|
||||||
kern._sliced_X -= 1
|
@wraps(f)
|
||||||
return ret
|
def wrap(self, X, *a, **kw):
|
||||||
else:
|
with _Slice_wrap(self, X, None) as s:
|
||||||
def x_slice_wrapper(X, X2=None, *args, **kw):
|
ret = f(self, s.X, *a, **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
|
return ret
|
||||||
kern._sliced_X += 1
|
return wrap
|
||||||
try:
|
|
||||||
ret = operation(X, X2, *args, **kw)
|
def _slice_update_gradients_full(f):
|
||||||
except: raise
|
@wraps(f)
|
||||||
finally:
|
def wrap(self, dL_dK, X, X2=None):
|
||||||
kern._sliced_X -= 1
|
with _Slice_wrap(self, X, X2) as s:
|
||||||
return ret
|
ret = f(self, dL_dK, s.X, s.X2)
|
||||||
x_slice_wrapper._operation = operation
|
return ret
|
||||||
x_slice_wrapper.__name__ = ("slicer("+str(operation)
|
return wrap
|
||||||
+(","+str(bool(diag)) if diag else'')
|
|
||||||
+(','+str(bool(derivative)) if derivative else '')
|
def _slice_update_gradients_diag(f):
|
||||||
+')')
|
@wraps(f)
|
||||||
x_slice_wrapper.__doc__ = "**sliced**\n" + (operation.__doc__ or "")
|
def wrap(self, dL_dKdiag, X):
|
||||||
return x_slice_wrapper
|
with _Slice_wrap(self, X, None) as s:
|
||||||
|
ret = f(self, dL_dKdiag, s.X)
|
||||||
|
return ret
|
||||||
|
return wrap
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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] = s.handle_return_array(r2[0])
|
||||||
|
ret[1] = s.handle_return_array(r2[1])
|
||||||
|
del r2
|
||||||
|
return ret
|
||||||
|
return wrap
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class Cacher(object):
|
||||||
if k in kw and kw[k] is not None:
|
if k in kw and kw[k] is not None:
|
||||||
return self.operation(*args, **kw)
|
return self.operation(*args, **kw)
|
||||||
# TODO: WARNING !!! Cache OFFSWITCH !!! WARNING
|
# TODO: WARNING !!! Cache OFFSWITCH !!! WARNING
|
||||||
#return self.operation(*args)
|
# return self.operation(*args, **kw)
|
||||||
|
|
||||||
#if the result is cached, return the cached computation
|
#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]
|
state = [all(a is b for a, b in itertools.izip_longest(args, cached_i)) for cached_i in self.cached_inputs]
|
||||||
|
|
@ -101,7 +101,7 @@ class Cacher(object):
|
||||||
def __name__(self):
|
def __name__(self):
|
||||||
return self.operation.__name__
|
return self.operation.__name__
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial, update_wrapper
|
||||||
|
|
||||||
class Cacher_wrap(object):
|
class Cacher_wrap(object):
|
||||||
def __init__(self, f, limit, ignore_args, force_kwargs):
|
def __init__(self, f, limit, ignore_args, force_kwargs):
|
||||||
|
|
@ -109,6 +109,7 @@ class Cacher_wrap(object):
|
||||||
self.ignore_args = ignore_args
|
self.ignore_args = ignore_args
|
||||||
self.force_kwargs = force_kwargs
|
self.force_kwargs = force_kwargs
|
||||||
self.f = f
|
self.f = f
|
||||||
|
update_wrapper(self, self.f)
|
||||||
def __get__(self, obj, objtype=None):
|
def __get__(self, obj, objtype=None):
|
||||||
return partial(self, obj)
|
return partial(self, obj)
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue