def to_dict(self, save_data=True):
        """
        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
            input_dict["Y"] = None
        else:
            try:
                input_dict["X"] = self.X.values.tolist()
            except:
                input_dict["X"] = self.X.tolist()
            try:
                input_dict["Y"] = self.Y.values.tolist()
            except:
                input_dict["Y"] = self.Y.tolist()
        input_dict["kernel"] = self.kern.to_dict()
        input_dict["likelihood"] = self.likelihood.to_dict()
        if self.mean_function is not None:
            input_dict["mean_function"] = self.mean_function.to_dict()
        input_dict["inference_method"] = self.inference_method.to_dict()
        #FIXME: Assumes the Y_metadata is serializable. We should create a Metadata class
        if self.Y_metadata is not None:
            input_dict["Y_metadata"] = self.Y_metadata
        if self.normalizer is not None:
            input_dict["normalizer"] = self.normalizer.to_dict()
        return input_dict