code: def to_dict(self, save_data=True):
          
          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
docs: 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