From 20e02e63a976a7c2cf50a1f80ca3a45983f9ec3c Mon Sep 17 00:00:00 2001 From: Max Zwiessele Date: Fri, 28 Feb 2014 16:58:24 +0000 Subject: [PATCH] global gradient test done and some parameterized fixes --- GPy/core/model.py | 8 +++- GPy/core/parameterization/array_core.py | 13 ------ GPy/core/parameterization/index_operations.py | 42 +------------------ GPy/core/parameterization/lists_and_dicts.py | 19 ++++++++- GPy/core/parameterization/param.py | 9 ++-- GPy/core/parameterization/parameter_core.py | 9 ++-- GPy/core/parameterization/parameterized.py | 32 ++------------ 7 files changed, 39 insertions(+), 93 deletions(-) diff --git a/GPy/core/model.py b/GPy/core/model.py index 0e3913c8..d27cbc69 100644 --- a/GPy/core/model.py +++ b/GPy/core/model.py @@ -226,6 +226,11 @@ class Model(Parameterized): TODO: valid args """ + if self.is_fixed: + raise RuntimeError, "Cannot optimize, when everything is fixed" + if self.size == 0: + raise RuntimeError, "Model without parameters cannot be minimized" + if optimizer is None: optimizer = self.preferred_optimizer @@ -294,9 +299,8 @@ class Model(Parameterized): dx = dx[transformed_index] gradient = gradient[transformed_index] - numerical_gradient = (f1 - f2) / (2 * dx) global_ratio = (f1 - f2) / (2 * np.dot(dx, np.where(gradient == 0, 1e-32, gradient))) - return (np.abs(1. - global_ratio) < tolerance) or (np.abs(gradient - numerical_gradient).mean() < tolerance) + return (np.abs(1. - global_ratio) < tolerance) else: # check the gradient of each parameter individually, and do some pretty printing try: diff --git a/GPy/core/parameterization/array_core.py b/GPy/core/parameterization/array_core.py index e9e5ca8c..cf353ead 100644 --- a/GPy/core/parameterization/array_core.py +++ b/GPy/core/parameterization/array_core.py @@ -6,19 +6,6 @@ __updated__ = '2013-12-16' import numpy as np from parameter_core import Observable -class ParamList(list): - """ - List to store ndarray-likes in. - It will look for 'is' instead of calling __eq__ on each element. - """ - def __contains__(self, other): - for el in self: - if el is other: - return True - return False - - pass - class ObservableArray(np.ndarray, Observable): """ An ndarray which reports changes to its observers. diff --git a/GPy/core/parameterization/index_operations.py b/GPy/core/parameterization/index_operations.py index 6450c41c..a9f3768e 100644 --- a/GPy/core/parameterization/index_operations.py +++ b/GPy/core/parameterization/index_operations.py @@ -5,47 +5,7 @@ Created on Oct 2, 2013 ''' import numpy from numpy.lib.function_base import vectorize -from param import Param -from collections import defaultdict - -class ParamDict(defaultdict): - def __init__(self): - """ - Default will be self._default, if not set otherwise - """ - defaultdict.__init__(self, self.default_factory) - - def __getitem__(self, key): - try: - return defaultdict.__getitem__(self, key) - except KeyError: - for a in self.iterkeys(): - if numpy.all(a==key) and a._parent_index_==key._parent_index_: - return defaultdict.__getitem__(self, a) - raise - - def __contains__(self, key): - if defaultdict.__contains__(self, key): - return True - for a in self.iterkeys(): - if numpy.all(a==key) and a._parent_index_==key._parent_index_: - return True - return False - - def __setitem__(self, key, value): - if isinstance(key, Param): - for a in self.iterkeys(): - if numpy.all(a==key) and a._parent_index_==key._parent_index_: - return super(ParamDict, self).__setitem__(a, value) - defaultdict.__setitem__(self, key, value) - -class SetDict(ParamDict): - def default_factory(self): - return set() - -class IntArrayDict(ParamDict): - def default_factory(self): - return numpy.int_([]) +from lists_and_dicts import IntArrayDict class ParameterIndexOperations(object): ''' diff --git a/GPy/core/parameterization/lists_and_dicts.py b/GPy/core/parameterization/lists_and_dicts.py index cdf9f5f6..5b13b3b5 100644 --- a/GPy/core/parameterization/lists_and_dicts.py +++ b/GPy/core/parameterization/lists_and_dicts.py @@ -4,7 +4,24 @@ Created on 27 Feb 2014 @author: maxz ''' -class ParamList(list): +from collections import defaultdict +class DefaultArrayDict(defaultdict): + def __init__(self): + """ + Default will be self._default, if not set otherwise + """ + defaultdict.__init__(self, self.default_factory) + +class SetDict(DefaultArrayDict): + def default_factory(self): + return set() + +class IntArrayDict(DefaultArrayDict): + def default_factory(self): + import numpy as np + return np.int_([]) + +class ArrayList(list): """ List to store ndarray-likes in. It will look for 'is' instead of calling __eq__ on each element. diff --git a/GPy/core/parameterization/param.py b/GPy/core/parameterization/param.py index d52442d1..22610a70 100644 --- a/GPy/core/parameterization/param.py +++ b/GPy/core/parameterization/param.py @@ -50,7 +50,7 @@ class Param(OptimizationHandlable, ObservableArray, Gradcheckable): obj._realsize_ = obj.size obj._realndim_ = obj.ndim obj._updated_ = False - from index_operations import SetDict + from lists_and_dicts import SetDict obj._tied_to_me_ = SetDict() obj._tied_to_ = [] obj._original_ = True @@ -232,7 +232,8 @@ class Param(OptimizationHandlable, ObservableArray, Gradcheckable): #=========================================================================== @property def is_fixed(self): - return self._highest_parent_._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) @@ -347,8 +348,8 @@ class ParamConcatenation(object): See :py:class:`GPy.core.parameter.Param` for more details on constraining. """ # self.params = params - from lists_and_dicts import ParamList - self.params = ParamList([]) + from lists_and_dicts import ArrayList + self.params = ArrayList([]) for p in params: for p in p.flattened_parameters: if p not in self.params: diff --git a/GPy/core/parameterization/parameter_core.py b/GPy/core/parameterization/parameter_core.py index 4b1b16e0..e7344fa5 100644 --- a/GPy/core/parameterization/parameter_core.py +++ b/GPy/core/parameterization/parameter_core.py @@ -335,6 +335,7 @@ class Constrainable(Nameable, Indexable): def _add_to_index_operations(self, which, reconstrained, transform, warning): if warning and reconstrained.size > 0: + # TODO: figure out which parameters have changed and only print those print "WARNING: reconstraining parameters {}".format(self.parameter_names() or self.name) which.add(transform, self._raveled_index()) @@ -419,8 +420,8 @@ import numpy as np class Parameterizable(OptimizationHandlable): def __init__(self, *args, **kwargs): super(Parameterizable, self).__init__(*args, **kwargs) - from GPy.core.parameterization.lists_and_dicts import ParamList - _parameters_ = ParamList() + from GPy.core.parameterization.lists_and_dicts import ArrayList + _parameters_ = ArrayList() self._added_names_ = set() def parameter_names(self, add_self=False, adjust_for_printing=False, recursive=True): @@ -482,7 +483,7 @@ class Parameterizable(OptimizationHandlable): """Returns a (deep) copy of the current model""" import copy from .index_operations import ParameterIndexOperations, ParameterIndexOperationsView - from .lists_and_dicts import ParamList + from .lists_and_dicts import ArrayList dc = dict() for k, v in self.__dict__.iteritems(): @@ -496,7 +497,7 @@ class Parameterizable(OptimizationHandlable): dc['_direct_parent_'] = None dc['_parent_index_'] = None - dc['_parameters_'] = ParamList() + dc['_parameters_'] = ArrayList() dc['constraints'].clear() dc['priors'].clear() dc['size'] = 0 diff --git a/GPy/core/parameterization/parameterized.py b/GPy/core/parameterization/parameterized.py index 56d785c3..6fd60442 100644 --- a/GPy/core/parameterization/parameterized.py +++ b/GPy/core/parameterization/parameterized.py @@ -9,7 +9,7 @@ from re import compile, _pattern_type from param import ParamConcatenation from parameter_core import Pickleable, Parameterizable, adjust_name_for_printing, Gradcheckable from transformations import __fixed__ -from array_core import ParamList +from lists_and_dicts import ArrayList class Parameterized(Parameterizable, Pickleable, Gradcheckable): """ @@ -56,7 +56,7 @@ class Parameterized(Parameterizable, Pickleable, Gradcheckable): def __init__(self, name=None, *a, **kw): super(Parameterized, self).__init__(name=name, parent=None, parent_index=None, *a, **kw) self._in_init_ = True - self._parameters_ = ParamList() + self._parameters_ = ArrayList() self.size = sum(p.size for p in self._parameters_) self.add_observer(self, self._parameters_changed_notification, -100) if not self._has_fixes(): @@ -265,16 +265,6 @@ class Parameterized(Parameterizable, Pickleable, Gradcheckable): if self._has_fixes(): return g[self._fixes_] return g - #=========================================================================== - # Indexable Handling - #=========================================================================== - def _backtranslate_index(self, param, ind): - # translate an index in parameterized indexing into the index of param - ind = ind - self._offset_for(param) - ind = ind[ind >= 0] - internal_offset = param._internal_offset() - ind = ind[ind < param.size + internal_offset] - return ind def _offset_for(self, param): # get the offset in the parameterized index array for param if param.has_parent(): @@ -300,35 +290,21 @@ class Parameterized(Parameterizable, Pickleable, Gradcheckable): """ return numpy.r_[:self.size] - #=========================================================================== - # Fixing parameters: - #=========================================================================== - def _fixes_for(self, param): - if self._has_fixes(): - return self._fixes_[self._raveled_index_for(param)] - return numpy.ones(self.size, dtype=bool)[self._raveled_index_for(param)] - #=========================================================================== # Convenience for fixed, tied checking of param: #=========================================================================== - def fixed_indices(self): - return np.array([x.is_fixed for x in self._parameters_]) - def _is_fixed(self, param): - # returns if the whole param is fixed - if not self._has_fixes(): - return False - return not self._fixes_[self._raveled_index_for(param)].any() - # return not self._fixes_[self._offset_for(param): self._offset_for(param)+param._realsize_].any() @property def is_fixed(self): for p in self._parameters_: if not p.is_fixed: return False return True + def _get_original(self, param): # if advanced indexing is activated it happens that the array is a copy # you can retrieve the original param through this method, by passing # the copy here return self._parameters_[param._parent_index_] + #=========================================================================== # Get/set parameters: #===========================================================================