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 bootstrap_fit(
      self, x_train, y_train, m_train, x_valid, y_valid, m_valid
  ):
      stop_steps = 0
      best_score = -np.inf
      best_epoch = 0
  
      # train
      self.logger.info("training...")
      self.fitted = True
      x_train_values = x_train.values
      y_train_values = np.squeeze(y_train.values)
      m_train_values = np.squeeze(m_train.values.astype(int))
  
      for step in range(self.n_epochs):
          self.logger.info("Epoch%d:", step)
          self.logger.info("training...")
          self.train_epoch(
              x_train_values, y_train_values, m_train_values
          )
          self.logger.info("evaluating...")
          train_metrics = self.test_epoch(x_train, y_train, m_train)
          valid_metrics = self.test_epoch(x_valid, y_valid, m_valid)
          self.log_metrics("train", train_metrics)
          self.log_metrics("valid", valid_metrics)
  
          if self.metric in valid_metrics:
              val_score = valid_metrics[self.metric]
          else:
              raise ValueError("unknown metric name `%s`" % self.metric)
          if val_score > best_score:
              best_score = val_score
              stop_steps = 0
              best_epoch = step
              best_param = copy.deepcopy(self.ADD_model.state_dict())
          else:
              stop_steps += 1
              if stop_steps >= self.early_stop:
                  self.logger.info("early stop")
                  break
          self.ADD_model.before_adv_excess.step_alpha()
          self.ADD_model.before_adv_market.step_alpha()
      self.logger.info(
          "bootstrap_fit best score: {:.6f} @ {}".format(
              best_score, best_epoch
          )
      )
      self.ADD_model.load_state_dict(best_param)
      return best_score
  
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 16 for calling the ADD obj's underlying member method code with example usage: obj.bootstrap_fit(x_train, y_train, m_train, x_valid, y_valid, m_valid) and returns: best_score