class_docstr: KRNN Model
  
  Parameters
  ----------
  d_feat : int
      input dimension for each time step
  metric: str
      the evaluation metric used in early stop
  optimizer : str
      optimizer name
  GPU : str
      the GPU ID(s) used for training
code: def fit(
      self,
      dataset: DatasetH,
      evals_result=dict(),
      save_path=None,
  ):
      df_train, df_valid, df_test = dataset.prepare(
          ["train", "valid", "test"],
          col_set=["feature", "label"],
          data_key=DataHandlerLP.DK_L,
      )
      if df_train.empty or df_valid.empty:
          raise ValueError(
              "Empty data from dataset, please check your dataset config."
          )
  
      x_train, y_train = df_train["feature"], df_train["label"]
      x_valid, y_valid = df_valid["feature"], df_valid["label"]
  
      save_path = get_or_create_path(save_path)
      stop_steps = 0
      train_loss = 0
      best_score = -np.inf
      best_epoch = 0
      evals_result["train"] = []
      evals_result["valid"] = []
  
      # train
      self.logger.info("training...")
      self.fitted = True
  
      for step in range(self.n_epochs):
          self.logger.info("Epoch%d:", step)
          self.logger.info("training...")
          self.train_epoch(x_train, y_train)
          self.logger.info("evaluating...")
          train_loss, train_score = self.test_epoch(x_train, y_train)
          val_loss, val_score = self.test_epoch(x_valid, y_valid)
          self.logger.info(
              "train %.6f, valid %.6f" % (train_score, val_score)
          )
          evals_result["train"].append(train_score)
          evals_result["valid"].append(val_score)
  
          if val_score > best_score:
              best_score = val_score
              stop_steps = 0
              best_epoch = step
              best_param = copy.deepcopy(self.krnn_model.state_dict())
          else:
              stop_steps += 1
              if stop_steps >= self.early_stop:
                  self.logger.info("early stop")
                  break
  
      self.logger.info(
          "best score: %.6lf @ %d" % (best_score, best_epoch)
      )
      self.krnn_model.load_state_dict(best_param)
      torch.save(best_param, save_path)
  
      if self.use_gpu:
          torch.cuda.empty_cache()
  
imports: from __future__ import division
  from __future__ import print_function
  import numpy
  import pandas
  from typing import Text, Union
  import copy
  from ...utils import get_or_create_path
  from ...log import get_module_logger
  import torch
  import torch.nn
  import torch.optim
  from ...model.base import Model
  from ...data.dataset import DatasetH
  from ...data.dataset.handler import DataHandlerLP
label_desc: Use image node_id 9 for calling the KRNN obj's underlying member method code with example usage: obj.fit(dataset, evals_result, save_path) without return types