class_docstr: ADD Model
  
  Parameters
  ----------
   lr : float
       learning rate
   d_feat : int
       input dimensions for each time step
   metric : str
       the evaluation metric used in early stop
   optimizer : str
       optimizer name
   GPU : int
       the GPU ID used for training
code: def __init__(
      self,
      d_feat=6,
      hidden_size=64,
      num_layers=2,
      dropout=0.0,
      dec_dropout=0.0,
      n_epochs=200,
      lr=0.001,
      metric="mse",
      batch_size=5000,
      early_stop=20,
      base_model="GRU",
      model_path=None,
      optimizer="adam",
      gamma=0.1,
      gamma_clip=0.4,
      mu=0.05,
      GPU=0,
      seed=None,
      **kwargs,
  ):
      # Set logger.
      self.logger = get_module_logger("ADD")
      self.logger.info("ADD pytorch version...")
  
      # set hyper-parameters.
      self.d_feat = d_feat
      self.hidden_size = hidden_size
      self.num_layers = num_layers
      self.dropout = dropout
      self.dec_dropout = dec_dropout
      self.n_epochs = n_epochs
      self.lr = lr
      self.metric = metric
      self.batch_size = batch_size
      self.early_stop = early_stop
      self.optimizer = optimizer.lower()
      self.base_model = base_model
      self.model_path = model_path
      self.device = torch.device(
          "cuda:%d" % (GPU)
          if torch.cuda.is_available() and GPU >= 0
          else "cpu"
      )
      self.seed = seed
  
      self.gamma = gamma
      self.gamma_clip = gamma_clip
      self.mu = mu
  
      self.logger.info(
          "ADD parameters setting:"
          "\nd_feat : {}"
          "\nhidden_size : {}"
          "\nnum_layers : {}"
          "\ndropout : {}"
          "\ndec_dropout : {}"
          "\nn_epochs : {}"
          "\nlr : {}"
          "\nmetric : {}"
          "\nbatch_size : {}"
          "\nearly_stop : {}"
          "\noptimizer : {}"
          "\nbase_model : {}"
          "\nmodel_path : {}"
          "\ngamma : {}"
          "\ngamma_clip : {}"
          "\nmu : {}"
          "\ndevice : {}"
          "\nuse_GPU : {}"
          "\nseed : {}".format(
              d_feat,
              hidden_size,
              num_layers,
              dropout,
              dec_dropout,
              n_epochs,
              lr,
              metric,
              batch_size,
              early_stop,
              optimizer.lower(),
              base_model,
              model_path,
              gamma,
              gamma_clip,
              mu,
              self.device,
              self.use_gpu,
              seed,
          )
      )
  
      if self.seed is not None:
          np.random.seed(self.seed)
          torch.manual_seed(self.seed)
  
      self.ADD_model = ADDModel(
          d_feat=self.d_feat,
          hidden_size=self.hidden_size,
          num_layers=self.num_layers,
          dropout=self.dropout,
          dec_dropout=self.dec_dropout,
          base_model=self.base_model,
          gamma=self.gamma,
          gamma_clip=self.gamma_clip,
      )
      self.logger.info("model:\n{:}".format(self.ADD_model))
      self.logger.info(
          "model size: {:.4f} MB".format(
              count_parameters(self.ADD_model)
          )
      )
  
      if optimizer.lower() == "adam":
          self.train_optimizer = optim.Adam(
              self.ADD_model.parameters(), lr=self.lr
          )
      elif optimizer.lower() == "gd":
          self.train_optimizer = optim.SGD(
              self.ADD_model.parameters(), lr=self.lr
          )
      else:
          raise NotImplementedError(
              "optimizer {} is not supported!".format(optimizer)
          )
  
      self.fitted = False
      self.ADD_model.to(self.device)
  
imports: from __future__ import division
  from __future__ import print_function
  import copy
  import math
  from typing import Text, Union
  import numpy
  import pandas
  import torch
  import torch.nn
  import torch.nn.functional
  import torch.optim
  from qlib.contrib.model.pytorch_gru import GRUModel
  from qlib.contrib.model.pytorch_lstm import LSTMModel
  from qlib.contrib.model.pytorch_utils import count_parameters
  from qlib.data.dataset import DatasetH
  from qlib.data.dataset.handler import DataHandlerLP
  from qlib.log import get_module_logger
  from qlib.model.base import Model
  from qlib.utils import get_or_create_path
  from torch.autograd import Function
label_desc: Use image node_id 1 to create a new ADD object from inherited base classes: Model with example: obj = ADD(d_feat, hidden_size, num_layers, dropout, dec_dropout, n_epochs, lr, metric, batch_size, early_stop, base_model, model_path, optimizer, gamma, gamma_clip, mu, GPU, seed)