class_docstr: A meta-model that trains the base model multiple times using different train/validation splits.
  
  Follows the logic of autogluon.core.models.ensembles.BaggedEnsembleModel.
  
  Parameters
  ----------
  model_base : Union[AbstractTimeSeriesModel, Type[AbstractTimeSeriesModel]]
      The base model to repeatedly train. If a AbstractTimeSeriesModel class, then also provide model_base_kwargs
      which will be used to initialize the model via model_base(**model_base_kwargs).
  model_base_kwargs : Optional[Dict[str, any]], default = None
      kwargs used to initialize model_base if model_base is a class.
class_docstr_tok: ["A","meta-model","that","trains","the","base","model","multiple","times","using","different","train\/validation","splits",".","Follows","the","logic","of","autogluon.core.models.ensembles.BaggedEnsembleModel",".","Parameters","--","--","--","--","--","model_base",":","Union","[","AbstractTimeSeriesModel",",","Type","[","AbstractTimeSeriesModel","]","]","The","base","model","to","repeatedly","train",".","If","a","AbstractTimeSeriesModel","class",",","then","also","provide","model_base_kwargs","which","will","be","used","to","initialize","the","model","via","model_base","(","*","*","model_base_kwargs",")",".","model_base_kwargs",":","Optional","[","Dict","[","str",",","any","]","]",",","default","=","None","kwargs","used","to","initialize","model_base","if","model_base","is","a","class","."]
code: def _fit(
      self,
      train_data: TimeSeriesDataFrame,
      val_data: Optional[TimeSeriesDataFrame] = None,
      time_limit: Optional[int] = None,
      val_splitter: AbstractWindowSplitter = None,
      refit_every_n_windows: Optional[int] = 1,
      **kwargs,
  ):
      # TODO: use incremental training for GluonTS models?
      # TODO: implement parallel fitting similar to ParallelLocalFoldFittingStrategy in tabular?
      verbosity = kwargs.get("verbosity", 2)
      set_logger_verbosity(verbosity, logger=logger)
  
      if val_data is not None:
          raise ValueError(
              f"val_data should not be passed to {self.name}.fit()"
          )
      if val_splitter is None:
          val_splitter = ExpandingWindowSplitter(
              prediction_length=self.prediction_length
          )
      if (
          not isinstance(val_splitter, AbstractWindowSplitter)
          or val_splitter.num_val_windows <= 0
      ):
          raise ValueError(
              f"{self.name}.fit expects an AbstractWindowSplitter with num_val_windows > 0"
          )
      if refit_every_n_windows is None:
          refit_every_n_windows = (
              val_splitter.num_val_windows + 1
          )  # only fit model for the first window
  
      oof_predictions_per_window = []
      global_fit_start_time = time.time()
  
      for window_index, (train_fold, val_fold) in enumerate(
          val_splitter.split(train_data)
      ):
          logger.debug(f"\tWindow {window_index}")
          # refit_this_window is always True for the 0th window
          refit_this_window = window_index % refit_every_n_windows == 0
          if time_limit is None:
              time_left_for_window = None
          else:
              time_left = time_limit - (
                  time.time() - global_fit_start_time
              )
              if issubclass(self.model_base_type, AbstractLocalModel):
                  # For local models we call `fit` for every window to ensure that the time_limit is respected.
                  refit_this_window = True
                  # Local models cannot early stop, we allocate all remaining time and hope that they finish in time
                  time_left_for_window = time_left
              else:
                  num_refits_remaining = math.ceil(
                      (val_splitter.num_val_windows - window_index)
                      / refit_every_n_windows
                  )
                  # Reserve 10% of the remaining time for prediction, use 90% of time for training
                  time_left_for_window = (
                      0.9 * time_left / num_refits_remaining
                  )
  
          if refit_this_window:
              model = self.get_child_model(window_index)
              model_fit_start_time = time.time()
              model.fit(
                  train_data=train_fold,
                  val_data=val_fold,
                  time_limit=time_left_for_window,
                  **kwargs,
              )
              model.fit_time = time.time() - model_fit_start_time
              most_recent_refit_window = f"W{window_index}"
          model.score_and_cache_oof(
              val_fold, store_val_score=True, store_predict_time=True
          )
  
          oof_predictions_per_window.append(
              model.get_oof_predictions()[0]
          )
  
          logger.debug(
              f"\t\t{model.val_score:<7.4f}".ljust(15)
              + f"= Validation score ({model.eval_metric.name_with_sign})"
          )
          logger.debug(
              f"\t\t{model.fit_time:<7.3f} s".ljust(15)
              + "= Training runtime"
          )
          logger.debug(
              f"\t\t{model.predict_time:<7.3f} s".ljust(15)
              + "= Prediction runtime"
          )
  
          self.info_per_val_window.append(
              {
                  "window_index": window_index,
                  "refit_this_window": refit_this_window,
                  "fit_time": model.fit_time
                  if refit_this_window
                  else float("nan"),
                  "val_score": model.val_score,
                  "predict_time": model.predict_time,
              }
          )
  
      # Only the model trained on most recent data is saved & used for prediction
      self.most_recent_model = model
      self.most_recent_model_folder = most_recent_refit_window
      self.predict_time = self.most_recent_model.predict_time
      self.fit_time = (
          time.time() - global_fit_start_time - self.predict_time
      )
      self._oof_predictions = oof_predictions_per_window
      self.val_score = np.mean(
          [info["val_score"] for info in self.info_per_val_window]
      )
  
imports: import copy
  import inspect
  import logging
  import math
  import os
  import time
  from typing import Dict, Optional, Type, Union
  import numpy
  import autogluon.core
  from autogluon.common.utils.log_utils import set_logger_verbosity
  from autogluon.timeseries.dataset.ts_dataframe import TimeSeriesDataFrame
  from autogluon.timeseries.models.abstract import AbstractTimeSeriesModel
  from autogluon.timeseries.models.local.abstract_local_model import AbstractLocalModel
  from autogluon.timeseries.splitter import AbstractWindowSplitter, ExpandingWindowSplitter
label_desc: Use image node_id 6 for calling the MultiWindowBacktestingModel obj's underlying member method code with example usage: obj._fit(train_data, val_data, time_limit, val_splitter, refit_every_n_windows) without return types