fixing now works, removing parameters needs fixing

This commit is contained in:
Max Zwiessele 2014-02-13 15:06:05 +00:00
parent d2e8807a88
commit f71af38505
7 changed files with 100 additions and 147 deletions

View file

@ -4,6 +4,7 @@ import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning) warnings.filterwarnings("ignore", category=DeprecationWarning)
import core import core
from core.parameterization import transformations
import models import models
import mappings import mappings
import inference import inference

View file

@ -57,9 +57,11 @@ class ParameterIndexOperations(object):
You can give an offset to set an offset for the given indices in the You can give an offset to set an offset for the given indices in the
index array, for multi-param handling. index array, for multi-param handling.
''' '''
def __init__(self): def __init__(self, constraints=None):
self._properties = IntArrayDict() self._properties = IntArrayDict()
#self._reverse = collections.defaultdict(list) if constraints is not None:
for t, i in constraints.iteritems():
self.add(t, i)
def __getstate__(self): def __getstate__(self):
return self._properties#, self._reverse return self._properties#, self._reverse
@ -191,7 +193,7 @@ class ParameterIndexOperationsView(object):
def indices(self): def indices(self):
[ind for ind in self.iterindices()] return [ind for ind in self.iterindices()]
def properties_for(self, index): def properties_for(self, index):
@ -206,6 +208,8 @@ class ParameterIndexOperationsView(object):
removed = self._param_index_ops.remove(prop, indices+self._offset) removed = self._param_index_ops.remove(prop, indices+self._offset)
if removed.size > 0: if removed.size > 0:
return removed - self._size + 1 return removed - self._size + 1
if self[prop].size == 0:
del self[prop]
return removed return removed
@ -222,6 +226,9 @@ class ParameterIndexOperationsView(object):
def update(self, parameter_index_view): def update(self, parameter_index_view):
for i, v in parameter_index_view.iteritems(): for i, v in parameter_index_view.iteritems():
self.add(i, v) self.add(i, v)
def copy(self):
return ParameterIndexOperations(dict(self.iteritems()))
pass pass

View file

