class_docstr: A trainer for `AbstractComponent`s. Used mainly for supervised learning.
  
  Create a `ModelTrainer` by passing a `AbstractNeuralModel` in the constructor.
  Invoke `train()` to initiate the training loop. The root `TNeuralModule` should return a scalar loss.
class_docstr_tok: ["A","trainer","for","`","AbstractComponent","`","s",".","Used","mainly","for","supervised","learning",".","Create","a","`","ModelTrainer","`","by","passing","a","`","AbstractNeuralModel","`","in","the","constructor",".","Invoke","`","train","(",")","`","to","initiate","the","training","loop",".","The","root","`","TNeuralModule","`","should","return","a","scalar","loss","."]
docstr: The training-validation loop for `AbstractNeuralModel`s.
  
  :param training_data: An iterable that each iteration yields the full training data.
  :param validation_data: An iterable that each iteration yields the full validation data.
  :param show_progress_bar: Show a progress bar
  :param validate_on_start: Whether to run a validation loop on start
  :param patience: The number of iterations before early stopping kicks in.
  :param initialize_metadata: If true, initialize the metadata from the training_data. Otherwise,
      assume that the model that is being trained has its metadata already initialized.
  :param parallelize: Bool indicating whether to run in parallel
  :param use_multiprocessing: Whether to use multiprocessing
  :param exponential_running_average_factor: The factor of the running average of the training loss
      displayed in the progress bar.
  :param device: the target PyTorch device for training
  :param store_tensorized_data_in_memory: store all tensorized data in memory instead of computing them on-line.
  :param shuffle_training_data: shuffle the incoming data from `training_data`.
  :param start_epoch_idx: the idx of the first epoch in this training loop (used for resuming).
