class_docstr: TCTS 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
class_docstr_tok: ["TCTS","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 training(
      self,
      x_train,
      y_train,
      x_valid,
      y_valid,
      x_test,
      y_test,
      verbose=True,
      save_path=None,
  ):
      self.fore_model = GRUModel(
          d_feat=self.d_feat,
          hidden_size=self.hidden_size,
          num_layers=self.num_layers,
          dropout=self.dropout,
      )
      self.weight_model = MLPModel(
          d_feat=self.input_dim + 3 * self.output_dim + 1,
          hidden_size=self.hidden_size,
          num_layers=self.num_layers,
          dropout=self.dropout,
          output_dim=self.output_dim,
      )
      if self._fore_optimizer.lower() == "adam":
          self.fore_optimizer = optim.Adam(
              self.fore_model.parameters(), lr=self.fore_lr
          )
      elif self._fore_optimizer.lower() == "gd":
          self.fore_optimizer = optim.SGD(
              self.fore_model.parameters(), lr=self.fore_lr
          )
      else:
          raise NotImplementedError(
              "optimizer {} is not supported!".format(
                  self._fore_optimizer
              )
          )
      if self._weight_optimizer.lower() == "adam":
          self.weight_optimizer = optim.Adam(
              self.weight_model.parameters(), lr=self.weight_lr
          )
      elif self._weight_optimizer.lower() == "gd":
          self.weight_optimizer = optim.SGD(
              self.weight_model.parameters(), lr=self.weight_lr
          )
      else:
          raise NotImplementedError(
              "optimizer {} is not supported!".format(
                  self._weight_optimizer
              )
          )
  
      self.fitted = False
      self.fore_model.to(self.device)
      self.weight_model.to(self.device)
  
      best_loss = np.inf
      best_epoch = 0
      stop_round = 0
  
      for epoch in range(self.n_epochs):
          print("Epoch:", epoch)
  
          print("training...")
          self.train_epoch(x_train, y_train, x_valid, y_valid)
          print("evaluating...")
          val_loss = self.test_epoch(x_valid, y_valid)
          test_loss = self.test_epoch(x_test, y_test)
  
          if verbose:
              print("valid %.6f, test %.6f" % (val_loss, test_loss))
  
          if val_loss < best_loss:
              best_loss = val_loss
              stop_round = 0
              best_epoch = epoch
              torch.save(
                  copy.deepcopy(self.fore_model.state_dict()),
                  save_path + "_fore_model.bin",
              )
              torch.save(
                  copy.deepcopy(self.weight_model.state_dict()),
                  save_path + "_weight_model.bin",
              )
  
          else:
              stop_round += 1
              if stop_round >= self.early_stop:
                  print("early stop")
                  break
  
      print("best loss:", best_loss, "@", best_epoch)
      best_param = torch.load(
          save_path + "_fore_model.bin", map_location=self.device
      )
      self.fore_model.load_state_dict(best_param)
      best_param = torch.load(
          save_path + "_weight_model.bin", map_location=self.device
      )
      self.weight_model.load_state_dict(best_param)
      self.fitted = True
  
      if self.use_gpu:
          torch.cuda.empty_cache()
  
      return best_loss
  
imports: from __future__ import division
  from __future__ import print_function
  import numpy
  import pandas
  import copy
  import random
  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 6 for calling the TCTS obj's underlying member method code with example usage: obj.training(x_train, y_train, x_valid, y_valid, x_test, y_test, verbose, save_path) and returns: best_loss