@ -1,7 +1,7 @@
# Copyright (c) 2012, GPy authors (see AUTHORS.txt). # Copyright (c) 2012, GPy authors (see AUTHORS.txt).
# Licensed under the BSD 3-clause license (see LICENSE.txt) # Licensed under the BSD 3-clause license (see LICENSE.txt)
from transformations import Transformation, Logexp, NegativeLogexp, Logistic from transformations import Transformation, Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
__updated__ = '2013-12-16' __updated__ = '2013-12-16'
@ -10,11 +10,6 @@ def adjust_name_for_printing(name):
return name.replace(" ", "_").replace(".", "_").replace("-","").replace("+","").replace("!","").replace("*","").replace("/","") return name.replace(" ", "_").replace(".", "_").replace("-","").replace("+","").replace("!","").replace("*","").replace("/","")
return '' return ''
#===============================================================================
# Printing:
__fixed__ = "fixed"
#===============================================================================
class Observable(object): class Observable(object):
_observers_ = {} _observers_ = {}
def add_observer(self, observer, callble): def add_observer(self, observer, callble):
@ -119,6 +114,14 @@ class Indexable(object):
def _offset_for(self, param): def _offset_for(self, param):
raise NotImplementedError, "shouldnt happen, offset required from non parameterization object?" raise NotImplementedError, "shouldnt happen, offset required from non parameterization object?"
def _raveled_index_for(self, param):
"""
get the raveled index for a param
that is an int array, containing the indexes for the flattened
param inside this parameterized logic.
"""
raise NotImplementedError, "shouldnt happen, raveld index transformation required from non parameterization object?"
class Constrainable(Nameable, Indexable, Parameterizable): class Constrainable(Nameable, Indexable, Parameterizable):
def __init__(self, name, default_constraint=None): def __init__(self, name, default_constraint=None):
@ -126,6 +129,9 @@ class Constrainable(Nameable, Indexable, Parameterizable):
self._default_constraint_ = default_constraint self._default_constraint_ = default_constraint
from index_operations import ParameterIndexOperations from index_operations import ParameterIndexOperations
self.constraints = ParameterIndexOperations() self.constraints = ParameterIndexOperations()
if self._default_constraint_ is not None:
self.constrain(self._default_constraint_)
#=========================================================================== #===========================================================================
# Fixing Parameters: # Fixing Parameters:
#=========================================================================== #===========================================================================
@ -138,17 +144,40 @@ class Constrainable(Nameable, Indexable, Parameterizable):
if value is not None: if value is not None:
self[:] = value self[:] = value
self.constrain(__fixed__, warning=warning) self.constrain(__fixed__, warning=warning)
self._highest_parent_._set_fixed(self._raveled_index()) rav_i = self._highest_parent_._raveled_index_for(self)
self._highest_parent_._set_fixed(rav_i)
fix = constrain_fixed fix = constrain_fixed
def unconstrain_fixed(self): def unconstrain_fixed(self):
""" """
This parameter will no longer be fixed. This parameter will no longer be fixed.
""" """
unconstrained = self.unconstrain(__fixed__) unconstrained = self.unconstrain(__fixed__)
import ipdb;ipdb.set_trace() self._highest_parent_._set_unfixed(unconstrained)
self._highest_parent_._set_unfixed(unconstrained)
unfix = unconstrain_fixed unfix = unconstrain_fixed
def _set_fixed(self, index):
import numpy as np
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool)
self._fixes_[index] = FIXED
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _set_unfixed(self, index):
import numpy as np
if not self._has_fixes(): self._fixes_ = np.ones(self.size, dtype=bool)
#rav_i = self._raveled_index_for(param)[index]
self._fixes_[index] = UNFIXED
if np.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _connect_fixes(self):
import numpy as np
fixed_indices = self.constraints[__fixed__]
if fixed_indices.size > 0:
self._fixes_ = np.ones(self.size, dtype=bool) * UNFIXED
self._fixes_[fixed_indices] = FIXED
else:
self._fixes_ = None
#=========================================================================== #===========================================================================
# Constrain operations -> done # Constrain operations -> done
#=========================================================================== #===========================================================================
@ -174,18 +203,29 @@ class Constrainable(Nameable, Indexable, Parameterizable):
self._set_params(transform.initialize(self._get_params()), update=False) self._set_params(transform.initialize(self._get_params()), update=False)
reconstrained = self.unconstrain() reconstrained = self.unconstrain()
self.constraints.add(transform, self._raveled_index()) self.constraints.add(transform, self._raveled_index())
if reconstrained.size > 0: if warning and reconstrained.size > 0:
print "WARNING: reconstraining parameters {}".format(self.parameter_names) print "WARNING: reconstraining parameters {}".format(self.parameter_names)
if update: if update:
self._highest_parent_.parameters_changed() self._highest_parent_.parameters_changed()
# if self.has_parent():
# self._highest_parent_._add_constrain(self, transform, warning)
# else:
# for p in self._parameters_:
# self._add_constrain(p, transform, warning)
# if update:
# self.parameters_changed()
def unconstrain(self, *transforms):
"""
:param transforms: The transformations to unconstrain from.
remove all :py:class:`GPy.core.transformations.Transformation`
transformats of this parameter object.
"""
if len(transforms) == 0:
transforms = self.constraints.properties()
import numpy as np
removed = np.empty((0,),dtype=int)
for t in transforms:
unconstrained = self.constraints.remove(t, self._raveled_index())
removed = np.union1d(removed, unconstrained)
if t is __fixed__:
self._highest_parent_._set_unfixed(unconstrained)
return removed
def constrain_positive(self, warning=True, update=True): def constrain_positive(self, warning=True, update=True):
""" """
:param warning: print a warning if re-constraining parameters. :param warning: print a warning if re-constraining parameters.
@ -211,21 +251,6 @@ class Constrainable(Nameable, Indexable, Parameterizable):
""" """
self.constrain(Logistic(lower, upper), warning=warning, update=update) self.constrain(Logistic(lower, upper), warning=warning, update=update)
def unconstrain(self, *transforms):
"""
:param transforms: The transformations to unconstrain from.
remove all :py:class:`GPy.core.transformations.Transformation`
transformats of this parameter object.
"""
if len(transforms) == 0:
transforms = self.constraints.properties()
import numpy as np
removed = np.empty((0,),dtype=int)
for t in transforms:
removed = np.union1d(removed, self.constraints.remove(t, self._raveled_index()))
return removed
def unconstrain_positive(self): def unconstrain_positive(self):
""" """
Remove positive constraint of this parameter. Remove positive constraint of this parameter.

