class_docstr: Base Windows
  
  Base class for all windows-based models. The forecasts are produced separately
  for each window, which are randomly sampled during training.
  
  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 generate windows.
class_docstr_tok: ["Base","Windows","Base","class","for","all","windows-based","models",".","The","forecasts","are","produced","separately","for","each","window",",","which","are","randomly","sampled","during","training",".","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","generate","windows","."]
code: def training_step(self, batch, batch_idx):
      # Create and normalize windows [Ws, L+H, C]
      windows = self._create_windows(batch, step="train")
      y_idx = batch["y_idx"]
      original_outsample_y = torch.clone(
          windows["temporal"][:, -self.h :, y_idx]
      )
      windows = self._normalization(windows=windows, y_idx=y_idx)
  
      # 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,  # [Ws, L]
          insample_mask=insample_mask,  # [Ws, L]
          futr_exog=futr_exog,  # [Ws, L+H]
          hist_exog=hist_exog,  # [Ws, L]
          stat_exog=stat_exog,
      )  # [Ws, 1]
  
      # Model Predictions
      output = self(windows_batch)
      if self.loss.is_distribution_output:
          _, y_loc, y_scale = self._inv_normalization(
              y_hat=outsample_y,
              temporal_cols=batch["temporal_cols"],
              y_idx=y_idx,
          )
          outsample_y = original_outsample_y
          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, 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 BaseWindows obj's underlying member method code with example usage: obj.training_step(batch, batch_idx) and returns: loss