mirror of
https://github.com/SheffieldML/GPy.git
synced 2026-05-30 14:35:15 +02:00
merge the discriminative prior to devel
This commit is contained in:
commit
2d89fa821a
72 changed files with 1681 additions and 1894 deletions
|
|
@ -49,11 +49,13 @@ class Param(Parameterizable, ObsAr):
|
|||
obj._realshape_ = obj.shape
|
||||
obj._realsize_ = obj.size
|
||||
obj._realndim_ = obj.ndim
|
||||
obj._original_ = True
|
||||
obj._original_ = obj
|
||||
return obj
|
||||
|
||||
def __init__(self, name, input_array, default_constraint=None, *a, **kw):
|
||||
self._in_init_ = True
|
||||
super(Param, self).__init__(name=name, default_constraint=default_constraint, *a, **kw)
|
||||
self._in_init_ = False
|
||||
|
||||
def build_pydot(self,G):
|
||||
import pydot
|
||||
|
|
@ -124,10 +126,10 @@ class Param(Parameterizable, ObsAr):
|
|||
#if not reduce(lambda a, b: a or numpy.any(b is Ellipsis), s, False) and len(s) <= self.ndim:
|
||||
# s += (Ellipsis,)
|
||||
new_arr = super(Param, self).__getitem__(s, *args, **kwargs)
|
||||
try:
|
||||
try:
|
||||
new_arr._current_slice_ = s
|
||||
new_arr._gradient_array_ = self.gradient[s]
|
||||
new_arr._original_ = self.base is new_arr.base
|
||||
new_arr._original_ = self._original_
|
||||
except AttributeError: pass # returning 0d array or float, double etc
|
||||
return new_arr
|
||||
|
||||
|
|
@ -157,29 +159,29 @@ class Param(Parameterizable, ObsAr):
|
|||
return self.constraints[__fixed__].size == self.size
|
||||
|
||||
def _get_original(self, param):
|
||||
return self
|
||||
return self._original_
|
||||
|
||||
#===========================================================================
|
||||
# Pickling and copying
|
||||
#===========================================================================
|
||||
def copy(self):
|
||||
return Parameterizable.copy(self, which=self)
|
||||
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
s = self.__new__(self.__class__, name=self.name, input_array=self.view(numpy.ndarray).copy())
|
||||
memo[id(self)] = s
|
||||
memo[id(self)] = s
|
||||
import copy
|
||||
Pickleable.__setstate__(s, copy.deepcopy(self.__getstate__(), memo))
|
||||
return s
|
||||
def _setup_observers(self):
|
||||
"""
|
||||
Setup the default observers
|
||||
|
||||
|
||||
1: pass through to parent, if present
|
||||
"""
|
||||
if self.has_parent():
|
||||
self.add_observer(self._parent_, self._parent_._pass_through_notify_observers, -np.inf)
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# Printing -> done
|
||||
#===========================================================================
|
||||
|
|
@ -249,6 +251,29 @@ class Param(Parameterizable, ObsAr):
|
|||
if ind.size > 4: indstr = ','.join(map(str, ind[:2])) + "..." + ','.join(map(str, ind[-2:]))
|
||||
else: indstr = ','.join(map(str, ind))
|
||||
return name + '[' + indstr + ']'
|
||||
|
||||
def _repr_html_(self, constr_matrix=None, indices=None, prirs=None, ties=None):
|
||||
"""Representation of the parameter in html for notebook display."""
|
||||
filter_ = self._current_slice_
|
||||
vals = self.flat
|
||||
if indices is None: indices = self._indices(filter_)
|
||||
ravi = self._raveled_index(filter_)
|
||||
if constr_matrix is None: constr_matrix = self.constraints.properties_for(ravi)
|
||||
if prirs is None: prirs = self.priors.properties_for(ravi)
|
||||
if ties is None: ties = self._ties_for(ravi)
|
||||
ties = [' '.join(map(lambda x: x, t)) for t in ties]
|
||||
header_format = """
|
||||
<tr>
|
||||
<td><b>{i}</b></td>
|
||||
<td><b>{x}</b></td>
|
||||
<td><b>{c}</b></td>
|
||||
<td><b>{p}</b></td>
|
||||
<td><b>{t}</b></td>
|
||||
</tr>"""
|
||||
header = header_format.format(x=self.hierarchy_name(), c=__constraints_name__, i=__index_name__, t=__tie_name__, p=__priors_name__) # nice header for printing
|
||||
if not ties: ties = itertools.cycle([''])
|
||||
return "\n".join(['<table>'] + [header] + ["<tr><td>{i}</td><td align=\"right\">{x}</td><td>{c}</td><td>{p}</td><td>{t}</td></tr>".format(x=x, c=" ".join(map(str, c)), p=" ".join(map(str, p)), t=(t or ''), i=i) for i, x, c, t, p in itertools.izip(indices, vals, constr_matrix, ties, prirs)] + ["</table>"])
|
||||
|
||||
def __str__(self, constr_matrix=None, indices=None, prirs=None, ties=None, lc=None, lx=None, li=None, lp=None, lt=None, only_name=False):
|
||||
filter_ = self._current_slice_
|
||||
vals = self.flat
|
||||
|
|
|
|||
|
|
@ -14,12 +14,11 @@ Observable Pattern for patameterization
|
|||
"""
|
||||
|
||||
from transformations import Transformation,Logexp, NegativeLogexp, Logistic, __fixed__, FIXED, UNFIXED
|
||||
from ...util.misc import param_to_array
|
||||
import numpy as np
|
||||
import re
|
||||
import logging
|
||||
|
||||
__updated__ = '2014-05-21'
|
||||
__updated__ = '2014-10-09'
|
||||
|
||||
class HierarchyError(Exception):
|
||||
"""
|
||||
|
|
@ -64,7 +63,7 @@ class Observable(object):
|
|||
@updates.setter
|
||||
def updates(self, ups):
|
||||
raise DeprecationWarning("updates is now a function, see update(True|False|None)")
|
||||
|
||||
|
||||
def update_model(self, updates=None):
|
||||
"""
|
||||
Get or set, whether automatic updates are performed. When updates are
|
||||
|
|
@ -88,21 +87,23 @@ class Observable(object):
|
|||
else:
|
||||
self._updates = updates
|
||||
self.trigger_update()
|
||||
|
||||
|
||||
def toggle_update(self):
|
||||
self.update_model(not self.update())
|
||||
|
||||
def trigger_update(self):
|
||||
def trigger_update(self, trigger_parent=True):
|
||||
"""
|
||||
Update the model from the current state.
|
||||
Make sure that updates are on, otherwise this
|
||||
method will do nothing
|
||||
|
||||
:param bool trigger_parent: Whether to trigger the parent, after self has updated
|
||||
"""
|
||||
if not self.update_model():
|
||||
if not self.update_model() or self._in_init_:
|
||||
#print "Warning: updates are off, updating the model will do nothing"
|
||||
return
|
||||
self._trigger_params_changed()
|
||||
|
||||
self._trigger_params_changed(trigger_parent)
|
||||
|
||||
def add_observer(self, observer, callble, priority=0):
|
||||
"""
|
||||
Add an observer `observer` with the callback `callble`
|
||||
|
|
@ -540,18 +541,18 @@ class Indexable(Nameable, Observable):
|
|||
[np.put(ret, ind, p.lnpdf_grad(x[ind])) for p, ind in self.priors.iteritems()]
|
||||
return ret
|
||||
return 0.
|
||||
|
||||
|
||||
#===========================================================================
|
||||
# Tie parameters together
|
||||
#===========================================================================
|
||||
|
||||
|
||||
def _has_ties(self):
|
||||
if self._highest_parent_.tie.tied_param is None:
|
||||
return False
|
||||
if self.has_parent():
|
||||
return self._highest_parent_.tie.label_buf[self._highest_parent_._raveled_index_for(self)].sum()>0
|
||||
return True
|
||||
|
||||
|
||||
def tie_together(self):
|
||||
self._highest_parent_.tie.add_tied_parameter(self)
|
||||
self._highest_parent_._set_fixed(self,self._raveled_index())
|
||||
|
|
@ -635,10 +636,18 @@ class Indexable(Nameable, Observable):
|
|||
"""
|
||||
From Parentable:
|
||||
Called when the parent changed
|
||||
|
||||
update the constraints and priors view, so that
|
||||
constraining is automized for the parent.
|
||||
"""
|
||||
from index_operations import ParameterIndexOperationsView
|
||||
self.constraints = ParameterIndexOperationsView(parent.constraints, parent._offset_for(self), self.size)
|
||||
self.priors = ParameterIndexOperationsView(parent.priors, parent._offset_for(self), self.size)
|
||||
#if getattr(self, "_in_init_"):
|
||||
#import ipdb;ipdb.set_trace()
|
||||
#self.constraints.update(param.constraints, start)
|
||||
#self.priors.update(param.priors, start)
|
||||
offset = parent._offset_for(self)
|
||||
self.constraints = ParameterIndexOperationsView(parent.constraints, offset, self.size)
|
||||
self.priors = ParameterIndexOperationsView(parent.priors, offset, self.size)
|
||||
self._fixes_ = None
|
||||
for p in self.parameters:
|
||||
p._parent_changed(parent)
|
||||
|
|
@ -741,6 +750,7 @@ class OptimizationHandlable(Indexable):
|
|||
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__]
|
||||
#self._highest_parent_.tie.propagate_val()
|
||||
|
||||
self._optimizer_copy_transformed = False
|
||||
self._trigger_params_changed()
|
||||
|
|
@ -826,15 +836,16 @@ class OptimizationHandlable(Indexable):
|
|||
"""
|
||||
# first take care of all parameters (from N(0,1))
|
||||
x = rand_gen(size=self._size_transformed(), *args, **kwargs)
|
||||
updates = self.update_model()
|
||||
self.update_model(False) # Switch off the updates
|
||||
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 = param_to_array(self.param_array).flat.copy()
|
||||
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]
|
||||
unfixlist = np.ones((self.size,),dtype=np.bool)
|
||||
unfixlist[self.constraints[__fixed__]] = False
|
||||
self.param_array.flat[unfixlist] = x[unfixlist]
|
||||
self.update_model(True)
|
||||
self.param_array.flat[unfixlist] = x.view(np.ndarray).ravel()[unfixlist]
|
||||
self.update_model(updates)
|
||||
|
||||
#===========================================================================
|
||||
# For shared memory arrays. This does nothing in Param, but sets the memory
|
||||
|
|
@ -928,7 +939,7 @@ class Parameterizable(OptimizationHandlable):
|
|||
"""
|
||||
if self.__dict__.get('_param_array_', None) is None:
|
||||
self._param_array_ = np.empty(self.size, dtype=np.float64)
|
||||
|
||||
|
||||
if self.constraints[__fixed__].size !=0:
|
||||
fixes = np.ones(self.size).astype(bool)
|
||||
fixes[self.constraints[__fixed__]] = FIXED
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ class Parameterized(Parameterizable):
|
|||
self.priors.update(param.priors, start)
|
||||
self.parameters.insert(index, param)
|
||||
|
||||
self._notify_parent_change()
|
||||
param.add_observer(self, self._pass_through_notify_observers, -np.inf)
|
||||
|
||||
parent = self
|
||||
|
|
@ -356,6 +357,35 @@ class Parameterized(Parameterizable):
|
|||
@property
|
||||
def _ties_str(self):
|
||||
return [','.join(x._ties_str) for x in self.flattened_parameters]
|
||||
|
||||
def _repr_html_(self, header=True):
|
||||
"""Representation of the parameters in html for notebook display."""
|
||||
name = adjust_name_for_printing(self.name) + "."
|
||||
constrs = self._constraints_str;
|
||||
ts = self._ties_str
|
||||
prirs = self._priors_str
|
||||
desc = self._description_str; names = self.parameter_names()
|
||||
nl = max([len(str(x)) for x in names + [name]])
|
||||
sl = max([len(str(x)) for x in desc + ["Value"]])
|
||||
cl = max([len(str(x)) if x else 0 for x in constrs + ["Constraint"]])
|
||||
tl = max([len(str(x)) if x else 0 for x in ts + ["Tied to"]])
|
||||
pl = max([len(str(x)) if x else 0 for x in prirs + ["Prior"]])
|
||||
format_spec = "<tr><td>{{name:<{0}s}}</td><td align=\"right\">{{desc:>{1}s}}</td><td>{{const:^{2}s}}</td><td>{{pri:^{3}s}}</td><td>{{t:^{4}s}}</td></tr>".format(nl, sl, cl, pl, tl)
|
||||
to_print = []
|
||||
for n, d, c, t, p in itertools.izip(names, desc, constrs, ts, prirs):
|
||||
to_print.append(format_spec.format(name=n, desc=d, const=c, t=t, pri=p))
|
||||
sep = '-' * (nl + sl + cl + + pl + tl + 8 * 2 + 3)
|
||||
if header:
|
||||
header = """
|
||||
<tr>
|
||||
<td><b>{name}</b>
|
||||
<td><b>Value</b></td>
|
||||
<td><b>Constraint</b></td>
|
||||
<td><b>Prior</b></td>
|
||||
<td><b>Tied to</b></td>""".format(name=name)
|
||||
to_print.insert(0, header)
|
||||
return '<table>' + '\n'.format(sep).join(to_print) + '\n</table>'
|
||||
|
||||
def __str__(self, header=True):
|
||||
name = adjust_name_for_printing(self.name) + "."
|
||||
constrs = self._constraints_str;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ class Gaussian(Prior):
|
|||
self.constant = -0.5 * np.log(2 * np.pi * self.sigma2)
|
||||
|
||||
def __str__(self):
|
||||
return "N(" + str(np.round(self.mu)) + ', ' + str(np.round(self.sigma2)) + ')'
|
||||
return "N({:.2g}, {:.2g})".format(self.mu, self.sigma)
|
||||
|
||||
def lnpdf(self, x):
|
||||
return self.constant - 0.5 * np.square(x - self.mu) / self.sigma2
|
||||
|
|
@ -89,7 +89,7 @@ class Uniform(Prior):
|
|||
self.upper = float(upper)
|
||||
|
||||
def __str__(self):
|
||||
return "[" + str(np.round(self.lower)) + ', ' + str(np.round(self.upper)) + ']'
|
||||
return "[{:.2g}, {:.2g}]".format(self.lower, self.upper)
|
||||
|
||||
def lnpdf(self, x):
|
||||
region = (x >= self.lower) * (x <= self.upper)
|
||||
|
|
@ -132,7 +132,7 @@ class LogGaussian(Prior):
|
|||
self.constant = -0.5 * np.log(2 * np.pi * self.sigma2)
|
||||
|
||||
def __str__(self):
|
||||
return "lnN(" + str(np.round(self.mu)) + ', ' + str(np.round(self.sigma2)) + ')'
|
||||
return "lnN({:.2g}, {:.2g})".format(self.mu, self.sigma)
|
||||
|
||||
def lnpdf(self, x):
|
||||
return self.constant - 0.5 * np.square(np.log(x) - self.mu) / self.sigma2 - np.log(x)
|
||||
|
|
@ -237,7 +237,7 @@ class Gamma(Prior):
|
|||
self.constant = -gammaln(self.a) + a * np.log(b)
|
||||
|
||||
def __str__(self):
|
||||
return "Ga(" + str(np.round(self.a)) + ', ' + str(np.round(self.b)) + ')'
|
||||
return "Ga({:.2g}, {:.2g})".format(self.a, self.b)
|
||||
|
||||
def summary(self):
|
||||
ret = {"E[x]": self.a / self.b, \
|
||||
|
|
@ -272,8 +272,7 @@ class Gamma(Prior):
|
|||
b = E / V
|
||||
return Gamma(a, b)
|
||||
|
||||
|
||||
class inverse_gamma(Prior):
|
||||
class InverseGamma(Prior):
|
||||
"""
|
||||
Implementation of the inverse-Gamma probability function, coupled with random variables.
|
||||
|
||||
|
|
@ -284,8 +283,8 @@ class inverse_gamma(Prior):
|
|||
|
||||
"""
|
||||
domain = _POSITIVE
|
||||
|
||||
def __new__(cls, a, b): # Singleton:
|
||||
_instances = []
|
||||
def __new__(cls, a, b): # Singleton:
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
|
|
@ -301,7 +300,7 @@ class inverse_gamma(Prior):
|
|||
self.constant = -gammaln(self.a) + a * np.log(b)
|
||||
|
||||
def __str__(self):
|
||||
return "iGa(" + str(np.round(self.a)) + ', ' + str(np.round(self.b)) + ')'
|
||||
return "iGa({:.2g}, {:.2g})".format(self.a, self.b)
|
||||
|
||||
def lnpdf(self, x):
|
||||
return self.constant - (self.a + 1) * np.log(x) - self.b / x
|
||||
|
|
@ -312,7 +311,6 @@ class inverse_gamma(Prior):
|
|||
def rvs(self, n):
|
||||
return 1. / np.random.gamma(scale=1. / self.b, shape=self.a, size=n)
|
||||
|
||||
|
||||
class DGPLVM_KFDA(Prior):
|
||||
"""
|
||||
Implementation of the Discriminative Gaussian Process Latent Variable function using
|
||||
|
|
@ -656,3 +654,64 @@ class DGPLVM(Prior):
|
|||
def __str__(self):
|
||||
return 'DGPLVM_prior'
|
||||
|
||||
class HalfT(Prior):
|
||||
"""
|
||||
Implementation of the half student t probability function, coupled with random variables.
|
||||
|
||||
:param A: scale parameter
|
||||
:param nu: degrees of freedom
|
||||
|
||||
"""
|
||||
domain = _POSITIVE
|
||||
_instances = []
|
||||
def __new__(cls, A, nu): # Singleton:
|
||||
if cls._instances:
|
||||
cls._instances[:] = [instance for instance in cls._instances if instance()]
|
||||
for instance in cls._instances:
|
||||
if instance().A == A and instance().nu == nu:
|
||||
return instance()
|
||||
o = super(Prior, cls).__new__(cls, A, nu)
|
||||
cls._instances.append(weakref.ref(o))
|
||||
return cls._instances[-1]()
|
||||
def __init__(self, A, nu):
|
||||
self.A = float(A)
|
||||
self.nu = float(nu)
|
||||
self.constant = gammaln(.5*(self.nu+1.)) - gammaln(.5*self.nu) - .5*np.log(np.pi*self.A*self.nu)
|
||||
|
||||
def __str__(self):
|
||||
return "hT({:.2g}, {:.2g})".format(self.A, self.nu)
|
||||
|
||||
def lnpdf(self,theta):
|
||||
return (theta>0) * ( self.constant -.5*(self.nu+1) * np.log( 1.+ (1./self.nu) * (theta/self.A)**2 ) )
|
||||
|
||||
#theta = theta if isinstance(theta,np.ndarray) else np.array([theta])
|
||||
#lnpdfs = np.zeros_like(theta)
|
||||
#theta = np.array([theta])
|
||||
#above_zero = theta.flatten()>1e-6
|
||||
#v = self.nu
|
||||
#sigma2=self.A
|
||||
#stop
|
||||
#lnpdfs[above_zero] = (+ gammaln((v + 1) * 0.5)
|
||||
# - gammaln(v * 0.5)
|
||||
# - 0.5*np.log(sigma2 * v * np.pi)
|
||||
# - 0.5*(v + 1)*np.log(1 + (1/np.float(v))*((theta[above_zero][0]**2)/sigma2))
|
||||
#)
|
||||
#return lnpdfs
|
||||
|
||||
def lnpdf_grad(self,theta):
|
||||
theta = theta if isinstance(theta,np.ndarray) else np.array([theta])
|
||||
grad = np.zeros_like(theta)
|
||||
above_zero = theta>1e-6
|
||||
v = self.nu
|
||||
sigma2=self.A
|
||||
grad[above_zero] = -0.5*(v+1)*(2*theta[above_zero])/(v*sigma2 + theta[above_zero][0]**2)
|
||||
return grad
|
||||
|
||||
def rvs(self, n):
|
||||
#return np.random.randn(n) * self.sigma + self.mu
|
||||
from scipy.stats import t
|
||||
#[np.abs(x) for x in t.rvs(df=4,loc=0,scale=50, size=10000)])
|
||||
ret = t.rvs(self.nu,loc=0,scale=self.A, size=n)
|
||||
ret[ret<0] = 0
|
||||
return ret
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue