class_docstr: This class defines the training and validation code for training models with CVNets
code: def __init__(
      self,
      opts,
      model,
      validation_loader,
      training_loader,
      criterion,
      optimizer,
      scheduler,
      gradient_scaler,
      start_epoch: int = 0,
      start_iteration: int = 0,
      best_metric: float = 0.0,
      model_ema=None,
      *args,
      **kwargs,
  ) -> None:
      super(Trainer, self).__init__()
  
      self.opts = opts
  
      self.model = model
      self.model_ema = model_ema
      self.criteria = criterion
      self.optimizer = optimizer
      self.scheduler = scheduler
      self.gradient_scaler = gradient_scaler
  
      self.val_loader = validation_loader
      self.train_loader = training_loader
  
      self.device = getattr(opts, "dev.device", torch.device("cpu"))
  
      self.start_epoch = start_epoch
      self.best_metric = best_metric
      self.train_iterations = start_iteration
  
      self.is_master_node = is_master(opts)
      self.max_iterations_reached = False
      self.max_iterations = getattr(
          self.opts, "scheduler.max_iterations", DEFAULT_ITERATIONS
      )
      self.use_distributed = getattr(
          self.opts, "ddp.use_distributed", False
      )
      self.log_freq = getattr(
          self.opts, "common.log_freq", DEFAULT_LOG_FREQ
      )
      self.accum_freq = getattr(self.opts, "common.accum_freq", 1)
      self.accum_after_epoch = getattr(
          self.opts, "common.accum_after_epoch", 0
      )
  
      self.mixed_precision_training = getattr(
          opts, "common.mixed_precision", False
      )
      self.mixed_precision_dtype = getattr(
          opts, "common.mixed_precision_dtype", "float16"
      )
  
      self.train_metric_names = getattr(opts, "stats.train", ["loss"])
      if isinstance(self.train_metric_names, str):
          self.train_metric_names = [self.train_metric_names]
  
      assert isinstance(
          self.train_metric_names, list
      ), "Type of metric names should be list. Got: {}".format(
          type(self.train_metric_names)
      )
  
      if "loss" not in self.train_metric_names:
          self.train_metric_names.append(self.train_metric_names)
  
      (
          self.val_metric_names,
          self.ckpt_metric,
          self.ckpt_submetric,
      ) = parse_validation_metric_names(self.opts)
  
      self.save_all_checkpoints = getattr(
          self.opts, "common.save_all_checkpoints", False
      )
  
      self.save_location = getattr(
          opts, "common.exp_loc", "results/run_1"
      )
  
      self.log_writers = get_log_writers(
          self.opts, save_location=self.save_location
      )
  
      self.adjust_norm_mom = None
      if getattr(
          opts, "model.normalization.adjust_bn_momentum.enable", False
      ):
          from cvnets.layers import AdjustBatchNormMomentum
  
          self.adjust_norm_mom = AdjustBatchNormMomentum(opts=opts)
          if self.is_master_node:
              logger.log(
                  "Batch normalization momentum will be annealed during training."
              )
              print(self.adjust_norm_mom)
  
      # sample-efficient training
      self.cache_dict = None
      self.sample_efficient_training = getattr(
          opts, "dataset.sample_efficient_training.enable", False
      )
      self.sample_confidence = getattr(
          opts,
          "dataset.sample_efficient_training.sample_confidence",
          0.5,
      )
      self.find_easy_samples_every_k_epoch = getattr(
          opts,
          "dataset.sample_efficient_training.find_easy_samples_every_k_epochs",
          5,
      )
      self.min_sample_frequency = getattr(
          opts,
          "dataset.sample_efficient_training.min_sample_frequency",
          5,
      )
      if self.sample_efficient_training:
          self.train_loader_set = copy.deepcopy(self.train_loader)
          self.sample_ids_orig = (
              self.train_loader_set.get_sample_indices()
          )
          n_samples = len(self.sample_ids_orig)
          self.running_sum_tensor = torch.zeros(
              (n_samples,), device=self.device, dtype=torch.int
          )
          self.running_sum_tensor.requires_grad = False
          if self.is_master_node:
              logger.log("Configuring for sample efficient training")
  
      # recent versions of PyTorch support setting grads to None, for better performance
      # To be explored in Future
      # self.optimizer.zero_grad(set_to_none=True)
      self.set_grad_to_none = False
  
      save_interval_freq = getattr(opts, "common.save_interval_freq", 0)
      # save interval checkpoints every `save_interval_freq` updates on the master node
      self.save_interval = (
          self.is_master_node and save_interval_freq > 0
      )
      self.save_interval_freq = save_interval_freq
  
imports: import copy
  import gc
  import shutil
  import time
  import traceback
  from itertools import product
  from typing import Dict, Union
  import numpy
  import torch
  from torch import Tensor
  from torch.nn import functional
  from common import DEFAULT_EPOCHS, DEFAULT_ITERATIONS, DEFAULT_LOG_FREQ, if_test_env
  from data.transforms.image_torch import apply_mixing_transforms
  from engine.utils import autocast_fn, get_batch_size, get_log_writers, log_metrics
  from loss_landscape import landscape_utils
  from metrics.stats import Statistics
  from options.parse_args import parse_validation_metric_names
  from utils import logger
  from utils.checkpoint_utils import copy_weights, save_checkpoint, save_interval_checkpoint
  from utils.common_utils import move_to_device, unwrap_model_fn
  from utils.ddp_utils import dist_barrier, is_master
  from utils.tensor_utils import reduce_tensor_sum
label_desc: Use image node_id 1 to create a new Trainer object from inherited base classes: object with example: obj = Trainer(opts, model, validation_loader, training_loader, criterion, optimizer, scheduler, gradient_scaler, start_epoch, start_iteration, best_metric, model_ema)