View file

@ -8,15 +8,10 @@ import cPickle
import itertools import itertools
from re import compile, _pattern_type from re import compile, _pattern_type
from param import ParamConcatenation, Param from param import ParamConcatenation, Param
from parameter_core import Constrainable, Pickleable, Observable, adjust_name_for_printing, Gradcheckable, __fixed__ from parameter_core import Constrainable, Pickleable, Observable, adjust_name_for_printing, Gradcheckable
from transformations import __fixed__, FIXED, UNFIXED
from array_core import ParamList from array_core import ParamList
#===============================================================================
# constants
FIXED = False
UNFIXED = True
#===============================================================================
class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable): class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
""" """
Parameterized class Parameterized class
@ -71,37 +66,6 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
self._added_names_ = set() self._added_names_ = set()
del self._in_init_ del self._in_init_
#===========================================================================
# Parameter connection for model creation:
#===========================================================================
# def set_as_parameter(self, name, array, gradient, index=None, gradient_parent=None):
# """
# :param name: name of the param (in print and plots), can be callable without parameters
# :type name: str, callable
# :param array: array which the param consists of
# :type array: array-like
# :param gradient: gradient method of the param
# :type gradient: callable
# :param index: (optional) index of the param when printing
#
# (:param gradient_parent: connect these parameters to this class, but tell
# updates to highest_parent, this is needed when parameterized classes
# contain parameterized classes, but want to access the parameters
# of their children)
#
#
# Set array (e.g. self.X) as param with name and gradient.
# I.e: self.set_as_parameter('curvature', self.lengthscale, self.dK_dlengthscale)
#
# Note: the order in which parameters are added can be adjusted by
# giving an index, of where to put this param in printing
# """
# if index is None:
# self._parameters_.append(Param(name, array, gradient))
# else:
# self._parameters_.insert(index, Param(name, array, gradient))
# self._connect_parameters(gradient_parent=gradient_parent)
def _has_fixes(self): def _has_fixes(self):
return hasattr(self, "_fixes_") and self._fixes_ is not None return hasattr(self, "_fixes_") and self._fixes_ is not None
@ -118,53 +82,22 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
# if param.has_parent(): # if param.has_parent():
# raise AttributeError, "parameter {} already in another model, create new object (or copy) for adding".format(param._short()) # raise AttributeError, "parameter {} already in another model, create new object (or copy) for adding".format(param._short())
if param in self._parameters_ and index is not None: if param in self._parameters_ and index is not None:
# make sure fixes and constraints are indexed right self.remove_parameter(param)
if self._has_fixes(): self.add_parameter(param, index)
param_slice = slice(self._offset_for(param), self._offset_for(param) + param.size)
dest_index = sum((p.size for p in self._parameters_[:index]))
dest_slice = slice(dest_index, dest_index + param.size)
fixes_param = self._fixes_[param_slice].copy()
self._fixes_[param_slice] = self._fixes_[dest_slice]
self._fixes_[dest_slice] = fixes_param
del self._parameters_[param._parent_index_]
self._parameters_.insert(index, param)
elif param not in self._parameters_: elif param not in self._parameters_:
# make sure the size is set # make sure the size is set
if not hasattr(self, 'size'):
self.size = sum(p.size for p in self._parameters_)
if index is None: if index is None:
self._parameters_.append(param) self._parameters_.append(param)
# make sure fixes and constraints are indexed right
if param._has_fixes(): fixes_param = param._fixes_.copy()
else: fixes_param = numpy.ones(param.size, dtype=bool)
if self._has_fixes(): self._fixes_ = np.r_[self._fixes_, fixes_param]
elif param._has_fixes(): self._fixes_ = np.r_[np.ones(self.size, dtype=bool), fixes_param]
else: else:
start = sum(p.size for p in self._parameters_[:index]) start = sum(p.size for p in self._parameters_[:index])
self.constraints.shift(start, param.size) self.constraints.shift(start, param.size)
self._parameters_.insert(index, param) self._parameters_.insert(index, param)
# make sure fixes and constraints are indexed right
if param._has_fixes(): fixes_param = param._fixes_.copy()
else: fixes_param = numpy.ones(param.size, dtype=bool)
ins = sum((p.size for p in self._parameters_[:index]))
if self._has_fixes(): self._fixes_ = np.r_[self._fixes_[:ins], fixes_param, self._fixes[ins:]]
elif not np.all(fixes_param):
self._fixes_ = np.ones(self.size + param.size, dtype=bool)
self._fixes_[ins:ins + param.size] = fixes_param
self.size += param.size self.size += param.size
else: else:
raise RuntimeError, """Parameter exists already added and no copy made""" raise RuntimeError, """Parameter exists already added and no copy made"""
self._connect_parameters() self._connect_parameters()
for p in self._parameters_: for p in self._parameters_:
p._parent_changed(self) p._parent_changed(self)
if param._default_constraint_ is not None:
param.constrain(param._default_constraint_, False)
if self._has_fixes() and np.all(self._fixes_): # ==UNFIXED
self._fixes_ = None
def add_parameters(self, *parameters): def add_parameters(self, *parameters):
""" """
@ -173,18 +106,20 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
""" """
[self.add_parameter(p) for p in parameters] [self.add_parameter(p) for p in parameters]
def remove_parameter(self, *names_params_indices): def remove_parameter(self, param):
""" """
:param names_params_indices: mix of parameter_names, param objects, or indices :param param: param object to remove from being a parameter of this parameterized object.
to remove from being a param of this parameterized object.
note: if it is a string object it will not (!) be regexp-matched
automatically.
""" """
self._parameters_ = ParamList([p for p in self._parameters_ if not param in self._parameters_:
if not (p._parent_index_ in names_params_indices raise RuntimeError, "Parameter {} does not belong to this object, remove parameters directly from their respective parents".format(param._short())
or p.name in names_params_indices del self._parameters_[param._parent_index_]
or p in names_params_indices)]) self.size -= param.size
constr = param.constraints.copy()
param.constraints.clear()
param.constraints = constr
param._direct_parent_ = None
param._parent_index_ = None
param._connect_fixes()
self._connect_parameters() self._connect_parameters()
def _connect_parameters(self): def _connect_parameters(self):
@ -214,6 +149,8 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
elif not (pname in not_unique): elif not (pname in not_unique):
self.__dict__[pname] = p self.__dict__[pname] = p
self._added_names_.add(pname) self._added_names_.add(pname)
self._connect_fixes()
#=========================================================================== #===========================================================================
# Pickling operations # Pickling operations
#=========================================================================== #===========================================================================
@ -337,7 +274,7 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
self._added_names_.add(pname) self._added_names_.add(pname)
self.__dict__[pname] = param self.__dict__[pname] = param
#=========================================================================== #===========================================================================
# Index Handling # Indexable Handling
#=========================================================================== #===========================================================================
def _backtranslate_index(self, param, ind): def _backtranslate_index(self, param, ind):
# translate an index in parameterized indexing into the index of param # translate an index in parameterized indexing into the index of param
@ -373,36 +310,10 @@ class Parameterized(Constrainable, Pickleable, Observable, Gradcheckable):
#=========================================================================== #===========================================================================
# Fixing parameters: # Fixing parameters:
#=========================================================================== #===========================================================================
def _set_fixed(self, param_or_index):
if not self._has_fixes(): self._fixes_ = numpy.ones(self.size, dtype=bool)
try:
param_or_index = self._raveled_index_for(param_or_index)
except AttributeError:
pass
self._fixes_[param_or_index] = FIXED
if numpy.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _set_unfixed(self, param_or_index):
if not self._has_fixes(): self._fixes_ = numpy.ones(self.size, dtype=bool)
try:
param_or_index = self._raveled_index_for(param_or_index)
except AttributeError:
pass
self._fixes_[param_or_index] = UNFIXED
for constr, ind in self.constraints.iteritems():
if constr is __fixed__:
self._fixes_[ind] = FIXED
if numpy.all(self._fixes_): self._fixes_ = None # ==UNFIXED
def _fixes_for(self, param): def _fixes_for(self, param):
if self._has_fixes(): if self._has_fixes():
return self._fixes_[self._raveled_index_for(param)] return self._fixes_[self._raveled_index_for(param)]
return numpy.ones(self.size, dtype=bool)[self._raveled_index_for(param)] return numpy.ones(self.size, dtype=bool)[self._raveled_index_for(param)]
# def _fix(self, param, warning=True):
# f = self._add_constrain(param, __fixed__, warning)
# self._set_fixed(f)
# def _unfix(self, param):
# if self._has_fixes():
# f = self._remove_constrain(param, __fixed__)
# self._set_unfixed(f)
#=========================================================================== #===========================================================================
# Convenience for fixed, tied checking of param: # Convenience for fixed, tied checking of param:
#=========================================================================== #===========================================================================

