class_docstr: Abstract class for custom training or validation loops.
  
  The scheduler will only be called at a batch or epoch frequency, depending
  on the user parameter. Be sure to set ``scheduler_step_freq`` in
  ``TorchTrainer`` to either "batch" or "epoch" to increment the scheduler
  correctly during training. If using a learning rate scheduler
  that depends on validation loss, you can use ``trainer.update_scheduler``.
  
  For both training and validation, there are two granularities that
  you can provide customization: per epoch or per batch.
  You do not need to override both.
  
  .. image:: raysgd-custom.jpg
      :scale: 80%
      :align: center
  
  Raises:
      ValueError if multiple models/optimizers/schedulers are provided.
          You are expected to subclass this class if you wish
          to train over multiple models/optimizers/schedulers.
docstr: Runs one standard validation pass over the val_iterator.
  
  This will call ``model.eval()`` and ``torch.no_grad`` when iterating
  over the validation dataloader.
  
  If overriding this method, you can access model, criterion via
  ``self.model`` and ``self.criterion``. You also do not need to call
  ``validate_batch`` if overriding this method.
  
  Args:
      val_iterator (iter): Iterable constructed from the
          validation dataloader.
      info: (dict): Dictionary for information to be used for custom
          validation operations.
  
  Returns:
      A dict of metrics from the evaluation.
          By default, returns "val_accuracy" and "val_loss"
          which is computed by aggregating "loss" and "correct" values
          from ``validate_batch`` and dividing it by the sum of
          ``num_samples`` from all calls to ``self.validate_batch``.
docstr_tok: ["Runs","one","standard","validation","pass","over","the","val_iterator",".","This","will","call","``","model.eval","(",")","``","and","``","torch.no_grad","``","when","iterating","over","the","validation","dataloader",".","If","overriding","this","method",",","you","can","access","model",",","criterion","via","``","self.model","``","and","``","self.criterion","``",".","You","also","do","not","need","to","call","``","validate_batch","``","if","overriding","this","method",".","Args",":","val_iterator","(","iter",")",":","Iterable","constructed","from","the","validation","dataloader",".","info",":","(","dict",")",":","Dictionary","for","information","to","be","used","for","custom","validation","operations",".","Returns",":","A","dict","of","metrics","from","the","evaluation",".","By","default",",","returns","``","val_accuracy","''","and","``","val_loss","''","which","is","computed","by","aggregating","``","loss","''","and","``","correct","''","values","from","``","validate_batch","``","and","dividing","it","by","the","sum","of","``","num_samples","``","from","all","calls","to","``","self.validate_batch","``","."]
code: def validate(self, val_iterator, info, metrics):
      """Runs one standard validation pass over the val_iterator.
  
      This will call ``model.eval()`` and ``torch.no_grad`` when iterating
      over the validation dataloader.
  
      If overriding this method, you can access model, criterion via
      ``self.model`` and ``self.criterion``. You also do not need to call
      ``validate_batch`` if overriding this method.
  
      Args:
          val_iterator (iter): Iterable constructed from the
              validation dataloader.
          info: (dict): Dictionary for information to be used for custom
              validation operations.
  
      Returns:
          A dict of metrics from the evaluation.
              By default, returns "val_accuracy" and "val_loss"
              which is computed by aggregating "loss" and "correct" values
              from ``validate_batch`` and dividing it by the sum of
              ``num_samples`` from all calls to ``self.validate_batch``.
      """
      # switch to evaluate mode
      self.model.eval()
      metrics = Metric.convert_metrics_dict(metrics, backend="pytorch")
      losses = []
      total_samples = 0
      with torch.no_grad():
          for batch_idx, batch in enumerate(val_iterator):
              batch_info = {"batch_idx": batch_idx}
              batch_info.update(info)
              output, target, loss = self.forward_batch(
                  batch, batch_info
              )
              num_samples = target.size(0)
              total_samples += num_samples
              losses.append(loss.item() * num_samples)
              for metric in metrics.values():
                  metric(output, target)
  
      result = {
          name: metric.compute() for name, metric in metrics.items()
      }
  
      result["val_loss"] = sum(losses) / total_samples
  
      result["num_samples"] = total_samples
  
      return result
  
imports: import collections
  import torch
  import numpy
  from zoo.orca.learn.metrics import Metric
  from zoo.orca.learn.pytorch.utils import TimerCollection, AverageMeterCollection, NUM_SAMPLES
  from zoo.orca.learn.pytorch.constants import SCHEDULER_STEP_EPOCH, NUM_STEPS, SCHEDULER_STEP_BATCH, SCHEDULER_STEP
  from torch.nn.parallel import DistributedDataParallel
label_desc: Use image node_id 7 for calling the TrainingOperator obj's underlying member method code with example usage: obj.validate(val_iterator, info, metrics) and returns: result