diff --git a/GPy/core/gp.py b/GPy/core/gp.py index 795be125..4c666e43 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -54,8 +54,8 @@ class GP(Model): print "defaulting to ", inference_method, "for latent function inference" self.inference_method = inference_method - self.add_parameter(self.kern, gradient=self.dL_dtheta_K) - self.add_parameter(self.likelihood, gradient=lambda:self.posterior.dL_dtheta_lik) + self.add_parameter(self.kern) + self.add_parameter(self.likelihood) self.parameters_changed() diff --git a/GPy/core/model.py b/GPy/core/model.py index 96fe8362..93f0f03e 100644 --- a/GPy/core/model.py +++ b/GPy/core/model.py @@ -34,9 +34,9 @@ class Model(Parameterized): g = np.zeros(self.size) try: #[g.__setitem__(s, self.gradient_mapping[p]().flat) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed] - [g.__setitem__(s, p.gradient.flat) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed] - except KeyError: - raise KeyError, 'Gradient for {} not defined, please specify gradients for parameters to optimize'.format(p.name) + [p._collect_gradient(g[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_) if not p.is_fixed] + except ValueError: + raise ValueError, 'Gradient for {} not defined, please specify gradients for parameters to optimize'.format(p.name) return g raise NotImplementedError, "this needs to be implemented to use the model class" diff --git a/GPy/core/parameterization/param.py b/GPy/core/parameterization/param.py index 9b2aa5f9..d7812c0f 100644 --- a/GPy/core/parameterization/param.py +++ b/GPy/core/parameterization/param.py @@ -26,9 +26,6 @@ class Param(ObservableArray, Constrainable): :param name: name of the parameter to be printed :param input_array: array which this parameter handles - :param gradient: callable with one argument, which is the model of this parameter - :param args: additional arguments to gradient - :param kwargs: additional keyword arguments to gradient You can add/remove constraints by calling constrain on the parameter itself, e.g: @@ -156,6 +153,8 @@ class Param(ObservableArray, Constrainable): @property def _parameters_(self): return [] + def _collect_gradient(self, target): + target[:] = self.gradient #=========================================================================== # Fixing Parameters: #=========================================================================== diff --git a/GPy/core/parameterization/parameterized.py b/GPy/core/parameterization/parameterized.py index 7eb4672b..83c3c301 100644 --- a/GPy/core/parameterization/parameterized.py +++ b/GPy/core/parameterization/parameterized.py @@ -75,7 +75,6 @@ class Parameterized(Constrainable, Pickleable, Observable): if not self._has_fixes(): self._fixes_ = None self._connect_parameters() - self.gradient_mapping = {} self._added_names_ = set() del self._in_init_ @@ -118,12 +117,10 @@ class Parameterized(Constrainable, Pickleable, Observable): def _has_fixes(self): return hasattr(self, "_fixes_") and self._fixes_ is not None - def add_parameter(self, param, gradient=None, index=None): + def add_parameter(self, param, index=None): """ :param parameters: the parameters to add :type parameters: list of or one :py:class:`GPy.core.param.Param` - :param [gradients]: gradients for each param, - one gradient per param :param [index]: index of where to put parameters @@ -167,8 +164,6 @@ class Parameterized(Constrainable, Pickleable, Observable): self._fixes_ = np.ones(self.size+param.size, dtype=bool) self._fixes_[ins:ins+param.size] = fixes_param self.size += param.size - if gradient: - self.gradient_mapping[param] = gradient self._connect_parameters() # make sure the constraints are pulled over: if hasattr(param, "_constraints_") and param._constraints_ is not None: @@ -206,7 +201,7 @@ class Parameterized(Constrainable, Pickleable, Observable): add self as a listener to the param, such that updates get passed through. See :py:function:``GPy.core.param.Observable.add_observer`` """ - # will be called as soon as paramters have changed + # will be called as soon as parameters have changed pass def _connect_parameters(self): @@ -282,13 +277,11 @@ class Parameterized(Constrainable, Pickleable, Observable): self._constraints_, self._parameters_, self._name, - #self.gradient_mapping, self._added_names_, ] def setstate(self, state): self._added_names_ = state.pop() - #self.gradient_mapping = state.pop() self._name = state.pop() self._parameters_ = state.pop() self._connect_parameters() @@ -547,6 +540,8 @@ class Parameterized(Constrainable, Pickleable, Observable): return [adjust_name_for_printing(self.name) + "." + xi for x in self._parameters_ for xi in x._parameter_names(add_name=True)] return [xi for x in self._parameters_ for xi in x._parameter_names(add_name=True)] parameter_names = property(_parameter_names, doc="Names for all parameters handled by this parameterization object -- will add hirarchy name entries for printing") + def _collect_gradient(self, target): + [p._collect_gradient(target[s]) for p, s in itertools.izip(self._parameters_, self._param_slices_)] @property def flattened_parameters(self): return [xi for x in self._parameters_ for xi in x.flattened_parameters] diff --git a/GPy/kern/kern.py b/GPy/kern/kern.py index 3f695f42..7ce4f652 100644 --- a/GPy/kern/kern.py +++ b/GPy/kern/kern.py @@ -346,6 +346,7 @@ class kern(Parameterized): return target def update_gradients_full(self, dL_dK, X): + [p.update_gradients_full(dL_dK, X) for p in self._parameters_] pass def update_gradients_sparse(self, dL_dKmm, dL_dKnm, dL_dKdiag, X, Z): pass diff --git a/GPy/kern/parts/rbf.py b/GPy/kern/parts/rbf.py index 57ce2996..4afebeb7 100644 --- a/GPy/kern/parts/rbf.py +++ b/GPy/kern/parts/rbf.py @@ -80,9 +80,6 @@ class RBF(Kernpart): self._X, self._X2 = np.empty(shape=(2, 1)) self._Z, self._mu, self._S = np.empty(shape=(3, 1)) # cached versions of Z,mu,S - - - def K(self, X, X2, target): self._K_computations(X, X2) target += self.variance * self._K_dvar @@ -101,11 +98,8 @@ class RBF(Kernpart): self._psi_computations(Z, mu, S) target += self._psi2 - - - def update_gradients_full(self, dL_dK, X): - self._K_computations(X, X2) + self._K_computations(X, None) self.variance.gradient = np.sum(self._K_dvar * dL_dK) if self.ARD: self.lengthscale.gradient = self._dL_dlengthscales_via_K(dL_dK, X, None) @@ -123,7 +117,7 @@ class RBF(Kernpart): self.lengthscales.gradient = self._dL_dlengthscales_via_K(dL_dKnm, X, Z) else: - self.lengthscale.gradient = (self.variance / self.lengthscale) * np.sum(self._K_dvar * self._K_dist2 * dL_dK) + self.lengthscale.gradient = (self.variance / self.lengthscale) * np.sum(self._K_dvar * self._K_dist2 * dL_dKmm) #from Kmm self._K_computations(Z, None) @@ -131,7 +125,7 @@ class RBF(Kernpart): if self.ARD: self.lengthscales.gradient += self._dL_dlengthscales_via_K(dL_dKmm, Z, None) else: - self.lengthscale.gradient += (self.variance / self.lengthscale) * np.sum(self._K_dvar * self._K_dist2 * dL_dK) + self.lengthscale.gradient += (self.variance / self.lengthscale) * np.sum(self._K_dvar * self._K_dist2 * dL_dKmm) def update_gradients_variational(self, dL_dKmm, dL_dpsi0, dL_dpsi1, dL_dpsi2, mu, S, Z): self._psi_computations(Z, mu, S)