View file

@ -6,8 +6,17 @@ import numpy as np
from domains import _POSITIVE,_NEGATIVE, _BOUNDED from domains import _POSITIVE,_NEGATIVE, _BOUNDED
import sys import sys
import weakref import weakref
_lim_val = -np.log(sys.float_info.epsilon) _lim_val = -np.log(sys.float_info.epsilon)
#===============================================================================
# Fixing constants
__fixed__ = "fixed"
FIXED = False
UNFIXED = True
#===============================================================================
class Transformation(object): class Transformation(object):
domain = None domain = None
_instance = None _instance = None

View file

@ -53,7 +53,7 @@ class RBF(Kernpart):
self.variance = Param('variance', variance, Logexp()) self.variance = Param('variance', variance, Logexp())
self.lengthscale = Param('lengthscale', lengthscale) self.lengthscale = Param('lengthscale', lengthscale, Logexp())
self.lengthscale.add_observer(self, self.update_lengthscale) self.lengthscale.add_observer(self, self.update_lengthscale)
self.update_lengthscale(self.lengthscale) self.update_lengthscale(self.lengthscale)

View file

@ -4,7 +4,6 @@ import GPy
import numpy as np import numpy as np
import matplotlib as mpl import matplotlib as mpl
import time import time
import Image
try: try:
import visual import visual
visual_available = True visual_available = True
@ -324,6 +323,7 @@ class image_show(matplotlib_show):
else: else:
self.vals = 255*(self.vals - self.vals.min())/(self.vals.max() - self.vals.min()) self.vals = 255*(self.vals - self.vals.min())/(self.vals.max() - self.vals.min())
if not self.palette == []: # applying using an image palette (e.g. if the image has been quantized) if not self.palette == []: # applying using an image palette (e.g. if the image has been quantized)
from PIL import Image
self.vals = Image.fromarray(self.vals.astype('uint8')) self.vals = Image.fromarray(self.vals.astype('uint8'))
self.vals.putpalette(self.palette) # palette is a list, must be loaded before calling this function self.vals.putpalette(self.palette) # palette is a list, must be loaded before calling this function