docstr_tok: ["The","training-validation","loop","for","`","AbstractNeuralModel","`","s",".",":","param","training_data",":","An","iterable","that","each","iteration","yields","the","full","training","data",".",":","param","validation_data",":","An","iterable","that","each","iteration","yields","the","full","validation","data",".",":","param","show_progress_bar",":","Show","a","progress","bar",":","param","validate_on_start",":","Whether","to","run","a","validation","loop","on","start",":","param","patience",":","The","number","of","iterations","before","early","stopping","kicks","in",".",":","param","initialize_metadata",":","If","true",",","initialize","the","metadata","from","the","training_data",".","Otherwise",",","assume","that","the","model","that","is","being","trained","has","its","metadata","already","initialized",".",":","param","parallelize",":","Bool","indicating","whether","to","run","in","parallel",":","param","use_multiprocessing",":","Whether","to","use","multiprocessing",":","param","exponential_running_average_factor",":","The","factor","of","the","running","average","of","the","training","loss","displayed","in","the","progress","bar",".",":","param","device",":","the","target","PyTorch","device","for","training",":","param","store_tensorized_data_in_memory",":","store","all","tensorized","data","in","memory","instead","of","computing","them","on-line",".",":","param","shuffle_training_data",":","shuffle","the","incoming","data","from","`","training_data","`",".",":","param","start_epoch_idx",":","the","idx","of","the","first","epoch","in","this","training","loop","(","used","for","resuming",")","."]
code: def train(
      self,
      training_data: Iterable[TRawDatapoint],
      validation_data: Iterable[TRawDatapoint],
      *,
      show_progress_bar: bool = True,
      validate_on_start: bool = True,
      patience: int = 5,
      initialize_metadata: bool = True,
      parallelize: bool = True,
      use_multiprocessing: bool = True,
      exponential_running_average_factor: float = 0.97,
      device=None,
      store_tensorized_data_in_memory: bool = False,
      shuffle_training_data: bool = True,
      start_epoch_idx: int = 0,
  ) -> None:
      """
      The training-validation loop for `AbstractNeuralModel`s.
  
      :param training_data: An iterable that each iteration yields the full training data.
      :param validation_data: An iterable that each iteration yields the full validation data.
      :param show_progress_bar: Show a progress bar
      :param validate_on_start: Whether to run a validation loop on start
      :param patience: The number of iterations before early stopping kicks in.
      :param initialize_metadata: If true, initialize the metadata from the training_data. Otherwise,
          assume that the model that is being trained has its metadata already initialized.
      :param parallelize: Bool indicating whether to run in parallel
      :param use_multiprocessing: Whether to use multiprocessing
      :param exponential_running_average_factor: The factor of the running average of the training loss
          displayed in the progress bar.
      :param device: the target PyTorch device for training
      :param store_tensorized_data_in_memory: store all tensorized data in memory instead of computing them on-line.
      :param shuffle_training_data: shuffle the incoming data from `training_data`.
      :param start_epoch_idx: the idx of the first epoch in this training loop (used for resuming).
      """
      if initialize_metadata:
          self.load_metadata_and_create_network(
              training_data, parallelize, show_progress_bar
          )
  
      self.LOGGER.info(
          "Model has %s trainable parameters.",
          sum(
              param.numel()
              for param in self.neural_module.parameters(recurse=True)
              if param.requires_grad
          ),
      )
  
      training_tensors = lambda: self.__model.tensorize_dataset(
          iter(training_data),
          parallelize=parallelize,
          use_multiprocessing=use_multiprocessing,
      )
      validation_tensors = lambda: self.__model.tensorize_dataset(
          iter(validation_data),
          parallelize=parallelize,
          use_multiprocessing=use_multiprocessing,
      )
      if store_tensorized_data_in_memory:
          training_tensors = MemorizedDataIterable(
              training_tensors, shuffle=True
          )
          validation_tensors = MemorizedDataIterable(validation_tensors)
  
      if device is None:
          device = torch.device(
              "cuda:0" if torch.cuda.is_available() else "cpu"
          )
      self.LOGGER.info("Using `%s` for training." % device)
      self.neural_module.to(device)
  
      optimizer = self._create_optimizer(
          self.neural_module.parameters()
      )
      scheduler = (
          None
          if self._create_scheduler is None
          else self._create_scheduler(optimizer)
      )
  
      for hook in self._training_start_hooks:
          hook(self.__model, self.neural_module, optimizer)
  
      if (
          self._target_metric_higher_is_better
          and self._target_metric is not None
      ):
          best_target_metric = -math.inf
      else:
          best_target_metric = math.inf
  
      if validate_on_start:
          target_metric, improved, _ = self._run_validation(
              validation_tensors,
              start_epoch_idx,
              best_target_metric,
              device,
              parallelize,
              show_progress_bar,
          )
          assert improved
          self.LOGGER.info(
              f"Initial {self._target_metric or 'Loss'}: {target_metric}"
          )
          best_target_metric = target_metric
  
      num_epochs_not_improved: int = 0
      for epoch in range(start_epoch_idx, self._max_num_epochs):
          self._run_training(
              training_tensors,
              epoch,
              device,
              exponential_running_average_factor,
              optimizer,
              parallelize,
              scheduler,
              show_progress_bar,
              shuffle_training_data,
          )
  
          # Save optimizer and epoch id for scheduler
          torch.save(
              {
                  "optimizer_state_dict": optimizer.state_dict(),
                  "epoch": epoch + 1,
              },
              self._checkpoint_location.with_suffix(".optimizerstate"),
          )
  
          (
              target_metric,
              target_metric_improved,
              validation_metrics,
          ) = self._run_validation(
              validation_tensors,
              epoch,
              best_target_metric,
              device,
              parallelize,
              show_progress_bar,
          )
          if target_metric_improved:
              self.LOGGER.info(
                  f"Best performance so far "
                  f"({self._target_metric or 'Loss'}: {target_metric:.3f} from {best_target_metric:.3f}). "
                  "Saving model checkpoint."
              )
              num_epochs_not_improved = 0
              self._save_checkpoint()
              best_target_metric = target_metric
  
              if target_metric_improved:
                  for epoch_hook in self._improved_epoch_end_hooks:
                      epoch_hook(
                          self.__model,
                          self.neural_module,
                          epoch,
                          validation_metrics,
                      )
          else:
              num_epochs_not_improved += 1
              if num_epochs_not_improved > patience:
                  self.LOGGER.warning(
                      f"The target metric has not improved for {num_epochs_not_improved} epochs . Stopping."
                  )
                  break
  
      # Restore the best model params that were found.
      self._restore_checkpoint(device=device)
  
imports: from typing_extensions import Final, Protocol
  import json
  import logging
  import math
  import time
  import torch
  from pathlib import Path
  from tqdm import tqdm
  from typing import Callable, Dict, Generic, Iterable, List, Optional, TypeVar
  from ptgnn.baseneuralmodel.abstractneuralmodel import AbstractNeuralModel
  from ptgnn.baseneuralmodel.modulewithmetrics import ModuleWithMetrics
  from ptgnn.baseneuralmodel.utils.data import MemorizedDataIterable
  from ptgnn.baseneuralmodel.utils.oom import catch_cuda_oom
label_desc: Use image node_id 16 for calling the ModelTrainer obj's underlying member method code with example usage: obj.train(training_data, validation_data) without return types