class_docstr: Base Recurrent
  
  Base class for all recurrent-based models. The forecasts are produced sequentially between
  windows.
  
  This class implements the basic functionality for all windows-based models, including:
  - PyTorch Lightning's methods training_step, validation_step, predict_step. <br>
  - fit and predict methods used by NeuralForecast.core class. <br>
  - sampling and wrangling methods to sequential windows. <br>
class_docstr_tok: ["Base","Recurrent","Base","class","for","all","recurrent-based","models",".","The","forecasts","are","produced","sequentially","between","windows",".","This","class","implements","the","basic","functionality","for","all","windows-based","models",",","including",":","-","PyTorch","Lightning","'s","methods","training_step",",","validation_step",",","predict_step",".","<","br",">","-","fit","and","predict","methods","used","by","NeuralForecast.core","class",".","<","br",">","-","sampling","and","wrangling","methods","to","sequential","windows",".","<","br",">"]
code: def training_step(self, batch, batch_idx):
      # Create and normalize windows [Ws, L+H, C]
      batch = self._normalization(
          batch, val_size=self.val_size, test_size=self.test_size
      )
      windows = self._create_windows(batch, step="train")
  
      # Parse windows
      (
          insample_y,
          insample_mask,
          outsample_y,
          outsample_mask,
          hist_exog,
          futr_exog,
          stat_exog,
      ) = self._parse_windows(batch, windows)
  
      windows_batch = dict(
          insample_y=insample_y,  # [B, seq_len, 1]
          insample_mask=insample_mask,  # [B, seq_len, 1]
          futr_exog=futr_exog,  # [B, F, seq_len, 1+H]
          hist_exog=hist_exog,  # [B, C, seq_len]
          stat_exog=stat_exog,
      )  # [B, S]
  
      # Model predictions
      output = self(windows_batch)  # tuple([B, seq_len, H, output])
      if self.loss.is_distribution_output:
          outsample_y, y_loc, y_scale = self._inv_normalization(
              y_hat=outsample_y,
              temporal_cols=batch["temporal_cols"],
              y_idx=batch["y_idx"],
          )
          B = output[0].size()[0]
          T = output[0].size()[1]
          H = output[0].size()[2]
          output = [arg.view(-1, *(arg.size()[2:])) for arg in output]
          outsample_y = outsample_y.view(B * T, H)
          outsample_mask = outsample_mask.view(B * T, H)
          y_loc = y_loc.repeat_interleave(repeats=T, dim=0).squeeze(-1)
          y_scale = y_scale.repeat_interleave(repeats=T, dim=0).squeeze(
              -1
          )
          distr_args = self.loss.scale_decouple(
              output=output, loc=y_loc, scale=y_scale
          )
          loss = self.loss(
              y=outsample_y, distr_args=distr_args, mask=outsample_mask
          )
      else:
          loss = self.loss(
              y=outsample_y, y_hat=output, mask=outsample_mask
          )
  
      if torch.isnan(loss):
          print("Model Parameters", self.hparams)
          print("insample_y", torch.isnan(insample_y).sum())
          print("outsample_y", torch.isnan(outsample_y).sum())
          print("output", torch.isnan(output).sum())
          raise Exception("Loss is NaN, training stopped.")
  
      self.log(
          "train_loss",
          loss,
          batch_size=self.batch_size,
          prog_bar=True,
          on_epoch=True,
      )
      self.train_trajectories.append((self.global_step, float(loss)))
      return loss
  
imports: import random
  import warnings
  import numpy
  import torch
  import torch.nn
  import pytorch_lightning
  from pytorch_lightning.callbacks import TQDMProgressBar
  from pytorch_lightning.callbacks.early_stopping import EarlyStopping
  from ._scalers import TemporalNorm
  from ..tsdataset import TimeSeriesDataModule
  from ..utils import get_indexer_raise_missing
label_desc: Use image node_id 10 for calling the BaseRecurrent obj's underlying member method code with example usage: obj.training_step(batch, batch_idx) and returns: loss