diff --git a/GPy/core/gp.py b/GPy/core/gp.py index 453de407..ab7e8f9d 100644 --- a/GPy/core/gp.py +++ b/GPy/core/gp.py @@ -110,7 +110,14 @@ class GP(Model): self.posterior = None def to_dict(self, save_data=True): - input_dict = super(GP, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + Note: It uses the private method _save_to_input_dict of the parent. + + :param boolean save_data: if true, it adds the training data self.X and self.Y to the dictionary + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + input_dict = super(GP, self)._save_to_input_dict() input_dict["class"] = "GPy.core.GP" if not save_data: input_dict["X"] = None @@ -137,7 +144,7 @@ class GP(Model): return input_dict @staticmethod - def _from_dict(input_dict, data=None): + def _build_from_input_dict(input_dict, data=None): import GPy import numpy as np if (input_dict['X'] is None) or (input_dict['Y'] is None): @@ -282,7 +289,7 @@ class GP(Model): mu += self.mean_function.f(Xnew) return mu, var - def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None, + def predict(self, Xnew, full_cov=False, Y_metadata=None, kern=None, likelihood=None, include_likelihood=True): """ Predict the function(s) at the new point(s) Xnew. This includes the diff --git a/GPy/core/mapping.py b/GPy/core/mapping.py index d8032c54..31e4d8bb 100644 --- a/GPy/core/mapping.py +++ b/GPy/core/mapping.py @@ -28,7 +28,7 @@ class Mapping(Parameterized): def to_dict(self): raise NotImplementedError - def _to_dict(self): + def _save_to_input_dict(self): input_dict = {} input_dict["input_dim"] = self.input_dim input_dict["output_dim"] = self.output_dim @@ -37,16 +37,27 @@ class Mapping(Parameterized): @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ import copy input_dict = copy.deepcopy(input_dict) mapping_class = input_dict.pop('class') input_dict["name"] = str(input_dict["name"]) import GPy mapping_class = eval(mapping_class) - return mapping_class._from_dict(mapping_class, input_dict) + return mapping_class._build_from_input_dict(mapping_class, input_dict) @staticmethod - def _from_dict(mapping_class, input_dict): + def _build_from_input_dict(mapping_class, input_dict): return mapping_class(**input_dict) diff --git a/GPy/core/model.py b/GPy/core/model.py index 799d42bd..b57e1a77 100644 --- a/GPy/core/model.py +++ b/GPy/core/model.py @@ -8,7 +8,10 @@ class Model(ParamzModel, Priorizable): def __init__(self, name): super(Model, self).__init__(name) # Parameterized.__init__(self) - def _to_dict(self): + def _save_to_input_dict(self): + """ + It is used by the public method to_dict to create json serializable dictionary. + """ input_dict = {} input_dict["name"] = self.name return input_dict @@ -18,16 +21,37 @@ class Model(ParamzModel, Priorizable): @staticmethod def from_dict(input_dict, data=None): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ import copy input_dict = copy.deepcopy(input_dict) model_class = input_dict.pop('class') input_dict["name"] = str(input_dict["name"]) import GPy model_class = eval(model_class) - return model_class._from_dict(input_dict, data) + return model_class._build_from_input_dict(input_dict, data) @staticmethod - def _from_dict(model_class, input_dict, data=None): + def _build_from_input_dict(model_class, input_dict, data=None): + """ + This method is used by the public method from_dict to build an object + of class model_class using the information contained in input_dict. + Note: This method is often overrided in the derived class to deal with + any pre-processing of the parameters in input_dict before calling the + constructor of the object. + + :param str model_class: Class of the object to build. + :param dict input_dict: Extra information needed by the constructor of model_class. + """ return model_class(**input_dict) def save_model(self, output_filename, compress=True, save_data=True): diff --git a/GPy/core/sparse_gp.py b/GPy/core/sparse_gp.py index 4c7e98c4..eb3650af 100644 --- a/GPy/core/sparse_gp.py +++ b/GPy/core/sparse_gp.py @@ -117,3 +117,50 @@ class SparseGP(GP): self.Z.gradient = self.kern.gradients_X(self.grad_dict['dL_dKmm'], self.Z) self.Z.gradient += self.kern.gradients_X(self.grad_dict['dL_dKnm'].T, self.Z, self.X) self._Zgrad = self.Z.gradient.copy() + + def to_dict(self, save_data=True): + """ + Convert the object into a json serializable dictionary. + + :param boolean save_data: if true, it adds the training data self.X and self.Y to the dictionary + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + input_dict = super(SparseGP, self).to_dict(save_data) + input_dict["class"] = "GPy.core.SparseGP" + input_dict["Z"] = self.Z.tolist() + return input_dict + + @staticmethod + def _build_from_input_dict(input_dict, data=None): + # Called from the from_dict method. + import GPy + if (input_dict['X'] is None) or (input_dict['Y'] is None): + if data is None: + raise ValueError("The model was serialized whithout the training data. 'data' must be not None!") + input_dict["X"], input_dict["Y"] = np.array(data[0]), np.array(data[1]) + elif data is not None: + print("WARNING: The model has been saved with X,Y! The original values are being overriden!") + input_dict["X"], input_dict["Y"] = np.array(data[0]), np.array(data[1]) + else: + input_dict["X"], input_dict["Y"] = np.array(input_dict['X']), np.array(input_dict['Y']) + + input_dict["Z"] = np.array(input_dict['Z']) + input_dict["kernel"] = GPy.kern.Kern.from_dict(input_dict["kernel"]) + input_dict["likelihood"] = GPy.likelihoods.likelihood.Likelihood.from_dict(input_dict["likelihood"]) + mean_function = input_dict.get("mean_function") + if mean_function is not None: + input_dict["mean_function"] = GPy.core.mapping.Mapping.from_dict(mean_function) + else: + input_dict["mean_function"] = mean_function + input_dict["inference_method"] = GPy.inference.latent_function_inference.LatentFunctionInference.from_dict(input_dict["inference_method"]) + + #FIXME: Assumes the Y_metadata is serializable. We should create a Metadata class + Y_metadata = input_dict.get("Y_metadata") + input_dict["Y_metadata"] = Y_metadata + + normalizer = input_dict.get("normalizer") + if normalizer is not None: + input_dict["normalizer"] = GPy.util.normalizer._Norm.from_dict(normalizer) + else: + input_dict["normalizer"] = normalizer + return SparseGP(**input_dict) diff --git a/GPy/inference/latent_function_inference/__init__.py b/GPy/inference/latent_function_inference/__init__.py index 97815a41..23742e6a 100644 --- a/GPy/inference/latent_function_inference/__init__.py +++ b/GPy/inference/latent_function_inference/__init__.py @@ -41,7 +41,7 @@ class LatentFunctionInference(object): """ pass - def _to_dict(self): + def _save_to_input_dict(self): input_dict = {} return input_dict @@ -50,15 +50,27 @@ class LatentFunctionInference(object): @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ + import copy input_dict = copy.deepcopy(input_dict) inference_class = input_dict.pop('class') import GPy inference_class = eval(inference_class) - return inference_class._from_dict(inference_class, input_dict) + return inference_class._build_from_input_dict(inference_class, input_dict) @staticmethod - def _from_dict(inference_class, input_dict): + def _build_from_input_dict(inference_class, input_dict): return inference_class(**input_dict) class InferenceMethodList(LatentFunctionInference, list): diff --git a/GPy/inference/latent_function_inference/exact_gaussian_inference.py b/GPy/inference/latent_function_inference/exact_gaussian_inference.py index a0a35fa5..569dbf3b 100644 --- a/GPy/inference/latent_function_inference/exact_gaussian_inference.py +++ b/GPy/inference/latent_function_inference/exact_gaussian_inference.py @@ -22,7 +22,15 @@ class ExactGaussianInference(LatentFunctionInference): pass#self._YYTfactor_cache = caching.cache() def to_dict(self): - input_dict = super(ExactGaussianInference, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(ExactGaussianInference, self)._save_to_input_dict() input_dict["class"] = "GPy.inference.latent_function_inference.exact_gaussian_inference.ExactGaussianInference" return input_dict diff --git a/GPy/inference/latent_function_inference/expectation_propagation.py b/GPy/inference/latent_function_inference/expectation_propagation.py index 61d3feff..2a558b5b 100644 --- a/GPy/inference/latent_function_inference/expectation_propagation.py +++ b/GPy/inference/latent_function_inference/expectation_propagation.py @@ -28,6 +28,14 @@ class cavityParams(object): self.tau[i] = 1./post_params.Sigma_diag[i] - eta*ga_approx.tau[i] self.v[i] = post_params.mu[i]/post_params.Sigma_diag[i] - eta*ga_approx.v[i] def to_dict(self): + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + return {"tau": self.tau.tolist(), "v": self.v.tolist()} @staticmethod def from_dict(input_dict): @@ -59,6 +67,14 @@ class gaussianApproximation(object): return (delta_tau, delta_v) def to_dict(self): + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + return {"tau": self.tau.tolist(), "v": self.v.tolist()} @staticmethod def from_dict(input_dict): @@ -89,6 +105,14 @@ class posteriorParams(posteriorParamsBase): DSYR(self.Sigma, si, -ci) def to_dict(self): + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + #TODO: Implement a more memory efficient variant if self.L is None: return { "mu": self.mu.tolist(), "Sigma": self.Sigma.tolist()} @@ -133,6 +157,14 @@ class posteriorParamsDTC(posteriorParamsBase): #mu = np.dot(Sigma, v_tilde) def to_dict(self): + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + return { "mu": self.mu.tolist(), "Sigma_diag": self.Sigma_diag.tolist()} @staticmethod @@ -205,8 +237,8 @@ class EPBase(object): def __getstate__(self): return [super(EPBase, self).__getstate__() , [self.epsilon, self.eta, self.delta]] - def _to_dict(self): - input_dict = super(EPBase, self)._to_dict() + def _save_to_input_dict(self): + input_dict = super(EPBase, self)._save_to_input_dict() input_dict["epsilon"]=self.epsilon input_dict["eta"]=self.eta input_dict["delta"]=self.delta @@ -370,7 +402,15 @@ class EP(EPBase, ExactGaussianInference): return Posterior(woodbury_inv=Wi, woodbury_vector=alpha, K=K), log_marginal, {'dL_dK':dL_dK, 'dL_dthetaL':dL_dthetaL, 'dL_dm':alpha} def to_dict(self): - input_dict = super(EP, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(EP, self)._save_to_input_dict() input_dict["class"] = "GPy.inference.latent_function_inference.expectation_propagation.EP" if self.ga_approx_old is not None: input_dict["ga_approx_old"] = self.ga_approx_old.to_dict() @@ -384,7 +424,7 @@ class EP(EPBase, ExactGaussianInference): return input_dict @staticmethod - def _from_dict(inference_class, input_dict): + def _build_from_input_dict(inference_class, input_dict): ga_approx_old = input_dict.pop('ga_approx_old', None) if ga_approx_old is not None: ga_approx_old = gaussianApproximation.from_dict(ga_approx_old) @@ -402,7 +442,7 @@ class EP(EPBase, ExactGaussianInference): class EPDTC(EPBase, VarDTC): def inference(self, kern, X, Z, likelihood, Y, mean_function=None, Y_metadata=None, Lm=None, dL_dKmm=None, psi0=None, psi1=None, psi2=None): - if self.always_reset: + if self.always_reset and not self.loading: self.reset() num_data, output_dim = Y.shape @@ -420,11 +460,11 @@ class EPDTC(EPBase, VarDTC): else: Kmn = psi1.T - if self.ep_mode=="nested": + if self.ep_mode=="nested" and not self.loading: #Force EP at each step of the optimization self._ep_approximation = None post_params, ga_approx, log_Z_tilde = self._ep_approximation = self.expectation_propagation(Kmm, Kmn, Y, likelihood, Y_metadata) - elif self.ep_mode=="alternated": + elif self.ep_mode=="alternated" or self.loading: if getattr(self, '_ep_approximation', None) is None: #if we don't yet have the results of runnign EP, run EP and store the computed factors in self._ep_approximation post_params, ga_approx, log_Z_tilde = self._ep_approximation = self.expectation_propagation(Kmm, Kmn, Y, likelihood, Y_metadata) @@ -434,6 +474,8 @@ class EPDTC(EPBase, VarDTC): else: raise ValueError("ep_mode value not valid") + self.loading = False + mu_tilde = ga_approx.v / ga_approx.tau.astype(float) return super(EPDTC, self).inference(kern, X, Z, likelihood, ObsAr(mu_tilde[:,None]), @@ -543,7 +585,15 @@ class EPDTC(EPBase, VarDTC): def to_dict(self): - input_dict = super(EPDTC, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(EPDTC, self)._save_to_input_dict() input_dict["class"] = "GPy.inference.latent_function_inference.expectation_propagation.EPDTC" if self.ga_approx_old is not None: input_dict["ga_approx_old"] = self.ga_approx_old.to_dict() @@ -551,13 +601,12 @@ class EPDTC(EPBase, VarDTC): input_dict["_ep_approximation"] = {} input_dict["_ep_approximation"]["post_params"] = self._ep_approximation[0].to_dict() input_dict["_ep_approximation"]["ga_approx"] = self._ep_approximation[1].to_dict() - input_dict["_ep_approximation"]["cav_params"] = self._ep_approximation[2].to_dict() - input_dict["_ep_approximation"]["log_Z_tilde"] = self._ep_approximation[3].tolist() + input_dict["_ep_approximation"]["log_Z_tilde"] = self._ep_approximation[2] return input_dict @staticmethod - def _from_dict(inference_class, input_dict): + def _build_from_input_dict(inference_class, input_dict): ga_approx_old = input_dict.pop('ga_approx_old', None) if ga_approx_old is not None: ga_approx_old = gaussianApproximation.from_dict(ga_approx_old) @@ -566,8 +615,7 @@ class EPDTC(EPBase, VarDTC): if _ep_approximation is not None: _ep_approximation.append(posteriorParamsDTC.from_dict(_ep_approximation_dict["post_params"])) _ep_approximation.append(gaussianApproximation.from_dict(_ep_approximation_dict["ga_approx"])) - _ep_approximation.append(cavityParams.from_dict(_ep_approximation_dict["cav_params"])) - _ep_approximation.append(np.array(_ep_approximation_dict["log_Z_tilde"])) + _ep_approximation.append(_ep_approximation_dict["log_Z_tilde"]) ee = EPDTC(**input_dict) ee.ga_approx_old = ga_approx_old ee._ep_approximation = _ep_approximation diff --git a/GPy/kern/src/add.py b/GPy/kern/src/add.py index c1834f76..3fc34883 100644 --- a/GPy/kern/src/add.py +++ b/GPy/kern/src/add.py @@ -44,7 +44,15 @@ class Add(CombinationKernel): return False def to_dict(self): - input_dict = super(Add, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Add, self)._save_to_input_dict() input_dict["class"] = str("GPy.kern.Add") return input_dict diff --git a/GPy/kern/src/kern.py b/GPy/kern/src/kern.py index c08489e2..8da3fbfb 100644 --- a/GPy/kern/src/kern.py +++ b/GPy/kern/src/kern.py @@ -60,7 +60,7 @@ class Kern(Parameterized): from .psi_comp import PSICOMP_GH self.psicomp = PSICOMP_GH() - def _to_dict(self): + def _save_to_input_dict(self): input_dict = {} input_dict["input_dim"] = self.input_dim if isinstance(self.active_dims, np.ndarray): @@ -76,16 +76,28 @@ class Kern(Parameterized): @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ + import copy input_dict = copy.deepcopy(input_dict) kernel_class = input_dict.pop('class') input_dict["name"] = str(input_dict["name"]) import GPy kernel_class = eval(kernel_class) - return kernel_class._from_dict(kernel_class, input_dict) + return kernel_class._build_from_input_dict(kernel_class, input_dict) @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): return kernel_class(**input_dict) @@ -375,15 +387,15 @@ class CombinationKernel(Kern): if link_parameters: self.link_parameters(*kernels) - def _to_dict(self): - input_dict = super(CombinationKernel, self)._to_dict() + def _save_to_input_dict(self): + input_dict = super(CombinationKernel, self)._save_to_input_dict() input_dict["parts"] = {} for ii in range(len(self.parts)): input_dict["parts"][ii] = self.parts[ii].to_dict() return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): parts = input_dict.pop('parts', None) subkerns = [] for pp in parts: diff --git a/GPy/kern/src/linear.py b/GPy/kern/src/linear.py index 10edb4c2..bf75f201 100644 --- a/GPy/kern/src/linear.py +++ b/GPy/kern/src/linear.py @@ -52,14 +52,14 @@ class Linear(Kern): self.psicomp = PSICOMP_Linear() def to_dict(self): - input_dict = super(Linear, self)._to_dict() + input_dict = super(Linear, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.Linear" input_dict["variances"] = self.variances.values.tolist() input_dict["ARD"] = self.ARD return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return Linear(**input_dict) diff --git a/GPy/kern/src/prod.py b/GPy/kern/src/prod.py index 31e62392..6bf5f9f3 100644 --- a/GPy/kern/src/prod.py +++ b/GPy/kern/src/prod.py @@ -43,7 +43,15 @@ class Prod(CombinationKernel): super(Prod, self).__init__(_newkerns, name) def to_dict(self): - input_dict = super(Prod, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Prod, self)._save_to_input_dict() input_dict["class"] = str("GPy.kern.Prod") return input_dict diff --git a/GPy/kern/src/rbf.py b/GPy/kern/src/rbf.py index 0b6730d8..c17345d8 100644 --- a/GPy/kern/src/rbf.py +++ b/GPy/kern/src/rbf.py @@ -32,7 +32,15 @@ class RBF(Stationary): self.link_parameter(self.inv_l) def to_dict(self): - input_dict = super(RBF, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(RBF, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.RBF" input_dict["inv_l"] = self.use_invLengthscale if input_dict["inv_l"] == True: diff --git a/GPy/kern/src/standard_periodic.py b/GPy/kern/src/standard_periodic.py index 201f8d19..e7b67239 100644 --- a/GPy/kern/src/standard_periodic.py +++ b/GPy/kern/src/standard_periodic.py @@ -94,7 +94,15 @@ class StdPeriodic(Kern): self.link_parameters(self.variance, self.period, self.lengthscale) def to_dict(self): - input_dict = super(StdPeriodic, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(StdPeriodic, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.StdPeriodic" input_dict["variance"] = self.variance.values.tolist() input_dict["period"] = self.period.values.tolist() diff --git a/GPy/kern/src/static.py b/GPy/kern/src/static.py index f7042cc1..a4831107 100644 --- a/GPy/kern/src/static.py +++ b/GPy/kern/src/static.py @@ -14,8 +14,8 @@ class Static(Kern): self.variance = Param('variance', variance, Logexp()) self.link_parameters(self.variance) - def _to_dict(self): - input_dict = super(Static, self)._to_dict() + def _save_to_input_dict(self): + input_dict = super(Static, self)._save_to_input_dict() input_dict["variance"] = self.variance.values.tolist() return input_dict @@ -139,12 +139,12 @@ class Bias(Static): super(Bias, self).__init__(input_dim, variance, active_dims, name) def to_dict(self): - input_dict = super(Bias, self)._to_dict() + input_dict = super(Bias, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.Bias" return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return Bias(**input_dict) diff --git a/GPy/kern/src/stationary.py b/GPy/kern/src/stationary.py index 81129a75..cf3f5dff 100644 --- a/GPy/kern/src/stationary.py +++ b/GPy/kern/src/stationary.py @@ -79,8 +79,8 @@ class Stationary(Kern): assert self.variance.size==1 self.link_parameters(self.variance, self.lengthscale) - def _to_dict(self): - input_dict = super(Stationary, self)._to_dict() + def _save_to_input_dict(self): + input_dict = super(Stationary, self)._save_to_input_dict() input_dict["variance"] = self.variance.values.tolist() input_dict["lengthscale"] = self.lengthscale.values.tolist() input_dict["ARD"] = self.ARD @@ -366,12 +366,20 @@ class Exponential(Stationary): return -self.K_of_r(r) def to_dict(self): - input_dict = super(Exponential, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Exponential, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.Exponential" return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return Exponential(**input_dict) @@ -424,12 +432,20 @@ class Matern32(Stationary): super(Matern32, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name) def to_dict(self): - input_dict = super(Matern32, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Matern32, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.Matern32" return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return Matern32(**input_dict) @@ -513,12 +529,20 @@ class Matern52(Stationary): super(Matern52, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name) def to_dict(self): - input_dict = super(Matern52, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Matern52, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.Matern52" return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return Matern52(**input_dict) @@ -578,12 +602,20 @@ class ExpQuad(Stationary): super(ExpQuad, self).__init__(input_dim, variance, lengthscale, ARD, active_dims, name) def to_dict(self): - input_dict = super(ExpQuad, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(ExpQuad, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.ExpQuad" return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return ExpQuad(**input_dict) @@ -621,13 +653,21 @@ class RatQuad(Stationary): self.link_parameters(self.power) def to_dict(self): - input_dict = super(RatQuad, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(RatQuad, self)._save_to_input_dict() input_dict["class"] = "GPy.kern.RatQuad" input_dict["power"] = self.power.values.tolist() return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): useGPU = input_dict.pop('useGPU', None) return RatQuad(**input_dict) diff --git a/GPy/likelihoods/bernoulli.py b/GPy/likelihoods/bernoulli.py index a00798f9..2e745b9b 100644 --- a/GPy/likelihoods/bernoulli.py +++ b/GPy/likelihoods/bernoulli.py @@ -30,7 +30,15 @@ class Bernoulli(Likelihood): self.log_concave = True def to_dict(self): - input_dict = super(Bernoulli, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Bernoulli, self)._save_to_input_dict() input_dict["class"] = "GPy.likelihoods.Bernoulli" return input_dict diff --git a/GPy/likelihoods/gaussian.py b/GPy/likelihoods/gaussian.py index 412fe404..830deb4d 100644 --- a/GPy/likelihoods/gaussian.py +++ b/GPy/likelihoods/gaussian.py @@ -47,7 +47,15 @@ class Gaussian(Likelihood): self.log_concave = True def to_dict(self): - input_dict = super(Gaussian, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Gaussian, self)._save_to_input_dict() input_dict["class"] = "GPy.likelihoods.Gaussian" input_dict["variance"] = self.variance.values.tolist() return input_dict diff --git a/GPy/likelihoods/likelihood.py b/GPy/likelihoods/likelihood.py index b28fdef5..b4f72719 100644 --- a/GPy/likelihoods/likelihood.py +++ b/GPy/likelihoods/likelihood.py @@ -49,7 +49,7 @@ class Likelihood(Parameterized): def to_dict(self): raise NotImplementedError - def _to_dict(self): + def _save_to_input_dict(self): input_dict = {} input_dict["name"] = self.name input_dict["gp_link_dict"] = self.gp_link.to_dict() @@ -57,6 +57,18 @@ class Likelihood(Parameterized): @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ + import copy input_dict = copy.deepcopy(input_dict) likelihood_class = input_dict.pop('class') @@ -64,10 +76,10 @@ class Likelihood(Parameterized): name = input_dict.pop('name') import GPy likelihood_class = eval(likelihood_class) - return likelihood_class._from_dict(likelihood_class, input_dict) + return likelihood_class._build_from_input_dict(likelihood_class, input_dict) @staticmethod - def _from_dict(likelihood_class, input_dict): + def _build_from_input_dict(likelihood_class, input_dict): import copy input_dict = copy.deepcopy(input_dict) gp_link_dict = input_dict.pop('gp_link_dict') diff --git a/GPy/likelihoods/link_functions.py b/GPy/likelihoods/link_functions.py index d5fc785f..0eb05e74 100644 --- a/GPy/likelihoods/link_functions.py +++ b/GPy/likelihoods/link_functions.py @@ -46,20 +46,32 @@ class GPTransformation(object): def to_dict(self): raise NotImplementedError - def _to_dict(self): + def _save_to_input_dict(self): return {} @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ + import copy input_dict = copy.deepcopy(input_dict) link_class = input_dict.pop('class') import GPy link_class = eval(link_class) - return link_class._from_dict(link_class, input_dict) + return link_class._build_from_input_dict(link_class, input_dict) @staticmethod - def _from_dict(link_class, input_dict): + def _build_from_input_dict(link_class, input_dict): return link_class(**input_dict) class Identity(GPTransformation): @@ -82,7 +94,15 @@ class Identity(GPTransformation): return np.zeros_like(f) def to_dict(self): - input_dict = super(Identity, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Identity, self)._save_to_input_dict() input_dict["class"] = "GPy.likelihoods.link_functions.Identity" return input_dict @@ -106,7 +126,15 @@ class Probit(GPTransformation): return (safe_square(f)-1.)*std_norm_pdf(f) def to_dict(self): - input_dict = super(Probit, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Probit, self)._save_to_input_dict() input_dict["class"] = "GPy.likelihoods.link_functions.Probit" return input_dict diff --git a/GPy/mappings/constant.py b/GPy/mappings/constant.py index 24c632c9..315b47b7 100644 --- a/GPy/mappings/constant.py +++ b/GPy/mappings/constant.py @@ -40,7 +40,14 @@ class Constant(Mapping): return np.zeros_like(X) def to_dict(self): - input_dict = super(Constant, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + input_dict = super(Constant, self)._save_to_input_dict() input_dict["class"] = "GPy.mappings.Constant" input_dict["value"] = self.C.values[0] return input_dict diff --git a/GPy/mappings/identity.py b/GPy/mappings/identity.py index 261d918f..3567b694 100644 --- a/GPy/mappings/identity.py +++ b/GPy/mappings/identity.py @@ -20,6 +20,13 @@ class Identity(Mapping): return dL_dF def to_dict(self): - input_dict = super(Identity, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + input_dict = super(Identity, self)._save_to_input_dict() input_dict["class"] = "GPy.mappings.Identity" return input_dict diff --git a/GPy/mappings/linear.py b/GPy/mappings/linear.py index e348d458..82b7a0e0 100644 --- a/GPy/mappings/linear.py +++ b/GPy/mappings/linear.py @@ -39,13 +39,21 @@ class Linear(Mapping): return np.dot(dL_dF, self.A.T) def to_dict(self): - input_dict = super(Linear, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Linear, self)._save_to_input_dict() input_dict["class"] = "GPy.mappings.Linear" input_dict["A"] = self.A.values.tolist() return input_dict @staticmethod - def _from_dict(mapping_class, input_dict): + def _build_from_input_dict(mapping_class, input_dict): import copy input_dict = copy.deepcopy(input_dict) A = np.array(input_dict.pop('A')) diff --git a/GPy/models/sparse_gp_classification.py b/GPy/models/sparse_gp_classification.py index a996732a..0e44966a 100644 --- a/GPy/models/sparse_gp_classification.py +++ b/GPy/models/sparse_gp_classification.py @@ -7,6 +7,7 @@ from ..core import SparseGP from .. import likelihoods from .. import kern from ..inference.latent_function_inference import EPDTC +from copy import deepcopy class SparseGPClassification(SparseGP): """ @@ -40,6 +41,51 @@ class SparseGPClassification(SparseGP): SparseGP.__init__(self, X, Y, Z, kernel, likelihood, inference_method=EPDTC(), name='SparseGPClassification',Y_metadata=Y_metadata) + @staticmethod + def from_sparse_gp(sparse_gp): + from copy import deepcopy + sparse_gp = deepcopy(sparse_gp) + SparseGPClassification(sparse_gp.X, sparse_gp.Y, sparse_gp.Z, sparse_gp.kern, sparse_gp.likelihood, sparse_gp.inference_method, sparse_gp.mean_function, name='sparse_gp_classification') + + def to_dict(self, save_data=True): + """ + Store the object into a json serializable dictionary + + :param boolean save_data: if true, it adds the data self.X and self.Y to the dictionary + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + model_dict = super(SparseGPClassification,self).to_dict(save_data) + model_dict["class"] = "GPy.models.SparseGPClassification" + return model_dict + + @staticmethod + def from_dict(input_dict, data=None): + """ + Instantiate an SparseGPClassification object using the information + in input_dict (built by the to_dict method). + + :param data: It is used to provide X and Y for the case when the model + was saved using save_data=False in to_dict method. + :type data: tuple(:class:`np.ndarray`, :class:`np.ndarray`) + """ + import GPy + m = GPy.core.model.Model.from_dict(input_dict, data) + from copy import deepcopy + sparse_gp = deepcopy(m) + return SparseGPClassification(sparse_gp.X, sparse_gp.Y, sparse_gp.Z, sparse_gp.kern, sparse_gp.likelihood, sparse_gp.inference_method, sparse_gp.mean_function, name='sparse_gp_classification') + + def save_model(self, output_filename, compress=True, save_data=True): + """ + Method to serialize the model. + + :param string output_filename: Output file + :param boolean compress: If true compress the file using zip + :param boolean save_data: if true, it serializes the training data + (self.X and self.Y) + """ + self._save_model(output_filename, compress=True, save_data=True) + + class SparseGPClassificationUncertainInput(SparseGP): """ Sparse Gaussian Process model for classification with uncertain inputs. @@ -87,8 +133,3 @@ class SparseGPClassificationUncertainInput(SparseGP): self.psi2 = self.kern.psi2n(self.Z, self.X) self.posterior, self._log_marginal_likelihood, self.grad_dict = self.inference_method.inference(self.kern, self.X, self.Z, self.likelihood, self.Y, self.Y_metadata, psi0=self.psi0, psi1=self.psi1, psi2=self.psi2) self._update_gradients() - - - - - diff --git a/GPy/testing/serialization_tests.py b/GPy/testing/serialization_tests.py index 7eb3fe5c..57781bf3 100644 --- a/GPy/testing/serialization_tests.py +++ b/GPy/testing/serialization_tests.py @@ -11,6 +11,7 @@ import tempfile import GPy from nose import SkipTest import numpy as np +import os fixed_seed = 11 @@ -116,46 +117,38 @@ class Test(unittest.TestCase): np.testing.assert_array_equal(e1._ep_approximation[2].v[:], e1_r._ep_approximation[2].v[:]) np.testing.assert_array_equal(e1._ep_approximation[3][:], e1_r._ep_approximation[3][:]) - - e1 = GPy.inference.latent_function_inference.expectation_propagation.EPDTC(ep_mode="nested") - e1.ga_approx_old = GPy.inference.latent_function_inference.expectation_propagation.gaussianApproximation(np.random.rand(10),np.random.rand(10)) - e1._ep_approximation = [] - e1._ep_approximation.append(GPy.inference.latent_function_inference.expectation_propagation.posteriorParamsDTC(np.random.rand(10),np.random.rand(10))) - e1._ep_approximation.append(GPy.inference.latent_function_inference.expectation_propagation.gaussianApproximation(np.random.rand(10),np.random.rand(10))) - e1._ep_approximation.append(GPy.inference.latent_function_inference.expectation_propagation.cavityParams(10)) - e1._ep_approximation[-1].v = np.random.rand(10) - e1._ep_approximation[-1].tau = np.random.rand(10) - e1._ep_approximation.append(np.random.rand(10)) - e1_r = GPy.inference.latent_function_inference.LatentFunctionInference.from_dict(e1.to_dict()) - - - assert type(e1) == type(e1_r) - assert e1.epsilon==e1_r.epsilon - assert e1.eta==e1_r.eta - assert e1.delta==e1_r.delta - assert e1.always_reset==e1_r.always_reset - assert e1.max_iters==e1_r.max_iters - assert e1.ep_mode==e1_r.ep_mode - assert e1.parallel_updates==e1_r.parallel_updates - - np.testing.assert_array_equal(e1.ga_approx_old.tau[:], e1_r.ga_approx_old.tau[:]) - np.testing.assert_array_equal(e1.ga_approx_old.v[:], e1_r.ga_approx_old.v[:]) - np.testing.assert_array_equal(e1._ep_approximation[0].mu[:], e1_r._ep_approximation[0].mu[:]) - np.testing.assert_array_equal(e1._ep_approximation[0].Sigma_diag[:], e1_r._ep_approximation[0].Sigma_diag[:]) - np.testing.assert_array_equal(e1._ep_approximation[1].tau[:], e1_r._ep_approximation[1].tau[:]) - np.testing.assert_array_equal(e1._ep_approximation[1].v[:], e1_r._ep_approximation[1].v[:]) - np.testing.assert_array_equal(e1._ep_approximation[2].tau[:], e1_r._ep_approximation[2].tau[:]) - np.testing.assert_array_equal(e1._ep_approximation[2].v[:], e1_r._ep_approximation[2].v[:]) - np.testing.assert_array_equal(e1._ep_approximation[3][:], e1_r._ep_approximation[3][:]) - - - e2 = GPy.inference.latent_function_inference.exact_gaussian_inference.ExactGaussianInference() + e2 = GPy.inference.latent_function_inference.expectation_propagation.EPDTC(ep_mode="nested") + e2.ga_approx_old = GPy.inference.latent_function_inference.expectation_propagation.gaussianApproximation(np.random.rand(10),np.random.rand(10)) + e2._ep_approximation = [] + e2._ep_approximation.append(GPy.inference.latent_function_inference.expectation_propagation.posteriorParamsDTC(np.random.rand(10),np.random.rand(10))) + e2._ep_approximation.append(GPy.inference.latent_function_inference.expectation_propagation.gaussianApproximation(np.random.rand(10),np.random.rand(10))) + e2._ep_approximation.append(100.0) e2_r = GPy.inference.latent_function_inference.LatentFunctionInference.from_dict(e2.to_dict()) assert type(e2) == type(e2_r) + assert e2.epsilon==e2_r.epsilon + assert e2.eta==e2_r.eta + assert e2.delta==e2_r.delta + assert e2.always_reset==e2_r.always_reset + assert e2.max_iters==e2_r.max_iters + assert e2.ep_mode==e2_r.ep_mode + assert e2.parallel_updates==e2_r.parallel_updates + + np.testing.assert_array_equal(e2.ga_approx_old.tau[:], e2_r.ga_approx_old.tau[:]) + np.testing.assert_array_equal(e2.ga_approx_old.v[:], e2_r.ga_approx_old.v[:]) + np.testing.assert_array_equal(e2._ep_approximation[0].mu[:], e2_r._ep_approximation[0].mu[:]) + np.testing.assert_array_equal(e2._ep_approximation[0].Sigma_diag[:], e2_r._ep_approximation[0].Sigma_diag[:]) + np.testing.assert_array_equal(e2._ep_approximation[1].tau[:], e2_r._ep_approximation[1].tau[:]) + np.testing.assert_array_equal(e2._ep_approximation[1].v[:], e2_r._ep_approximation[1].v[:]) + assert(e2._ep_approximation[2] == e2_r._ep_approximation[2]) + + e3 = GPy.inference.latent_function_inference.exact_gaussian_inference.ExactGaussianInference() + e3_r = GPy.inference.latent_function_inference.LatentFunctionInference.from_dict(e3.to_dict()) + + assert type(e3) == type(e3_r) - def test_serialize_deserialize_model(self): + def test_serialize_deserialize_GP(self): np.random.seed(fixed_seed) N = 20 Nhalf = int(N/2) @@ -165,13 +158,13 @@ class Test(unittest.TestCase): likelihood = GPy.likelihoods.Bernoulli() inference_method=GPy.inference.latent_function_inference.expectation_propagation.EP(ep_mode="nested") mean_function=None + m = GPy.core.GP(X=X, Y=Y, kernel=kernel, likelihood=likelihood, inference_method=inference_method, mean_function=mean_function, normalizer=True, name='gp_classification') m.optimize() m.save_model("temp_test_gp_with_data.json", compress=True, save_data=True) m.save_model("temp_test_gp_without_data.json", compress=True, save_data=False) m1_r = GPy.core.GP.load_model("temp_test_gp_with_data.json.zip") m2_r = GPy.core.GP.load_model("temp_test_gp_without_data.json.zip", (X,Y)) - import os os.remove("temp_test_gp_with_data.json.zip") os.remove("temp_test_gp_without_data.json.zip") var = m.predict(X)[0] @@ -180,7 +173,32 @@ class Test(unittest.TestCase): np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) np.testing.assert_array_equal(np.array(var).flatten(), np.array(var2_r).flatten()) - def test_serialize_deserialize_inference_GPRegressor(self): + def test_serialize_deserialize_SparseGP(self): + np.random.seed(fixed_seed) + N = 20 + Nhalf = int(N/2) + X = np.hstack([np.random.normal(5, 2, Nhalf), np.random.normal(10, 2, Nhalf)])[:, None] + Y = np.hstack([np.ones(Nhalf), np.zeros(Nhalf)])[:, None] + kernel = GPy.kern.RBF(1) + likelihood = GPy.likelihoods.Bernoulli() + inference_method=GPy.inference.latent_function_inference.expectation_propagation.EPDTC(ep_mode="nested") + mean_function=None + + sm = GPy.core.SparseGP(X=X, Y=Y, Z=X[0:20,:], kernel=kernel, likelihood=likelihood, inference_method=inference_method, mean_function=mean_function, normalizer=True, name='sparse_gp_classification') + sm.optimize() + sm.save_model("temp_test_gp_with_data.json", compress=True, save_data=True) + sm.save_model("temp_test_gp_without_data.json", compress=True, save_data=False) + sm1_r = GPy.core.GP.load_model("temp_test_gp_with_data.json.zip") + sm2_r = GPy.core.GP.load_model("temp_test_gp_without_data.json.zip", (X,Y)) + os.remove("temp_test_gp_with_data.json.zip") + os.remove("temp_test_gp_without_data.json.zip") + var = sm.predict(X)[0] + var1_r = sm1_r.predict(X)[0] + var2_r = sm2_r.predict(X)[0] + np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) + np.testing.assert_array_equal(np.array(var).flatten(), np.array(var2_r).flatten()) + + def test_serialize_deserialize_GPRegressor(self): np.random.seed(fixed_seed) N = 50 N_new = 50 @@ -195,7 +213,6 @@ class Test(unittest.TestCase): m.save_model("temp_test_gp_regressor_without_data.json", compress=True, save_data=False) m1_r = GPy.models.GPRegression.load_model("temp_test_gp_regressor_with_data.json.zip") m2_r = GPy.models.GPRegression.load_model("temp_test_gp_regressor_without_data.json.zip", (X,Y)) - import os os.remove("temp_test_gp_regressor_with_data.json.zip") os.remove("temp_test_gp_regressor_without_data.json.zip") @@ -208,7 +225,7 @@ class Test(unittest.TestCase): np.testing.assert_array_equal(var.flatten(), var1_r.flatten()) np.testing.assert_array_equal(var.flatten(), var2_r.flatten()) - def test_serialize_deserialize_inference_GPClassifier(self): + def test_serialize_deserialize_GPClassification(self): np.random.seed(fixed_seed) N = 50 Nhalf = int(N/2) @@ -221,7 +238,6 @@ class Test(unittest.TestCase): m.save_model("temp_test_gp_classifier_without_data.json", compress=True, save_data=False) m1_r = GPy.models.GPClassification.load_model("temp_test_gp_classifier_with_data.json.zip") m2_r = GPy.models.GPClassification.load_model("temp_test_gp_classifier_without_data.json.zip", (X,Y)) - import os os.remove("temp_test_gp_classifier_with_data.json.zip") os.remove("temp_test_gp_classifier_without_data.json.zip") @@ -231,6 +247,28 @@ class Test(unittest.TestCase): np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) + def test_serialize_deserialize_SparseGPClassification(self): + np.random.seed(fixed_seed) + N = 50 + Nhalf = int(N/2) + X = np.hstack([np.random.normal(5, 2, Nhalf), np.random.normal(10, 2, Nhalf)])[:, None] + Y = np.hstack([np.ones(Nhalf), np.zeros(Nhalf)])[:, None] + kernel = GPy.kern.RBF(1) + m = GPy.models.SparseGPClassification(X, Y, num_inducing=3, kernel=kernel) + m.optimize() + m.save_model("temp_test_sparse_gp_classifier_with_data.json", compress=True, save_data=True) + m.save_model("temp_test_sparse_gp_classifier_without_data.json", compress=True, save_data=False) + m1_r = GPy.models.SparseGPClassification.load_model("temp_test_sparse_gp_classifier_with_data.json.zip") + m2_r = GPy.models.SparseGPClassification.load_model("temp_test_sparse_gp_classifier_without_data.json.zip", (X,Y)) + os.remove("temp_test_sparse_gp_classifier_with_data.json.zip") + os.remove("temp_test_sparse_gp_classifier_without_data.json.zip") + + var = m.predict(X)[0] + var1_r = m1_r.predict(X)[0] + var2_r = m2_r.predict(X)[0] + np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) + np.testing.assert_array_equal(np.array(var).flatten(), np.array(var1_r).flatten()) + if __name__ == "__main__": #import sys;sys.argv = ['', 'Test.test_parameter_index_operations'] unittest.main() diff --git a/GPy/util/normalizer.py b/GPy/util/normalizer.py index 7a3ee020..2e6d991a 100644 --- a/GPy/util/normalizer.py +++ b/GPy/util/normalizer.py @@ -52,21 +52,33 @@ class _Norm(object): def to_dict(self): raise NotImplementedError - def _to_dict(self): + def _save_to_input_dict(self): input_dict = {} return input_dict @staticmethod def from_dict(input_dict): + """ + Instantiate an object of a derived class using the information + in input_dict (built by the to_dict method of the derived class). + More specifically, after reading the derived class from input_dict, + it calls the method _build_from_input_dict of the derived class. + Note: This method should not be overrided in the derived class. In case + it is needed, please override _build_from_input_dict instate. + + :param dict input_dict: Dictionary with all the information needed to + instantiate the object. + """ + import copy input_dict = copy.deepcopy(input_dict) normalizer_class = input_dict.pop('class') import GPy normalizer_class = eval(normalizer_class) - return normalizer_class._from_dict(normalizer_class, input_dict) + return normalizer_class._build_from_input_dict(normalizer_class, input_dict) @staticmethod - def _from_dict(normalizer_class, input_dict): + def _build_from_input_dict(normalizer_class, input_dict): return normalizer_class(**input_dict) @@ -96,7 +108,15 @@ class Standardize(_Norm): return self.mean is not None def to_dict(self): - input_dict = super(Standardize, self)._to_dict() + """ + Convert the object into a json serializable dictionary. + + Note: It uses the private method _save_to_input_dict of the parent. + + :return dict: json serializable dictionary containing the needed information to instantiate the object + """ + + input_dict = super(Standardize, self)._save_to_input_dict() input_dict["class"] = "GPy.util.normalizer.Standardize" if self.mean is not None: input_dict["mean"] = self.mean.tolist() @@ -104,7 +124,7 @@ class Standardize(_Norm): return input_dict @staticmethod - def _from_dict(kernel_class, input_dict): + def _build_from_input_dict(kernel_class, input_dict): s = Standardize() if "mean" in input_dict: s.mean = np.array(input_dict["mean"])