mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-06-11 15:15:15 +02:00
Handpicked James Hensman's code that ensures that fixes the PDF of transformed variables. Fixed minor plotting bug.
This commit is contained in:
parent
d3730bb518
commit
8b384fd000
2 changed files with 169 additions and 87 deletions
|
|
@ -13,11 +13,12 @@ Observable Pattern for patameterization
|
|||
|
||||
"""
|
||||
|
||||
from transformations import Transformation,Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||
from .transformations import Transformation,Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||
import numpy as np
|
||||
import re
|
||||
import logging
|
||||
from updateable import Updateable
|
||||
from .updateable import Updateable
|
||||
from functools import reduce
|
||||
|
||||
class HierarchyError(Exception):
|
||||
"""
|
||||
|
|
@ -36,7 +37,7 @@ def adjust_name_for_printing(name):
|
|||
name = name.replace("/", "_l_").replace("@", '_at_')
|
||||
name = name.replace("(", "_of_").replace(")", "")
|
||||
if re.match(r'^[a-zA-Z_][a-zA-Z0-9-_]*$', name) is None:
|
||||
raise NameError, "name {} converted to {} cannot be further converted to valid python variable name!".format(name2, name)
|
||||
raise NameError("name {} converted to {} cannot be further converted to valid python variable name!".format(name2, name))
|
||||
return name
|
||||
return ''
|
||||
|
||||
|
|
@ -65,13 +66,13 @@ class Parentable(object):
|
|||
Gets called, when the parent changed, so we can adjust our
|
||||
inner attributes according to the new parent.
|
||||
"""
|
||||
raise NotImplementedError, "shouldnt happen, Parentable objects need to be able to change their parent"
|
||||
raise NotImplementedError("shouldnt happen, Parentable objects need to be able to change their parent")
|
||||
|
||||
def _disconnect_parent(self, *args, **kw):
|
||||
"""
|
||||
Disconnect this object from its parent
|
||||
"""
|
||||
raise NotImplementedError, "Abstract superclass"
|
||||
raise NotImplementedError("Abstract superclass")
|
||||
|
||||
@property
|
||||
def _highest_parent_(self):
|
||||
|
|
@ -109,7 +110,10 @@ class Pickleable(object):
|
|||
it properly.
|
||||
:param protocol: pickling protocol to use, python-pickle for details.
|
||||
"""
|
||||
import cPickle as pickle
|
||||
try: #Py2
|
||||
import cPickle as pickle
|
||||
except ImportError: #Py3
|
||||
import pickle
|
||||
if isinstance(f, str):
|
||||
with open(f, 'wb') as f:
|
||||
pickle.dump(self, f, protocol)
|
||||
|
|
@ -138,9 +142,9 @@ class Pickleable(object):
|
|||
which = self
|
||||
which.traverse_parents(parents.append) # collect parents
|
||||
for p in parents:
|
||||
if not memo.has_key(id(p)):memo[id(p)] = None # set all parents to be None, so they will not be copied
|
||||
if not memo.has_key(id(self.gradient)):memo[id(self.gradient)] = None # reset the gradient
|
||||
if not memo.has_key(id(self._fixes_)):memo[id(self._fixes_)] = None # fixes have to be reset, as this is now highest parent
|
||||
if not id(p) in memo :memo[id(p)] = None # set all parents to be None, so they will not be copied
|
||||
if not id(self.gradient) in memo:memo[id(self.gradient)] = None # reset the gradient
|
||||
if not id(self._fixes_) in memo :memo[id(self._fixes_)] = None # fixes have to be reset, as this is now highest parent
|
||||
copy = copy.deepcopy(self, memo) # and start the copy
|
||||
copy._parent_index_ = None
|
||||
copy._trigger_params_changed()
|
||||
|
|
@ -163,14 +167,16 @@ class Pickleable(object):
|
|||
'_Cacher_wrap__cachers', # never pickle cachers
|
||||
]
|
||||
dc = dict()
|
||||
for k,v in self.__dict__.iteritems():
|
||||
#py3 fix
|
||||
#for k,v in self.__dict__.iteritems():
|
||||
for k,v in self.__dict__.items():
|
||||
if k not in ignore_list:
|
||||
dc[k] = v
|
||||
return dc
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__.update(state)
|
||||
from lists_and_dicts import ObserverList
|
||||
from .lists_and_dicts import ObserverList
|
||||
self.observers = ObserverList()
|
||||
self._setup_observers()
|
||||
self._optimizer_copy_transformed = False
|
||||
|
|
@ -214,7 +220,7 @@ class Gradcheckable(Pickleable, Parentable):
|
|||
Perform the checkgrad on the model.
|
||||
TODO: this can be done more efficiently, when doing it inside here
|
||||
"""
|
||||
raise HierarchyError, "This parameter is not in a model with a likelihood, and, therefore, cannot be gradient checked!"
|
||||
raise HierarchyError("This parameter is not in a model with a likelihood, and, therefore, cannot be gradient checked!")
|
||||
|
||||
class Nameable(Gradcheckable):
|
||||
"""
|
||||
|
|
@ -268,7 +274,7 @@ class Indexable(Nameable, Updateable):
|
|||
def __init__(self, name, default_constraint=None, *a, **kw):
|
||||
super(Indexable, self).__init__(name=name, *a, **kw)
|
||||
self._default_constraint_ = default_constraint
|
||||
from index_operations import ParameterIndexOperations
|
||||
from .index_operations import ParameterIndexOperations
|
||||
self.constraints = ParameterIndexOperations()
|
||||
self.priors = ParameterIndexOperations()
|
||||
if self._default_constraint_ is not None:
|
||||
|
|
@ -310,7 +316,7 @@ class Indexable(Nameable, Updateable):
|
|||
that is an int array, containing the indexes for the flattened
|
||||
param inside this parameterized logic.
|
||||
"""
|
||||
from param import ParamConcatenation
|
||||
from .param import ParamConcatenation
|
||||
if isinstance(param, ParamConcatenation):
|
||||
return np.hstack((self._raveled_index_for(p) for p in param.params))
|
||||
return param._raveled_index() + self._offset_for(param)
|
||||
|
|
@ -407,7 +413,7 @@ class Indexable(Nameable, Updateable):
|
|||
repriorized = self.unset_priors()
|
||||
self._add_to_index_operations(self.priors, repriorized, prior, warning)
|
||||
|
||||
from domains import _REAL, _POSITIVE, _NEGATIVE
|
||||
from .domains import _REAL, _POSITIVE, _NEGATIVE
|
||||
if prior.domain is _POSITIVE:
|
||||
self.constrain_positive(warning)
|
||||
elif prior.domain is _NEGATIVE:
|
||||
|
|
@ -424,19 +430,38 @@ class Indexable(Nameable, Updateable):
|
|||
|
||||
def log_prior(self):
|
||||
"""evaluate the prior"""
|
||||
if self.priors.size > 0:
|
||||
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.
|
||||
if self.priors.size == 0:
|
||||
return 0.
|
||||
x = self.param_array
|
||||
#evaluate the prior log densities
|
||||
log_p = reduce(lambda a, b: a + b, (p.lnpdf(x[ind]).sum() for p, ind in self.priors.items()), 0)
|
||||
|
||||
#account for the transformation by evaluating the log Jacobian (where things are transformed)
|
||||
log_j = 0.
|
||||
priored_indexes = np.hstack([i for p, i in self.priors.items()])
|
||||
for c,j in self.constraints.items():
|
||||
if not isinstance(c, Transformation):continue
|
||||
for jj in j:
|
||||
if jj in priored_indexes:
|
||||
log_j += c.log_jacobian(x[jj])
|
||||
return log_p + log_j
|
||||
|
||||
def _log_prior_gradients(self):
|
||||
"""evaluate the gradients of the priors"""
|
||||
if self.priors.size > 0:
|
||||
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
|
||||
return 0.
|
||||
if self.priors.size == 0:
|
||||
return 0.
|
||||
x = self.param_array
|
||||
ret = np.zeros(x.size)
|
||||
#compute derivate of prior density
|
||||
[np.put(ret, ind, p.lnpdf_grad(x[ind])) for p, ind in self.priors.items()]
|
||||
#add in jacobian derivatives if transformed
|
||||
priored_indexes = np.hstack([i for p, i in self.priors.items()])
|
||||
for c,j in self.constraints.items():
|
||||
if not isinstance(c, Transformation):continue
|
||||
for jj in j:
|
||||
if jj in priored_indexes:
|
||||
ret[jj] += c.log_jacobian_grad(x[jj])
|
||||
return ret
|
||||
|
||||
#===========================================================================
|
||||
# Tie parameters together
|
||||
|
|
@ -471,7 +496,7 @@ class Indexable(Nameable, Updateable):
|
|||
self.param_array[...] = transform.initialize(self.param_array)
|
||||
reconstrained = self.unconstrain()
|
||||
added = self._add_to_index_operations(self.constraints, reconstrained, transform, warning)
|
||||
self.notify_observers(self, None if trigger_parent else -np.inf)
|
||||
self.trigger_update(trigger_parent)
|
||||
return added
|
||||
|
||||
def unconstrain(self, *transforms):
|
||||
|
|
@ -536,7 +561,7 @@ class Indexable(Nameable, Updateable):
|
|||
update the constraints and priors view, so that
|
||||
constraining is automized for the parent.
|
||||
"""
|
||||
from index_operations import ParameterIndexOperationsView
|
||||
from .index_operations import ParameterIndexOperationsView
|
||||
#if getattr(self, "_in_init_"):
|
||||
#import ipdb;ipdb.set_trace()
|
||||
#self.constraints.update(param.constraints, start)
|
||||
|
|
@ -558,7 +583,7 @@ class Indexable(Nameable, Updateable):
|
|||
"""
|
||||
if warning and reconstrained.size > 0:
|
||||
# TODO: figure out which parameters have changed and only print those
|
||||
print "WARNING: reconstraining parameters {}".format(self.hierarchy_name() or self.name)
|
||||
print("WARNING: reconstraining parameters {}".format(self.hierarchy_name() or self.name))
|
||||
index = self._raveled_index()
|
||||
which.add(what, index)
|
||||
return index
|
||||
|
|
@ -571,7 +596,7 @@ class Indexable(Nameable, Updateable):
|
|||
if len(transforms) == 0:
|
||||
transforms = which.properties()
|
||||
removed = np.empty((0,), dtype=int)
|
||||
for t in transforms:
|
||||
for t in list(transforms):
|
||||
unconstrained = which.remove(t, self._raveled_index())
|
||||
removed = np.union1d(removed, unconstrained)
|
||||
if t is __fixed__:
|
||||
|
|
@ -612,7 +637,9 @@ class OptimizationHandlable(Indexable):
|
|||
|
||||
if not self._optimizer_copy_transformed:
|
||||
self._optimizer_copy_.flat = self.param_array.flat
|
||||
[np.put(self._optimizer_copy_, ind, c.finv(self.param_array[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
#py3 fix
|
||||
#[np.put(self._optimizer_copy_, ind, c.finv(self.param_array[ind])) for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
[np.put(self._optimizer_copy_, ind, c.finv(self.param_array[ind])) for c, ind in self.constraints.items() if c != __fixed__]
|
||||
if self.has_parent() and (self.constraints[__fixed__].size != 0 or self._has_ties()):
|
||||
fixes = np.ones(self.size).astype(bool)
|
||||
fixes[self.constraints[__fixed__]] = FIXED
|
||||
|
|
@ -641,21 +668,25 @@ class OptimizationHandlable(Indexable):
|
|||
if f is None:
|
||||
self.param_array.flat = p
|
||||
[np.put(self.param_array, ind, c.f(self.param_array.flat[ind]))
|
||||
for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
#py3 fix
|
||||
#for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
for c, ind in self.constraints.items() if c != __fixed__]
|
||||
else:
|
||||
self.param_array.flat[f] = p
|
||||
[np.put(self.param_array, ind[f[ind]], c.f(self.param_array.flat[ind[f[ind]]]))
|
||||
for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
#py3 fix
|
||||
#for c, ind in self.constraints.iteritems() if c != __fixed__]
|
||||
for c, ind in self.constraints.items() if c != __fixed__]
|
||||
#self._highest_parent_.tie.propagate_val()
|
||||
|
||||
self._optimizer_copy_transformed = False
|
||||
self.trigger_update()
|
||||
|
||||
def _get_params_transformed(self):
|
||||
raise DeprecationWarning, "_get|set_params{_optimizer_copy_transformed} is deprecated, use self.optimizer array insetad!"
|
||||
raise DeprecationWarning("_get|set_params{_optimizer_copy_transformed} is deprecated, use self.optimizer array insetad!")
|
||||
#
|
||||
def _set_params_transformed(self, p):
|
||||
raise DeprecationWarning, "_get|set_params{_optimizer_copy_transformed} is deprecated, use self.optimizer array insetad!"
|
||||
raise DeprecationWarning("_get|set_params{_optimizer_copy_transformed} is deprecated, use self.optimizer array insetad!")
|
||||
|
||||
def _trigger_params_changed(self, trigger_parent=True):
|
||||
"""
|
||||
|
|
@ -680,19 +711,24 @@ class OptimizationHandlable(Indexable):
|
|||
constraint to it.
|
||||
"""
|
||||
self._highest_parent_.tie.collate_gradient()
|
||||
[np.put(g, i, c.gradfactor(self.param_array[i], g[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
#py3 fix
|
||||
#[np.put(g, i, c.gradfactor(self.param_array[i], g[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
[np.put(g, i, c.gradfactor(self.param_array[i], g[i])) for c, i in self.constraints.items() if c != __fixed__]
|
||||
if self._has_fixes(): return g[self._fixes_]
|
||||
return g
|
||||
|
||||
def _log_det_jacobian(self):
|
||||
def _transform_gradients_non_natural(self, g):
|
||||
"""
|
||||
Return the logarithm of the Jacobian needed for a proper change of
|
||||
variables.
|
||||
Transform the gradients by multiplying the gradient factor for each
|
||||
constraint to it.
|
||||
"""
|
||||
J = np.ones(self.param_array.shape)
|
||||
[np.put(J, i, c.jacobianfactor(self.param_array[i]))
|
||||
for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
return np.log(J).sum()
|
||||
self._highest_parent_.tie.collate_gradient()
|
||||
#py3 fix
|
||||
#[np.put(g, i, c.gradfactor_non_natural(self.param_array[i], g[i])) for c, i in self.constraints.iteritems() if c != __fixed__]
|
||||
[np.put(g, i, c.gradfactor_non_natural(self.param_array[i], g[i])) for c, i in self.constraints.items() if c != __fixed__]
|
||||
if self._has_fixes(): return g[self._fixes_]
|
||||
return g
|
||||
|
||||
|
||||
@property
|
||||
def num_params(self):
|
||||
|
|
@ -700,7 +736,7 @@ class OptimizationHandlable(Indexable):
|
|||
Return the number of parameters of this parameter_handle.
|
||||
Param objects will always return 0.
|
||||
"""
|
||||
raise NotImplemented, "Abstract, please implement in respective classes"
|
||||
raise NotImplemented("Abstract, please implement in respective classes")
|
||||
|
||||
def parameter_names(self, add_self=False, adjust_for_printing=False, recursive=True):
|
||||
"""
|
||||
|
|
@ -749,7 +785,9 @@ class OptimizationHandlable(Indexable):
|
|||
self.optimizer_array = x # makes sure all of the tied parameters get the same init (since there's only one prior object...)
|
||||
# now draw from prior where possible
|
||||
x = self.param_array.copy()
|
||||
[np.put(x, ind, p.rvs(ind.size)) for p, ind in self.priors.iteritems() if not p is None]
|
||||
#Py3 fix
|
||||
#[np.put(x, ind, p.rvs(ind.size)) for p, ind in self.priors.iteritems() if not p is None]
|
||||
[np.put(x, ind, p.rvs(ind.size)) for p, ind in self.priors.items() if not p is None]
|
||||
unfixlist = np.ones((self.size,),dtype=np.bool)
|
||||
unfixlist[self.constraints[__fixed__]] = False
|
||||
self.param_array.flat[unfixlist] = x.view(np.ndarray).ravel()[unfixlist]
|
||||
|
|
@ -808,7 +846,7 @@ class Parameterizable(OptimizationHandlable):
|
|||
A parameterisable class.
|
||||
|
||||
This class provides the parameters list (ArrayList) and standard parameter handling,
|
||||
such as {add|remove}_parameter(), traverse hierarchy and param_array, gradient_array
|
||||
such as {link|unlink}_parameter(), traverse hierarchy and param_array, gradient_array
|
||||
and the empty parameters_changed().
|
||||
|
||||
This class is abstract and should not be instantiated.
|
||||
|
|
@ -946,7 +984,7 @@ class Parameterizable(OptimizationHandlable):
|
|||
self._add_parameter_name(param, ignore_added_names)
|
||||
# and makes sure to not delete programmatically added parameters
|
||||
for other in self.parameters[::-1]:
|
||||
if other is not param and other.name.startswith(param.name):
|
||||
if other is not param and other.name == param.name:
|
||||
warn_and_retry(param, _name_digit.match(other.name))
|
||||
return
|
||||
if pname not in dir(self):
|
||||
|
|
@ -1041,6 +1079,9 @@ class Parameterizable(OptimizationHandlable):
|
|||
p = param_to_array(p)
|
||||
d = f.create_dataset(n,p.shape,dtype=p.dtype)
|
||||
d[:] = p
|
||||
if hasattr(self, 'param_array'):
|
||||
d = f.create_dataset('param_array',self.param_array.shape, dtype=self.param_array.dtype)
|
||||
d[:] = self.param_array
|
||||
f.close()
|
||||
except:
|
||||
raise 'Fails to write the parameters into a HDF5 file!'
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
|
||||
import numpy as np
|
||||
from domains import _POSITIVE,_NEGATIVE, _BOUNDED
|
||||
from .domains import _POSITIVE,_NEGATIVE, _BOUNDED
|
||||
import weakref
|
||||
|
||||
import sys
|
||||
|
|
@ -31,13 +31,16 @@ class Transformation(object):
|
|||
raise NotImplementedError
|
||||
def finv(self, model_param):
|
||||
raise NotImplementedError
|
||||
def jacobianfactor(self, model_param):
|
||||
def log_jacobian(self, model_param):
|
||||
"""
|
||||
Return log|det J| where J is the Jacobian of the inverse of the
|
||||
transformation.
|
||||
compute the log of the jacobian of f, evaluated at f(x)= model_param
|
||||
"""
|
||||
return np.abs([self.gradfactor(np.array([theta]), np.ones((1,)))[0]
|
||||
for theta in model_param])
|
||||
raise NotImplementedError
|
||||
def log_jacobian_grad(self, model_param):
|
||||
"""
|
||||
compute the drivative of the log of the jacobian of f, evaluated at f(x)= model_param
|
||||
"""
|
||||
raise NotImplementedError
|
||||
def gradfactor(self, model_param, dL_dmodel_param):
|
||||
""" df(opt_param)_dopt_param evaluated at self.f(opt_param)=model_param, times the gradient dL_dmodel_param,
|
||||
|
||||
|
|
@ -49,6 +52,8 @@ class Transformation(object):
|
|||
\frac{\frac{\partial L}{\partial f}\left(\left.\partial f(x)}{\partial x}\right|_{x=f^{-1}(f)\right)}
|
||||
"""
|
||||
raise NotImplementedError
|
||||
def gradfactor_non_natural(self, model_param, dL_dmodel_param):
|
||||
return self.gradfactor(model_param, dL_dmodel_param)
|
||||
def initialize(self, f):
|
||||
""" produce a sensible initial value for f(x)"""
|
||||
raise NotImplementedError
|
||||
|
|
@ -57,12 +62,10 @@ class Transformation(object):
|
|||
import matplotlib.pyplot as plt
|
||||
from ...plotting.matplot_dep import base_plots
|
||||
x = np.linspace(-8,8)
|
||||
base_plots.meanplot(x, self.f(x), ax=axes, *args, **kw)
|
||||
base_plots.meanplot(x, self.f(x),axes=axes*args,**kw)
|
||||
axes = plt.gca()
|
||||
axes.set_xlabel(xlabel)
|
||||
axes.set_ylabel(ylabel)
|
||||
return axes
|
||||
|
||||
def __str__(self):
|
||||
raise NotImplementedError
|
||||
def __repr__(self):
|
||||
|
|
@ -74,20 +77,46 @@ class Logexp(Transformation):
|
|||
return np.where(x>_lim_val, x, np.log1p(np.exp(np.clip(x, -_lim_val, _lim_val)))) + epsilon
|
||||
#raises overflow warning: return np.where(x>_lim_val, x, np.log(1. + np.exp(x)))
|
||||
def finv(self, f):
|
||||
return np.where(f>_lim_val, f, np.log(np.exp(f+epsilon) - 1.))
|
||||
return np.where(f>_lim_val, f, np.log(np.exp(f+1e-20) - 1.))
|
||||
def gradfactor(self, f, df):
|
||||
return np.einsum('i,i->i', df, np.where(f>_lim_val, 1., 1. - np.exp(-f)))
|
||||
def initialize(self, f):
|
||||
if np.any(f < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
return np.abs(f)
|
||||
def log_jacobian(self, model_param):
|
||||
return np.where(model_param>_lim_val, model_param, np.log(np.exp(model_param+1e-20) - 1.)) - model_param
|
||||
def log_jacobian_grad(self, model_param):
|
||||
return 1./(np.exp(model_param)-1.)
|
||||
def __str__(self):
|
||||
return '+ve'
|
||||
|
||||
class Exponent(Transformation):
|
||||
domain = _POSITIVE
|
||||
def f(self, x):
|
||||
return np.where(x<_lim_val, np.where(x>-_lim_val, np.exp(x), np.exp(-_lim_val)), np.exp(_lim_val))
|
||||
def finv(self, x):
|
||||
return np.log(x)
|
||||
def gradfactor(self, f, df):
|
||||
return np.einsum('i,i->i', df, f)
|
||||
def initialize(self, f):
|
||||
if np.any(f < 0.):
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
return np.abs(f)
|
||||
def log_jacobian(self, model_param):
|
||||
return np.log(model_param)
|
||||
def log_jacobian_grad(self, model_param):
|
||||
return 1./model_param
|
||||
def __str__(self):
|
||||
return '+ve'
|
||||
|
||||
|
||||
|
||||
class NormalTheta(Transformation):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -107,6 +136,7 @@ class NormalTheta(Transformation):
|
|||
# that the values are ok
|
||||
# Before:
|
||||
theta[self.var_indices] = np.abs(-.5/theta[self.var_indices])
|
||||
#theta[self.var_indices] = np.exp(-.5/theta[self.var_indices])
|
||||
theta[self.mu_indices] *= theta[self.var_indices]
|
||||
return theta # which is now {mu, var}
|
||||
|
||||
|
|
@ -115,6 +145,7 @@ class NormalTheta(Transformation):
|
|||
varp = muvar[self.var_indices]
|
||||
muvar[self.mu_indices] /= varp
|
||||
muvar[self.var_indices] = -.5/varp
|
||||
#muvar[self.var_indices] = -.5/np.log(varp)
|
||||
|
||||
return muvar # which is now {theta1, theta2}
|
||||
|
||||
|
|
@ -133,7 +164,7 @@ class NormalTheta(Transformation):
|
|||
|
||||
def initialize(self, f):
|
||||
if np.any(f[self.var_indices] < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
f[self.var_indices] = np.abs(f[self.var_indices])
|
||||
return f
|
||||
|
||||
|
|
@ -148,9 +179,10 @@ class NormalTheta(Transformation):
|
|||
self.var_indices = state[1]
|
||||
|
||||
class NormalNaturalAntti(NormalTheta):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
_logexp = Logexp()
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -179,7 +211,7 @@ class NormalNaturalAntti(NormalTheta):
|
|||
|
||||
def initialize(self, f):
|
||||
if np.any(f[self.var_indices] < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
f[self.var_indices] = np.abs(f[self.var_indices])
|
||||
return f
|
||||
|
||||
|
|
@ -187,8 +219,10 @@ class NormalNaturalAntti(NormalTheta):
|
|||
return "natantti"
|
||||
|
||||
class NormalEta(Transformation):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -220,7 +254,7 @@ class NormalEta(Transformation):
|
|||
|
||||
def initialize(self, f):
|
||||
if np.any(f[self.var_indices] < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
f[self.var_indices] = np.abs(f[self.var_indices])
|
||||
return f
|
||||
|
||||
|
|
@ -228,8 +262,10 @@ class NormalEta(Transformation):
|
|||
return "eta"
|
||||
|
||||
class NormalNaturalThroughTheta(NormalTheta):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -259,13 +295,28 @@ class NormalNaturalThroughTheta(NormalTheta):
|
|||
#=======================================================================
|
||||
return dmuvar # which is now the gradient multiplicator
|
||||
|
||||
def gradfactor_non_natural(self, muvar, dmuvar):
|
||||
mu = muvar[self.mu_indices]
|
||||
var = muvar[self.var_indices]
|
||||
#=======================================================================
|
||||
# theta gradients
|
||||
# This works and the gradient checks!
|
||||
dmuvar[self.mu_indices] *= var
|
||||
dmuvar[self.var_indices] *= 2*(var)**2
|
||||
dmuvar[self.var_indices] += 2*dmuvar[self.mu_indices]*mu
|
||||
#=======================================================================
|
||||
|
||||
return dmuvar # which is now the gradient multiplicator for {theta1, theta2}
|
||||
|
||||
def __str__(self):
|
||||
return "natgrad"
|
||||
|
||||
|
||||
class NormalNaturalWhooot(NormalTheta):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -299,8 +350,10 @@ class NormalNaturalWhooot(NormalTheta):
|
|||
return "natgrad"
|
||||
|
||||
class NormalNaturalThroughEta(NormalEta):
|
||||
"Do not use, not officially supported!"
|
||||
_instances = []
|
||||
def __new__(cls, mu_indices, var_indices):
|
||||
def __new__(cls, mu_indices=None, var_indices=None):
|
||||
"Do not use, not officially supported!"
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -341,7 +394,7 @@ class LogexpNeg(Transformation):
|
|||
return np.einsum('i,i->i', df, np.where(f>_lim_val, -1, -1 + np.exp(-f)))
|
||||
def initialize(self, f):
|
||||
if np.any(f < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
return np.abs(f)
|
||||
def __str__(self):
|
||||
return '+ve'
|
||||
|
|
@ -393,27 +446,11 @@ class LogexpClipped(Logexp):
|
|||
return np.einsum('i,i->i', df, gf) # np.where(f < self.lower, 0, gf)
|
||||
def initialize(self, f):
|
||||
if np.any(f < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
return np.abs(f)
|
||||
def __str__(self):
|
||||
return '+ve_c'
|
||||
|
||||
class Exponent(Transformation):
|
||||
# TODO: can't allow this to go to zero, need to set a lower bound. Similar with negative Exponent below. See old MATLAB code.
|
||||
domain = _POSITIVE
|
||||
def f(self, x):
|
||||
return np.where(x<_lim_val, np.where(x>-_lim_val, np.exp(x), np.exp(-_lim_val)), np.exp(_lim_val))
|
||||
def finv(self, x):
|
||||
return np.log(x)
|
||||
def gradfactor(self, f, df):
|
||||
return np.einsum('i,i->i', df, f)
|
||||
def initialize(self, f):
|
||||
if np.any(f < 0.):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
return np.abs(f)
|
||||
def __str__(self):
|
||||
return '+ve'
|
||||
|
||||
class NegativeExponent(Exponent):
|
||||
domain = _NEGATIVE
|
||||
def f(self, x):
|
||||
|
|
@ -449,7 +486,11 @@ class Logistic(Transformation):
|
|||
for instance in cls._instances:
|
||||
if instance().lower == lower and instance().upper == upper:
|
||||
return instance()
|
||||
o = super(Transformation, cls).__new__(cls, lower, upper, *args, **kwargs)
|
||||
newfunc = super(Transformation, cls).__new__
|
||||
if newfunc is object.__new__:
|
||||
o = newfunc(cls)
|
||||
else:
|
||||
o = newfunc(cls, lower, upper, *args, **kwargs)
|
||||
cls._instances.append(weakref.ref(o))
|
||||
return cls._instances[-1]()
|
||||
def __init__(self, lower, upper):
|
||||
|
|
@ -467,7 +508,7 @@ class Logistic(Transformation):
|
|||
return np.einsum('i,i->i', df, (f - self.lower) * (self.upper - f) / self.difference)
|
||||
def initialize(self, f):
|
||||
if np.any(np.logical_or(f < self.lower, f > self.upper)):
|
||||
print "Warning: changing parameters to satisfy constraints"
|
||||
print("Warning: changing parameters to satisfy constraints")
|
||||
#return np.where(np.logical_or(f < self.lower, f > self.upper), self.f(f * 0.), f)
|
||||
#FIXME: Max, zeros_like right?
|
||||
return np.where(np.logical_or(f < self.lower, f > self.upper), self.f(np.zeros_like(f)), f)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue