mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-05-30 14:35:15 +02:00
[GPU] GPU version of varDTC is ready
This commit is contained in:
commit
bbcba2553c
59 changed files with 2012 additions and 1186 deletions
|
|
@ -24,12 +24,6 @@ class ParameterIndexOperations(object):
|
|||
for t, i in constraints.iteritems():
|
||||
self.add(t, i)
|
||||
|
||||
def __getstate__(self):
|
||||
return self._properties
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._properties = state
|
||||
|
||||
def iteritems(self):
|
||||
return self._properties.iteritems()
|
||||
|
||||
|
|
@ -92,13 +86,18 @@ class ParameterIndexOperations(object):
|
|||
for i, v in parameter_index_view.iteritems():
|
||||
self.add(i, v+offset)
|
||||
|
||||
|
||||
def copy(self):
|
||||
return self.__deepcopy__(None)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return ParameterIndexOperations(dict(self.iteritems()))
|
||||
|
||||
def __getitem__(self, prop):
|
||||
return self._properties[prop]
|
||||
|
||||
def __delitem__(self, prop):
|
||||
del self._properties[prop]
|
||||
|
||||
def __str__(self, *args, **kwargs):
|
||||
import pprint
|
||||
return pprint.pformat(dict(self._properties))
|
||||
|
|
@ -183,7 +182,7 @@ class ParameterIndexOperationsView(object):
|
|||
|
||||
|
||||
def remove(self, prop, indices):
|
||||
removed = self._param_index_ops.remove(prop, indices+self._offset)
|
||||
removed = self._param_index_ops.remove(prop, numpy.array(indices)+self._offset)
|
||||
if removed.size > 0:
|
||||
return removed - self._size + 1
|
||||
return removed
|
||||
|
|
@ -193,6 +192,9 @@ class ParameterIndexOperationsView(object):
|
|||
ind = self._filter_index(self._param_index_ops[prop])
|
||||
return ind
|
||||
|
||||
def __delitem__(self, prop):
|
||||
self.remove(prop, self[prop])
|
||||
|
||||
def __str__(self, *args, **kwargs):
|
||||
import pprint
|
||||
return pprint.pformat(dict(self.iteritems()))
|
||||
|
|
@ -203,6 +205,9 @@ class ParameterIndexOperationsView(object):
|
|||
|
||||
|
||||
def copy(self):
|
||||
return self.__deepcopy__(None)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return ParameterIndexOperations(dict(self.iteritems()))
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ Created on 27 Feb 2014
|
|||
'''
|
||||
|
||||
from collections import defaultdict
|
||||
import weakref
|
||||
|
||||
def intarray_default_factory():
|
||||
import numpy as np
|
||||
|
|
@ -28,4 +29,90 @@ 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
|
||||
|
||||
class ObservablesList(object):
|
||||
def __init__(self):
|
||||
self._poc = []
|
||||
|
||||
def __getitem__(self, ind):
|
||||
p,o,c = self._poc[ind]
|
||||
return p, o(), c
|
||||
|
||||
def remove(self, priority, observable, callble):
|
||||
"""
|
||||
"""
|
||||
self.flush()
|
||||
for i in range(len(self) - 1, -1, -1):
|
||||
p,o,c = self[i]
|
||||
if priority==p and observable==o and callble==c:
|
||||
del self._poc[i]
|
||||
|
||||
def __repr__(self):
|
||||
return self._poc.__repr__()
|
||||
|
||||
def add(self, priority, observable, callble):
|
||||
ins = 0
|
||||
for pr, _, _ in self:
|
||||
if priority > pr:
|
||||
break
|
||||
ins += 1
|
||||
self._poc.insert(ins, (priority, weakref.ref(observable), callble))
|
||||
|
||||
def __str__(self):
|
||||
ret = []
|
||||
curr_p = None
|
||||
for p, o, c in self:
|
||||
curr = ''
|
||||
if curr_p != p:
|
||||
pre = "{!s}: ".format(p)
|
||||
curr_pre = pre
|
||||
else: curr_pre = " "*len(pre)
|
||||
curr_p = p
|
||||
curr += curr_pre
|
||||
ret.append(curr + ", ".join(map(repr, [o,c])))
|
||||
return '\n'.join(ret)
|
||||
|
||||
def flush(self):
|
||||
self._poc = [(p,o,c) for p,o,c in self._poc if o() is not None]
|
||||
|
||||
def __iter__(self):
|
||||
self.flush()
|
||||
for p, o, c in self._poc:
|
||||
if o() is not None:
|
||||
yield p, o(), c
|
||||
|
||||
def __len__(self):
|
||||
self.flush()
|
||||
return self._poc.__len__()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
self.flush()
|
||||
s = ObservablesList()
|
||||
import copy
|
||||
s._poc = copy.deepcopy(self._poc, memo)
|
||||
return s
|
||||
|
||||
def __getstate__(self):
|
||||
self.flush()
|
||||
from ...util.caching import Cacher
|
||||
obs = []
|
||||
for p, o, c in self:
|
||||
if (getattr(o, c.__name__, None) is not None
|
||||
and not isinstance(o, Cacher)):
|
||||
obs.append((p,o,c.__name__))
|
||||
return obs
|
||||
|
||||
def __setstate__(self, state):
|
||||
self._poc = []
|
||||
for p, o, c in state:
|
||||
self.add(p,o,getattr(o, c))
|
||||
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
# Copyright (c) 2012, GPy authors (see AUTHORS.txt).
|
||||
# Licensed under the BSD 3-clause license (see LICENSE.txt)
|
||||
|
||||
__updated__ = '2014-03-21'
|
||||
__updated__ = '2014-03-31'
|
||||
|
||||
import numpy as np
|
||||
from parameter_core import Observable
|
||||
from parameter_core import Observable, Pickleable
|
||||
|
||||
class ObsAr(np.ndarray, Observable):
|
||||
class ObsAr(np.ndarray, Pickleable, Observable):
|
||||
"""
|
||||
An ndarray which reports changes to its observers.
|
||||
The observers can add themselves with a callable, which
|
||||
|
|
@ -25,37 +25,34 @@ class ObsAr(np.ndarray, Observable):
|
|||
def __array_finalize__(self, obj):
|
||||
# see InfoArray.__array_finalize__ for comments
|
||||
if obj is None: return
|
||||
self._observer_callables_ = getattr(obj, '_observer_callables_', None)
|
||||
self.observers = getattr(obj, 'observers', None)
|
||||
|
||||
def __array_wrap__(self, out_arr, context=None):
|
||||
return out_arr.view(np.ndarray)
|
||||
|
||||
def copy(self):
|
||||
memo = {}
|
||||
memo[id(self)] = self
|
||||
return self.__deepcopy__(memo)
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
s = self.__new__(self.__class__, input_array=self.view(np.ndarray).copy())
|
||||
memo[id(self)] = s
|
||||
import copy
|
||||
s.__dict__.update(copy.deepcopy(self.__dict__, memo))
|
||||
return s
|
||||
|
||||
def __reduce__(self):
|
||||
func, args, state = np.ndarray.__reduce__(self)
|
||||
return func, args, (state, Observable._getstate(self))
|
||||
func, args, state = super(ObsAr, self).__reduce__()
|
||||
return func, args, (state, Pickleable.__getstate__(self))
|
||||
|
||||
def __setstate__(self, state):
|
||||
np.ndarray.__setstate__(self, state[0])
|
||||
Observable._setstate(self, state[1])
|
||||
|
||||
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
|
||||
Pickleable.__setstate__(self, state[1])
|
||||
|
||||
def __setitem__(self, s, val):
|
||||
if self._s_not_empty(s):
|
||||
super(ObsAr, self).__setitem__(s, val)
|
||||
self.notify_observers()
|
||||
super(ObsAr, self).__setitem__(s, val)
|
||||
self.notify_observers()
|
||||
|
||||
def __getslice__(self, start, stop):
|
||||
return self.__getitem__(slice(start, stop))
|
||||
|
|
@ -63,12 +60,6 @@ class ObsAr(np.ndarray, Observable):
|
|||
def __setslice__(self, start, stop, val):
|
||||
return self.__setitem__(slice(start, stop), val)
|
||||
|
||||
def __copy__(self, *args):
|
||||
return ObsAr(self.view(np.ndarray).copy())
|
||||
|
||||
def copy(self, *args):
|
||||
return self.__copy__(*args)
|
||||
|
||||
def __ilshift__(self, *args, **kwargs):
|
||||
r = np.ndarray.__ilshift__(self, *args, **kwargs)
|
||||
self.notify_observers()
|
||||
|
|
@ -143,77 +134,4 @@ class ObsAr(np.ndarray, Observable):
|
|||
def __imul__(self, *args, **kwargs):
|
||||
r = np.ndarray.__imul__(self, *args, **kwargs)
|
||||
self.notify_observers()
|
||||
return r
|
||||
|
||||
|
||||
# def __rrshift__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rrshift__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __ror__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__ror__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rxor__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rxor__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
|
||||
# def __rdivmod__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rdivmod__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __radd__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__radd__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rdiv__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rdiv__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rtruediv__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rtruediv__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rshift__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rshift__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rmul__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rmul__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rpow__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rpow__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
|
||||
# def __rsub__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rsub__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
# def __rfloordiv__(self, *args, **kwargs):
|
||||
# r = np.ndarray.__rfloordiv__(self, *args, **kwargs)
|
||||
# self.notify_observers()
|
||||
# return r
|
||||
|
||||
return r
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
import itertools
|
||||
import numpy
|
||||
from parameter_core import OptimizationHandlable, adjust_name_for_printing
|
||||
from array_core import ObsAr
|
||||
from observable_array import ObsAr
|
||||
|
||||
###### printing
|
||||
__constraints_name__ = "Constraint"
|
||||
|
|
@ -43,14 +43,13 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
_fixes_ = None
|
||||
_parameters_ = []
|
||||
def __new__(cls, name, input_array, default_constraint=None):
|
||||
obj = numpy.atleast_1d(super(Param, cls).__new__(cls, input_array=input_array, name=name, default_constraint=default_constraint))
|
||||
obj = numpy.atleast_1d(super(Param, cls).__new__(cls, input_array=input_array))
|
||||
cls.__name__ = "Param"
|
||||
obj._current_slice_ = (slice(obj.shape[0]),)
|
||||
obj._realshape_ = obj.shape
|
||||
obj._realsize_ = obj.size
|
||||
obj._realndim_ = obj.ndim
|
||||
obj._original_ = True
|
||||
obj._gradient_array_ = numpy.zeros(obj.shape, dtype=numpy.float64)
|
||||
return obj
|
||||
|
||||
def __init__(self, name, input_array, default_constraint=None, *a, **kw):
|
||||
|
|
@ -60,7 +59,7 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
import pydot
|
||||
node = pydot.Node(id(self), shape='record', label=self.name)
|
||||
G.add_node(node)
|
||||
for o in self._observer_callables_.keys():
|
||||
for o in self.observers.keys():
|
||||
label = o.name if hasattr(o, 'name') else str(o)
|
||||
observed_node = pydot.Node(id(o), label=label)
|
||||
G.add_node(observed_node)
|
||||
|
|
@ -87,74 +86,24 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
self.priors = getattr(obj, 'priors', None)
|
||||
|
||||
@property
|
||||
def _param_array_(self):
|
||||
def param_array(self):
|
||||
return self
|
||||
|
||||
@property
|
||||
def gradient(self):
|
||||
"""
|
||||
Return a view on the gradient, which is in the same shape as this parameter is.
|
||||
Note: this is not the real gradient array, it is just a view on it.
|
||||
|
||||
To work on the real gradient array use: self.full_gradient
|
||||
"""
|
||||
if getattr(self, '_gradient_array_', None) is None:
|
||||
self._gradient_array_ = numpy.empty(self._realshape_, dtype=numpy.float64)
|
||||
return self._gradient_array_[self._current_slice_]
|
||||
|
||||
@gradient.setter
|
||||
def gradient(self, val):
|
||||
self.gradient[:] = val
|
||||
|
||||
#===========================================================================
|
||||
# Pickling operations
|
||||
#===========================================================================
|
||||
def __reduce__(self):
|
||||
func, args, state = super(Param, self).__reduce__()
|
||||
return func, args, (state,
|
||||
(self._name,
|
||||
self._parent_,
|
||||
self._parent_index_,
|
||||
self._default_constraint_,
|
||||
self._current_slice_,
|
||||
self._realshape_,
|
||||
self._realsize_,
|
||||
self._realndim_,
|
||||
self.constraints,
|
||||
self.priors
|
||||
)
|
||||
)
|
||||
|
||||
def __setstate__(self, state):
|
||||
super(Param, self).__setstate__(state[0])
|
||||
state = list(state[1])
|
||||
self.priors = state.pop()
|
||||
self.constraints = state.pop()
|
||||
self._realndim_ = state.pop()
|
||||
self._realsize_ = state.pop()
|
||||
self._realshape_ = state.pop()
|
||||
self._current_slice_ = state.pop()
|
||||
self._default_constraint_ = state.pop()
|
||||
self._parent_index_ = state.pop()
|
||||
self._parent_ = state.pop()
|
||||
self._name = state.pop()
|
||||
|
||||
def copy(self, *args):
|
||||
constr = self.constraints.copy()
|
||||
priors = self.priors.copy()
|
||||
p = Param(self.name, self.view(numpy.ndarray).copy(), self._default_constraint_)
|
||||
p.constraints = constr
|
||||
p.priors = priors
|
||||
return p
|
||||
#===========================================================================
|
||||
# get/set parameters
|
||||
#===========================================================================
|
||||
# def _set_params(self, param, trigger_parent=True):
|
||||
# self.flat = param
|
||||
# if trigger_parent: min_priority = None
|
||||
# else: min_priority = -numpy.inf
|
||||
# self.notify_observers(None, min_priority)
|
||||
#
|
||||
# def _get_params(self):
|
||||
# return self.flat
|
||||
#
|
||||
# def _collect_gradient(self, target):
|
||||
# target += self.gradient.flat
|
||||
#
|
||||
# def _set_gradient(self, g):
|
||||
# self.gradient = g.reshape(self._realshape_)
|
||||
self._gradient_array_[self._current_slice_] = val
|
||||
|
||||
#===========================================================================
|
||||
# Array operations -> done
|
||||
|
|
@ -172,24 +121,6 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
def __setitem__(self, s, val):
|
||||
super(Param, self).__setitem__(s, val)
|
||||
|
||||
#===========================================================================
|
||||
# Index Operations:
|
||||
#===========================================================================
|
||||
#def _internal_offset(self):
|
||||
# internal_offset = 0
|
||||
# extended_realshape = numpy.cumprod((1,) + self._realshape_[:0:-1])[::-1]
|
||||
# for i, si in enumerate(self._current_slice_[:self._realndim_]):
|
||||
# if numpy.all(si == Ellipsis):
|
||||
# continue
|
||||
# if isinstance(si, slice):
|
||||
# a = si.indices(self._realshape_[i])[0]
|
||||
# elif isinstance(si, (list,numpy.ndarray,tuple)):
|
||||
# a = si[0]
|
||||
# else: a = si
|
||||
# if a < 0:
|
||||
# a = self._realshape_[i] + a
|
||||
# internal_offset += a * extended_realshape[i]
|
||||
# return internal_offset
|
||||
|
||||
def _raveled_index(self, slice_index=None):
|
||||
# return an index array on the raveled array, which is formed by the current_slice
|
||||
|
|
@ -235,13 +166,21 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
def is_fixed(self):
|
||||
from transformations import __fixed__
|
||||
return self.constraints[__fixed__].size == self.size
|
||||
#def round(self, decimals=0, out=None):
|
||||
# view = super(Param, self).round(decimals, out).view(Param)
|
||||
# view.__array_finalize__(self)
|
||||
# return view
|
||||
#round.__doc__ = numpy.round.__doc__
|
||||
|
||||
def _get_original(self, param):
|
||||
return self
|
||||
|
||||
#===========================================================================
|
||||
# Pickling and copying
|
||||
#===========================================================================
|
||||
def __deepcopy__(self, memo):
|
||||
s = self.__new__(self.__class__, name=self.name, input_array=self.view(numpy.ndarray).copy())
|
||||
memo[id(self)] = s
|
||||
import copy
|
||||
s.__dict__.update(copy.deepcopy(self.__dict__, memo))
|
||||
return s
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# Printing -> done
|
||||
#===========================================================================
|
||||
|
|
@ -250,7 +189,8 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
if self.size <= 1:
|
||||
return [str(self.view(numpy.ndarray)[0])]
|
||||
else: return [str(self.shape)]
|
||||
def parameter_names(self, add_self=False, adjust_for_printing=False):
|
||||
def parameter_names(self, add_self=False, adjust_for_printing=False, recursive=True):
|
||||
# this is just overwrighting the parameterized calls to parameter names, in order to maintain OOP
|
||||
if adjust_for_printing:
|
||||
return [adjust_name_for_printing(self.name)]
|
||||
return [self.name]
|
||||
|
|
@ -261,6 +201,9 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
def parameter_shapes(self):
|
||||
return [self.shape]
|
||||
@property
|
||||
def num_params(self):
|
||||
return 0
|
||||
@property
|
||||
def _constraints_str(self):
|
||||
return [' '.join(map(lambda c: str(c[0]) if c[1].size == self._realsize_ else "{" + str(c[0]) + "}", self.constraints.iteritems()))]
|
||||
@property
|
||||
|
|
@ -282,8 +225,8 @@ class Param(OptimizationHandlable, ObsAr):
|
|||
if isinstance(slice_index, (tuple, list)):
|
||||
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])
|
||||
i+=1
|
||||
clean_curr_slice += [range(self._realshape_[i])]
|
||||
if (all(isinstance(n, (numpy.ndarray, list, tuple)) for n in clean_curr_slice)
|
||||
and len(set(map(len, clean_curr_slice))) <= 1):
|
||||
return numpy.fromiter(itertools.izip(*clean_curr_slice),
|
||||
|
|
@ -368,7 +311,7 @@ class ParamConcatenation(object):
|
|||
#===========================================================================
|
||||
def __getitem__(self, s):
|
||||
ind = numpy.zeros(sum(self._param_sizes), dtype=bool); ind[s] = True;
|
||||
params = [p._param_array_[ind[ps]] for p,ps in zip(self.params, self._param_slices_) if numpy.any(p._param_array_[ind[ps]])]
|
||||
params = [p.param_array[ind[ps]] for p,ps in zip(self.params, self._param_slices_) if numpy.any(p.param_array[ind[ps]])]
|
||||
if len(params)==1: return params[0]
|
||||
return ParamConcatenation(params)
|
||||
def __setitem__(self, s, val, update=True):
|
||||
|
|
@ -381,7 +324,7 @@ class ParamConcatenation(object):
|
|||
if update:
|
||||
self.update_all_params()
|
||||
def values(self):
|
||||
return numpy.hstack([p._param_array_ for p in self.params])
|
||||
return numpy.hstack([p.param_array.flat for p in self.params])
|
||||
#===========================================================================
|
||||
# parameter operations:
|
||||
#===========================================================================
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@ Observable Pattern for patameterization
|
|||
|
||||
"""
|
||||
|
||||
from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||
from transformations import Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||
import numpy as np
|
||||
|
||||
__updated__ = '2014-03-24'
|
||||
__updated__ = '2014-03-31'
|
||||
|
||||
class HierarchyError(Exception):
|
||||
"""
|
||||
|
|
@ -31,71 +31,8 @@ def adjust_name_for_printing(name):
|
|||
return name.replace(" ", "_").replace(".", "_").replace("-", "_m_").replace("+", "_p_").replace("!", "_I_").replace("**", "_xx_").replace("*", "_x_").replace("/", "_l_").replace("@", '_at_')
|
||||
return ''
|
||||
|
||||
class InterfacePickleFunctions(object):
|
||||
def __init__(self, *a, **kw):
|
||||
super(InterfacePickleFunctions, self).__init__()
|
||||
|
||||
def _getstate(self):
|
||||
"""
|
||||
Returns the state of this class in a memento pattern.
|
||||
The state must be a list-like structure of all the fields
|
||||
this class needs to run.
|
||||
|
||||
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
|
||||
"""
|
||||
raise NotImplementedError, "To be able to use pickling you need to implement this method"
|
||||
def _setstate(self, state):
|
||||
"""
|
||||
Set the state (memento pattern) of this class to the given state.
|
||||
Usually this is just the counterpart to _getstate, such that
|
||||
an object is a copy of another when calling
|
||||
|
||||
copy = <classname>.__new__(*args,**kw)._setstate(<to_be_copied>._getstate())
|
||||
|
||||
See python doc "pickling" (`__getstate__` and `__setstate__`) for details.
|
||||
"""
|
||||
raise NotImplementedError, "To be able to use pickling you need to implement this method"
|
||||
|
||||
class Pickleable(InterfacePickleFunctions):
|
||||
"""
|
||||
Make an object pickleable (See python doc 'pickling').
|
||||
|
||||
This class allows for pickling support by Memento pattern.
|
||||
_getstate returns a memento of the class, which gets pickled.
|
||||
_setstate(<memento>) (re-)sets the state of the class to the memento
|
||||
"""
|
||||
def __init__(self, *a, **kw):
|
||||
super(Pickleable, self).__init__()
|
||||
#===========================================================================
|
||||
# Pickling operations
|
||||
#===========================================================================
|
||||
def pickle(self, f, protocol=-1):
|
||||
"""
|
||||
:param f: either filename or open file object to write to.
|
||||
if it is an open buffer, you have to make sure to close
|
||||
it properly.
|
||||
:param protocol: pickling protocol to use, python-pickle for details.
|
||||
"""
|
||||
import cPickle
|
||||
if isinstance(f, str):
|
||||
with open(f, 'w') as f:
|
||||
cPickle.dump(self, f, protocol)
|
||||
else:
|
||||
cPickle.dump(self, f, protocol)
|
||||
def __getstate__(self):
|
||||
if self._has_get_set_state():
|
||||
return self._getstate()
|
||||
return self.__dict__
|
||||
def __setstate__(self, state):
|
||||
if self._has_get_set_state():
|
||||
self._setstate(state)
|
||||
# TODO: maybe parameters_changed() here?
|
||||
return
|
||||
self.__dict__ = state
|
||||
def _has_get_set_state(self):
|
||||
return '_getstate' in vars(self.__class__) and '_setstate' in vars(self.__class__)
|
||||
|
||||
class Observable(Pickleable):
|
||||
class Observable(object):
|
||||
"""
|
||||
Observable pattern for parameterization.
|
||||
|
||||
|
|
@ -105,23 +42,25 @@ class Observable(Pickleable):
|
|||
"""
|
||||
_updated = True
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Observable, self).__init__(*args, **kwargs)
|
||||
self._observer_callables_ = []
|
||||
super(Observable, self).__init__()
|
||||
from lists_and_dicts import ObservablesList
|
||||
self.observers = ObservablesList()
|
||||
|
||||
def add_observer(self, observer, callble, priority=0):
|
||||
self._insert_sorted(priority, observer, callble)
|
||||
self.observers.add(priority, observer, callble)
|
||||
|
||||
def remove_observer(self, observer, callble=None):
|
||||
to_remove = []
|
||||
for p, obs, clble in self._observer_callables_:
|
||||
for poc in self.observers:
|
||||
_, obs, clble = poc
|
||||
if callble is not None:
|
||||
if (obs == observer) and (callble == clble):
|
||||
to_remove.append((p, obs, clble))
|
||||
to_remove.append(poc)
|
||||
else:
|
||||
if obs is observer:
|
||||
to_remove.append((p, obs, clble))
|
||||
to_remove.append(poc)
|
||||
for r in to_remove:
|
||||
self._observer_callables_.remove(r)
|
||||
self.observers.remove(*r)
|
||||
|
||||
def notify_observers(self, which=None, min_priority=None):
|
||||
"""
|
||||
|
|
@ -136,32 +75,18 @@ class Observable(Pickleable):
|
|||
if which is None:
|
||||
which = self
|
||||
if min_priority is None:
|
||||
[callble(self, which=which) for _, _, callble in self._observer_callables_]
|
||||
[callble(self, which=which) for _, _, callble in self.observers]
|
||||
else:
|
||||
for p, _, callble in self._observer_callables_:
|
||||
for p, _, callble in self.observers:
|
||||
if p <= min_priority:
|
||||
break
|
||||
callble(self, which=which)
|
||||
|
||||
def _insert_sorted(self, p, o, c):
|
||||
ins = 0
|
||||
for pr, _, _ in self._observer_callables_:
|
||||
if p > pr:
|
||||
break
|
||||
ins += 1
|
||||
self._observer_callables_.insert(ins, (p, o, c))
|
||||
|
||||
def _getstate(self):
|
||||
return [self._observer_callables_]
|
||||
|
||||
def _setstate(self, state):
|
||||
self._observer_callables_ = state.pop()
|
||||
|
||||
#===============================================================================
|
||||
# Foundation framework for parameterized and param objects:
|
||||
#===============================================================================
|
||||
|
||||
class Parentable(Observable):
|
||||
class Parentable(object):
|
||||
"""
|
||||
Enable an Object to have a parent.
|
||||
|
||||
|
|
@ -171,7 +96,7 @@ class Parentable(Observable):
|
|||
_parent_ = None
|
||||
_parent_index_ = None
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Parentable, self).__init__(*args, **kwargs)
|
||||
super(Parentable, self).__init__()
|
||||
|
||||
def has_parent(self):
|
||||
"""
|
||||
|
|
@ -207,7 +132,84 @@ class Parentable(Observable):
|
|||
"""
|
||||
pass
|
||||
|
||||
class Gradcheckable(Parentable):
|
||||
class Pickleable(object):
|
||||
"""
|
||||
Make an object pickleable (See python doc 'pickling').
|
||||
|
||||
This class allows for pickling support by Memento pattern.
|
||||
_getstate returns a memento of the class, which gets pickled.
|
||||
_setstate(<memento>) (re-)sets the state of the class to the memento
|
||||
"""
|
||||
def __init__(self, *a, **kw):
|
||||
super(Pickleable, self).__init__()
|
||||
#===========================================================================
|
||||
# Pickling operations
|
||||
#===========================================================================
|
||||
def pickle(self, f, protocol=-1):
|
||||
"""
|
||||
:param f: either filename or open file object to write to.
|
||||
if it is an open buffer, you have to make sure to close
|
||||
it properly.
|
||||
:param protocol: pickling protocol to use, python-pickle for details.
|
||||
"""
|
||||
import cPickle as pickle
|
||||
import pickle #TODO: cPickle
|
||||
if isinstance(f, str):
|
||||
with open(f, 'w') as f:
|
||||
pickle.dump(self, f, protocol)
|
||||
else:
|
||||
pickle.dump(self, f, protocol)
|
||||
|
||||
#===========================================================================
|
||||
# copy and pickling
|
||||
#===========================================================================
|
||||
def copy(self):
|
||||
"""Returns a (deep) copy of the current model"""
|
||||
#raise NotImplementedError, "Copy is not yet implemented, TODO: Observable hierarchy"
|
||||
import copy
|
||||
memo = {}
|
||||
memo[id(self._parent_)] = None
|
||||
memo[id(self.gradient)] = None
|
||||
memo[id(self.param_array)] = None
|
||||
memo[id(self._fixes_)] = None
|
||||
c = copy.deepcopy(self, memo)
|
||||
c._parent_index_ = None
|
||||
return c
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
s = self.__new__(self.__class__)
|
||||
memo[id(self)] = s
|
||||
import copy
|
||||
s.__dict__.update(copy.deepcopy(self.__dict__, memo))
|
||||
return s
|
||||
|
||||
def __getstate__(self):
|
||||
ignore_list = ([#'_parent_', '_parent_index_',
|
||||
#'observers',
|
||||
'_param_array_', '_gradient_array_', '_fixes_',
|
||||
'_Cacher_wrap__cachers']
|
||||
#+ self.parameter_names(recursive=False)
|
||||
)
|
||||
dc = dict()
|
||||
for k,v in self.__dict__.iteritems():
|
||||
if k not in ignore_list:
|
||||
#if hasattr(v, "__getstate__"):
|
||||
#dc[k] = v.__getstate__()
|
||||
#else:
|
||||
dc[k] = v
|
||||
return dc
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__.update(state)
|
||||
return self
|
||||
|
||||
#def __getstate__(self, memo):
|
||||
# raise NotImplementedError, "get state must be implemented to be able to pickle objects"
|
||||
|
||||
#def __setstate__(self, memo):
|
||||
# raise NotImplementedError, "set state must be implemented to be able to pickle objects"
|
||||
|
||||
class Gradcheckable(Pickleable, Parentable):
|
||||
"""
|
||||
Adds the functionality for an object to be gradcheckable.
|
||||
It is just a thin wrapper of a call to the highest parent for now.
|
||||
|
|
@ -312,7 +314,7 @@ class Indexable(object):
|
|||
raise NotImplementedError, "shouldnt happen, raveld index transformation required from non parameterization object?"
|
||||
|
||||
|
||||
class Constrainable(Nameable, Indexable):
|
||||
class Constrainable(Nameable, Indexable, Observable):
|
||||
"""
|
||||
Make an object constrainable with Priors and Transformations.
|
||||
TODO: Mappings!!
|
||||
|
|
@ -394,6 +396,7 @@ class Constrainable(Nameable, Indexable):
|
|||
self._fixes_[fixed_indices] = FIXED
|
||||
else:
|
||||
self._fixes_ = None
|
||||
del self.constraints[__fixed__]
|
||||
|
||||
def _has_fixes(self):
|
||||
return hasattr(self, "_fixes_") and self._fixes_ is not None and self._fixes_.size == self.size
|
||||
|
|
@ -429,14 +432,14 @@ class Constrainable(Nameable, Indexable):
|
|||
def log_prior(self):
|
||||
"""evaluate the prior"""
|
||||
if self.priors.size > 0:
|
||||
x = self._param_array_
|
||||
x = self.param_array
|
||||
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"""
|
||||
if self.priors.size > 0:
|
||||
x = self._param_array_
|
||||
x = self.param_array
|
||||
ret = np.zeros(x.size)
|
||||
[np.put(ret, ind, p.lnpdf_grad(x[ind])) for p, ind in self.priors.iteritems()]
|
||||
return ret
|
||||
|
|
@ -455,7 +458,7 @@ class Constrainable(Nameable, Indexable):
|
|||
Constrain the parameter to the given
|
||||
:py:class:`GPy.core.transformations.Transformation`.
|
||||
"""
|
||||
self._param_array_[:] = transform.initialize(self._param_array_)
|
||||
self.param_array[:] = transform.initialize(self.param_array)
|
||||
reconstrained = self.unconstrain()
|
||||
self._add_to_index_operations(self.constraints, reconstrained, transform, warning)
|
||||
self.notify_observers(self, None if trigger_parent else -np.inf)
|
||||
|
|
@ -565,14 +568,14 @@ class OptimizationHandlable(Constrainable):
|
|||
super(OptimizationHandlable, self).__init__(name, default_constraint=default_constraint, *a, **kw)
|
||||
|
||||
def transform(self):
|
||||
[np.put(self._param_array_, ind, c.finv(self._param_array_.flat[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
[np.put(self.param_array, ind, c.finv(self.param_array.flat[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
|
||||
def untransform(self):
|
||||
[np.put(self._param_array_, ind, c.f(self._param_array_.flat[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
[np.put(self.param_array, ind, c.f(self.param_array.flat[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
|
||||
def _get_params_transformed(self):
|
||||
# transformed parameters (apply transformation rules)
|
||||
p = self._param_array_.copy()
|
||||
p = self.param_array.copy()
|
||||
[np.put(p, ind, c.finv(p[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
if self.has_parent() and self.constraints[__fixed__].size != 0:
|
||||
fixes = np.ones(self.size).astype(bool)
|
||||
|
|
@ -583,14 +586,14 @@ class OptimizationHandlable(Constrainable):
|
|||
return p
|
||||
|
||||
def _set_params_transformed(self, p):
|
||||
if p is self._param_array_:
|
||||
if p is self.param_array:
|
||||
p = p.copy()
|
||||
if self.has_parent() and self.constraints[__fixed__].size != 0:
|
||||
fixes = np.ones(self.size).astype(bool)
|
||||
fixes[self.constraints[__fixed__]] = FIXED
|
||||
self._param_array_.flat[fixes] = p
|
||||
elif self._has_fixes(): self._param_array_.flat[self._fixes_] = p
|
||||
else: self._param_array_.flat = p
|
||||
self.param_array.flat[fixes] = p
|
||||
elif self._has_fixes(): self.param_array.flat[self._fixes_] = p
|
||||
else: self.param_array.flat = p
|
||||
self.untransform()
|
||||
self._trigger_params_changed()
|
||||
|
||||
|
|
@ -600,36 +603,29 @@ class OptimizationHandlable(Constrainable):
|
|||
|
||||
def _size_transformed(self):
|
||||
return self.size - self.constraints[__fixed__].size
|
||||
#
|
||||
# def _untransform_params(self, p):
|
||||
# # inverse apply transformations for parameters
|
||||
# #p = p.copy()
|
||||
# if self._has_fixes(): tmp = self._get_params(); tmp[self._fixes_] = p; p = tmp; del tmp
|
||||
# [np.put(p, ind, c.f(p[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
# return p
|
||||
#
|
||||
# def _get_params(self):
|
||||
# """
|
||||
# get all parameters
|
||||
# """
|
||||
# return self._param_array_
|
||||
# p = np.empty(self.size, dtype=np.float64)
|
||||
# if self.size == 0:
|
||||
# return p
|
||||
# [np.put(p, ind, par._get_params()) for ind, par in itertools.izip(self._param)]
|
||||
# return p
|
||||
|
||||
# def _set_params(self, params, trigger_parent=True):
|
||||
# self._param_array_.flat = params
|
||||
# if trigger_parent: min_priority = None
|
||||
# else: min_priority = -np.inf
|
||||
# self.notify_observers(None, min_priority)
|
||||
# don't overwrite this anymore!
|
||||
# raise NotImplementedError, "Abstract superclass: This needs to be implemented in Param and Parameterizable"
|
||||
@property
|
||||
def num_params(self):
|
||||
"""
|
||||
Return the number of parameters of this parameter_handle.
|
||||
Param objects will allways return 0.
|
||||
"""
|
||||
raise NotImplemented, "Abstract, please implement in respective classes"
|
||||
|
||||
#===========================================================================
|
||||
# Optimization handles:
|
||||
#===========================================================================
|
||||
def parameter_names(self, add_self=False, adjust_for_printing=False, recursive=True):
|
||||
"""
|
||||
Get the names of all parameters of this model.
|
||||
|
||||
:param bool add_self: whether to add the own name in front of names
|
||||
:param bool adjust_for_printing: whether to call `adjust_name_for_printing` on names
|
||||
:param bool recursive: whether to traverse through hierarchy and append leaf node names
|
||||
"""
|
||||
if adjust_for_printing: adjust = lambda x: adjust_name_for_printing(x)
|
||||
else: adjust = lambda x: x
|
||||
if recursive: names = [xi for x in self._parameters_ for xi in x.parameter_names(add_self=True, adjust_for_printing=adjust_for_printing)]
|
||||
else: names = [adjust(x.name) for x in self._parameters_]
|
||||
if add_self: names = map(lambda x: adjust(self.name) + "." + x, names)
|
||||
return names
|
||||
def _get_param_names(self):
|
||||
n = np.array([p.hierarchy_name() + '[' + str(i) + ']' for p in self.flattened_parameters for i in p._indices()])
|
||||
return n
|
||||
|
|
@ -663,16 +659,30 @@ class OptimizationHandlable(Constrainable):
|
|||
# For shared memory arrays. This does nothing in Param, but sets the memory
|
||||
# for all parameterized objects
|
||||
#===========================================================================
|
||||
@property
|
||||
def full_gradient(self):
|
||||
"""
|
||||
Note to users:
|
||||
This does not return the gradient in the right shape! Use self.gradient
|
||||
for the right gradient array.
|
||||
|
||||
To work on the gradient array, use this as the gradient handle.
|
||||
This method exists for in memory use of parameters.
|
||||
When trying to access the true gradient array, use this.
|
||||
"""
|
||||
self.gradient # <<< ensure _gradient_array_
|
||||
return self._gradient_array_
|
||||
|
||||
def _propagate_param_grad(self, parray, garray):
|
||||
pi_old_size = 0
|
||||
for pi in self._parameters_:
|
||||
pislice = slice(pi_old_size, pi_old_size + pi.size)
|
||||
|
||||
self._param_array_[pislice] = pi._param_array_.flat # , requirements=['C', 'W']).flat
|
||||
self._gradient_array_[pislice] = pi._gradient_array_.flat # , requirements=['C', 'W']).flat
|
||||
self.param_array[pislice] = pi.param_array.flat # , requirements=['C', 'W']).flat
|
||||
self.full_gradient[pislice] = pi.full_gradient.flat # , requirements=['C', 'W']).flat
|
||||
|
||||
pi._param_array_.data = parray[pislice].data
|
||||
pi._gradient_array_.data = garray[pislice].data
|
||||
pi.param_array.data = parray[pislice].data
|
||||
pi.full_gradient.data = garray[pislice].data
|
||||
|
||||
pi._propagate_param_grad(parray[pislice], garray[pislice])
|
||||
pi_old_size += pi.size
|
||||
|
|
@ -681,26 +691,32 @@ class Parameterizable(OptimizationHandlable):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super(Parameterizable, self).__init__(*args, **kwargs)
|
||||
from GPy.core.parameterization.lists_and_dicts import ArrayList
|
||||
_parameters_ = ArrayList()
|
||||
self._parameters_ = ArrayList()
|
||||
self.size = 0
|
||||
self._param_array_ = np.empty(self.size, dtype=np.float64)
|
||||
self._gradient_array_ = np.empty(self.size, dtype=np.float64)
|
||||
self._added_names_ = set()
|
||||
|
||||
def parameter_names(self, add_self=False, adjust_for_printing=False, recursive=True):
|
||||
"""
|
||||
Get the names of all parameters of this model.
|
||||
@property
|
||||
def param_array(self):
|
||||
if not hasattr(self, '_param_array_'):
|
||||
self._param_array_ = np.empty(self.size, dtype=np.float64)
|
||||
return self._param_array_
|
||||
|
||||
:param bool add_self: whether to add the own name in front of names
|
||||
:param bool adjust_for_printing: whether to call `adjust_name_for_printing` on names
|
||||
:param bool recursive: whether to traverse through hierarchy and append leaf node names
|
||||
"""
|
||||
if adjust_for_printing: adjust = lambda x: adjust_name_for_printing(x)
|
||||
else: adjust = lambda x: x
|
||||
if recursive: names = [xi for x in self._parameters_ for xi in x.parameter_names(add_self=True, adjust_for_printing=adjust_for_printing)]
|
||||
else: names = [adjust(x.name) for x in self._parameters_]
|
||||
if add_self: names = map(lambda x: adjust(self.name) + "." + x, names)
|
||||
return names
|
||||
@param_array.setter
|
||||
def param_array(self, arr):
|
||||
self._param_array_ = arr
|
||||
|
||||
#=========================================================================
|
||||
# Gradient handling
|
||||
#=========================================================================
|
||||
@property
|
||||
def gradient(self):
|
||||
if not hasattr(self, '_gradient_array_'):
|
||||
self._gradient_array_ = np.empty(self.size, dtype=np.float64)
|
||||
return self._gradient_array_
|
||||
|
||||
@gradient.setter
|
||||
def gradient(self, val):
|
||||
self._gradient_array_[:] = val
|
||||
|
||||
@property
|
||||
def num_params(self):
|
||||
|
|
@ -737,34 +753,6 @@ class Parameterizable(OptimizationHandlable):
|
|||
self._remove_parameter_name(None, old_name)
|
||||
self._add_parameter_name(param)
|
||||
|
||||
#=========================================================================
|
||||
# Gradient handling
|
||||
#=========================================================================
|
||||
@property
|
||||
def gradient(self):
|
||||
return self._gradient_array_
|
||||
|
||||
@gradient.setter
|
||||
def gradient(self, val):
|
||||
self._gradient_array_[:] = val
|
||||
#===========================================================================
|
||||
# def _collect_gradient(self, target):
|
||||
# [p._collect_gradient(target[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
||||
#===========================================================================
|
||||
|
||||
#===========================================================================
|
||||
# def _set_params(self, params, trigger_parent=True):
|
||||
# [p._set_params(params[s], trigger_parent=False) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
||||
# if trigger_parent: min_priority = None
|
||||
# else: min_priority = -np.inf
|
||||
# self.notify_observers(None, min_priority)
|
||||
#===========================================================================
|
||||
|
||||
#===========================================================================
|
||||
# def _set_gradient(self, g):
|
||||
# [p._set_gradient(g[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_)]
|
||||
#===========================================================================
|
||||
|
||||
def add_parameter(self, param, index=None, _ignore_added_names=False):
|
||||
"""
|
||||
:param parameters: the parameters to add
|
||||
|
|
@ -864,7 +852,7 @@ class Parameterizable(OptimizationHandlable):
|
|||
# no parameters for this class
|
||||
return
|
||||
old_size = 0
|
||||
self._param_array_ = np.empty(self.size, dtype=np.float64)
|
||||
self.param_array = np.empty(self.size, dtype=np.float64)
|
||||
self._gradient_array_ = np.empty(self.size, dtype=np.float64)
|
||||
|
||||
self._param_slices_ = []
|
||||
|
|
@ -874,15 +862,15 @@ class Parameterizable(OptimizationHandlable):
|
|||
|
||||
pslice = slice(old_size, old_size + p.size)
|
||||
# first connect all children
|
||||
p._propagate_param_grad(self._param_array_[pslice], self._gradient_array_[pslice])
|
||||
p._propagate_param_grad(self.param_array[pslice], self.full_gradient[pslice])
|
||||
# then connect children to self
|
||||
self._param_array_[pslice] = p._param_array_.flat # , requirements=['C', 'W']).ravel(order='C')
|
||||
self._gradient_array_[pslice] = p._gradient_array_.flat # , requirements=['C', 'W']).ravel(order='C')
|
||||
self.param_array[pslice] = p.param_array.flat # , requirements=['C', 'W']).ravel(order='C')
|
||||
self.full_gradient[pslice] = p.full_gradient.flat # , requirements=['C', 'W']).ravel(order='C')
|
||||
|
||||
if not p._param_array_.flags['C_CONTIGUOUS']:
|
||||
import ipdb;ipdb.set_trace()
|
||||
p._param_array_.data = self._param_array_[pslice].data
|
||||
p._gradient_array_.data = self._gradient_array_[pslice].data
|
||||
if not p.param_array.flags['C_CONTIGUOUS']:
|
||||
raise ValueError, "This should not happen! Please write an email to the developers with the code, which reproduces this error. All parameter arrays must be C_CONTIGUOUS"
|
||||
p.param_array.data = self.param_array[pslice].data
|
||||
p.full_gradient.data = self.full_gradient[pslice].data
|
||||
|
||||
self._param_slices_.append(pslice)
|
||||
|
||||
|
|
@ -898,41 +886,22 @@ class Parameterizable(OptimizationHandlable):
|
|||
self.notify_observers(which=which)
|
||||
|
||||
#===========================================================================
|
||||
# TODO: not working yet
|
||||
# Pickling
|
||||
#===========================================================================
|
||||
def __setstate__(self, state):
|
||||
super(Parameterizable, self).__setstate__(state)
|
||||
self._connect_parameters()
|
||||
self._connect_fixes()
|
||||
self._notify_parent_change()
|
||||
|
||||
self.parameters_changed()
|
||||
|
||||
def copy(self):
|
||||
"""Returns a (deep) copy of the current model"""
|
||||
raise NotImplementedError, "Copy is not yet implemented, TODO: Observable hierarchy"
|
||||
import copy
|
||||
from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView
|
||||
from .lists_and_dicts import ArrayList
|
||||
|
||||
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)):
|
||||
dc[k] = v.copy()
|
||||
else:
|
||||
dc[k] = copy.deepcopy(v)
|
||||
if k == '_parameters_':
|
||||
params = [p.copy() for p in v]
|
||||
|
||||
dc['_parent_'] = None
|
||||
dc['_parent_index_'] = None
|
||||
dc['_observer_callables_'] = []
|
||||
dc['_parameters_'] = ArrayList()
|
||||
dc['constraints'].clear()
|
||||
dc['priors'].clear()
|
||||
dc['size'] = 0
|
||||
|
||||
s = self.__new__(self.__class__)
|
||||
s.__dict__ = dc
|
||||
|
||||
for p in params:
|
||||
s.add_parameter(p, _ignore_added_names=True)
|
||||
|
||||
return s
|
||||
|
||||
c = super(Parameterizable, self).copy()
|
||||
c._connect_parameters()
|
||||
c._connect_fixes()
|
||||
c._notify_parent_change()
|
||||
return c
|
||||
#===========================================================================
|
||||
# From being parentable, we have to define the parent_change notification
|
||||
#===========================================================================
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class ParametersChangedMeta(type):
|
|||
instance.parameters_changed()
|
||||
return instance
|
||||
|
||||
class Parameterized(Parameterizable, Pickleable):
|
||||
class Parameterized(Parameterizable):
|
||||
"""
|
||||
Parameterized class
|
||||
|
||||
|
|
@ -63,7 +63,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
# Metaclass for parameters changed after init.
|
||||
# This makes sure, that parameters changed will always be called after __init__
|
||||
# **Never** call parameters_changed() yourself
|
||||
__metaclass__ = ParametersChangedMeta
|
||||
__metaclass__ = ParametersChangedMeta
|
||||
#===========================================================================
|
||||
def __init__(self, name=None, parameters=[], *a, **kw):
|
||||
super(Parameterized, self).__init__(name=name, *a, **kw)
|
||||
|
|
@ -90,7 +90,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
child_node = child.build_pydot(G)
|
||||
G.add_edge(pydot.Edge(node, child_node))
|
||||
|
||||
for o in self._observer_callables_.keys():
|
||||
for o in self.observers.keys():
|
||||
label = o.name if hasattr(o, 'name') else str(o)
|
||||
observed_node = pydot.Node(id(o), label=label)
|
||||
G.add_node(observed_node)
|
||||
|
|
@ -101,48 +101,13 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
return G
|
||||
return node
|
||||
|
||||
def _getstate(self):
|
||||
"""
|
||||
Get the current state of the class,
|
||||
here just all the indices, rest can get recomputed
|
||||
For inheriting from Parameterized:
|
||||
|
||||
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_,
|
||||
]
|
||||
|
||||
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.add_observer(c, c._parameters_changed_notification, -100)
|
||||
return c
|
||||
|
||||
#===========================================================================
|
||||
# Gradient control
|
||||
#===========================================================================
|
||||
def _transform_gradients(self, g):
|
||||
if self.has_parent():
|
||||
return g
|
||||
[numpy.put(g, i, g[i] * c.gradfactor(self._param_array_[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
[numpy.put(g, i, g[i] * c.gradfactor(self.param_array[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
if self._has_fixes(): return g[self._fixes_]
|
||||
return g
|
||||
|
||||
|
|
@ -174,7 +139,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
this is not in the global view of things!
|
||||
"""
|
||||
return numpy.r_[:self.size]
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# Convenience for fixed, tied checking of param:
|
||||
#===========================================================================
|
||||
|
|
@ -189,7 +154,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
# you can retrieve the original param through this method, by passing
|
||||
# the copy here
|
||||
return self._parameters_[param._parent_index_]
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# Get/set parameters:
|
||||
#===========================================================================
|
||||
|
|
@ -206,7 +171,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
|
||||
def __getitem__(self, name, paramlist=None):
|
||||
if isinstance(name, (int, slice, tuple, np.ndarray)):
|
||||
return self._param_array_[name]
|
||||
return self.param_array[name]
|
||||
else:
|
||||
if paramlist is None:
|
||||
paramlist = self.grep_param_names(name)
|
||||
|
|
@ -222,7 +187,7 @@ class Parameterized(Parameterizable, Pickleable):
|
|||
def __setitem__(self, name, value, paramlist=None):
|
||||
if isinstance(name, (slice, tuple, np.ndarray)):
|
||||
try:
|
||||
self._param_array_[name] = value
|
||||
self.param_array[name] = value
|
||||
except:
|
||||
raise ValueError, "Setting by slice or index only allowed with array-like"
|
||||
self._trigger_params_changed()
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class SpikeAndSlabPrior(VariationalPrior):
|
|||
self.pi.gradient = (gamma/self.pi - (1.-gamma)/(1.-self.pi)).sum(axis=0)
|
||||
|
||||
class VariationalPosterior(Parameterized):
|
||||
def __init__(self, means=None, variances=None, name=None, *a, **kw):
|
||||
def __init__(self, means=None, variances=None, name='latent space', *a, **kw):
|
||||
super(VariationalPosterior, self).__init__(name=name, *a, **kw)
|
||||
self.mean = Param("mean", means)
|
||||
self.variance = Param("variance", variances, Logexp())
|
||||
|
|
@ -124,6 +124,7 @@ class NormalPosterior(VariationalPosterior):
|
|||
import sys
|
||||
assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
|
||||
from ...plotting.matplot_dep import variational_plots
|
||||
import matplotlib
|
||||
return variational_plots.plot(self,*args)
|
||||
|
||||
class SpikeAndSlabPosterior(VariationalPosterior):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue