class_docstr: Train/eval directpose
class_docstr_tok: ["Train\/eval","directpose"]
code: def validate(self, val_loader):
      if not self.evaluators:
          self.info("No evaluation data specified, skip...")
          return
      # save model before evaluation so we may recover from bugs
      self.save_model()
      is_training = self.model.training
      self.model.eval()
      for evaluator in self.evaluators:
          evaluator.reset()
  
      # inference
      num_devices = comm.get_world_size()
      total = len(val_loader)
      logger.info(f"Start evaluation on {total} images.")
      warmup_meter = min(5, total - 1)
      start_time = time.perf_counter()
      total_compute_time = 0
      with torch.no_grad():
          for idx, inputs in enumerate(val_loader):
              if idx <= warmup_meter:
                  # no timing during gpu warm up
                  start_time = time.perf_counter()
                  total_compute_time = 0
  
              start_compute_time = time.perf_counter()
              outputs = self.model(inputs)
              if torch.cuda.is_available():
                  torch.cuda.synchronize()
              total_compute_time += (
                  time.perf_counter() - start_compute_time
              )
              for evaluator in self.evaluators:
                  evaluator.process(inputs, outputs)
              iters_after_start = (
                  idx + 1 - warmup_meter * int(idx >= warmup_meter)
              )
              seconds_per_img = total_compute_time / iters_after_start
              if idx >= warmup_meter * 2 or seconds_per_img > 5:
                  total_seconds_per_img = (
                      time.perf_counter() - start_time
                  ) / iters_after_start
                  eta = datetime.timedelta(
                      seconds=int(
                          total_seconds_per_img * (total - idx - 1)
                      )
                  )
                  logger.info(
                      f"Inference done {idx + 1}/{total}. {seconds_per_img:.4f} sec/img. ETA={str(eta)}"
                  )
  
      # Measure the time only for this worker (before the synchronization barrier)
      total_time = time.perf_counter() - start_time
      total_time_str = str(datetime.timedelta(seconds=total_time))
      # NOTE this format is parsed by grep
      logger.info(
          "Total inference time: {} ({:.6f} s / img per device, on {} devices)".format(
              total_time_str,
              total_time / (total - warmup_meter),
              num_devices,
          )
      )
      total_compute_time_str = str(
          datetime.timedelta(seconds=int(total_compute_time))
      )
      logger.info(
          "Total inference pure compute time: {} ({:.6f} s / img per device, on {} devices)".format(
              total_compute_time_str,
              total_compute_time / (total - warmup_meter),
              num_devices,
          )
      )
      for evaluator in self.evaluators:
          results = evaluator.evaluate()
          if self.cfg.DDP_CONFIG.GPU_WORLD_RANK == 0:
              assert isinstance(results, dict)
              for task, res in results.items():
                  # Don't print "AP-category" metrics since they are usually not tracked.
                  important_res = [
                      (k, v) for k, v in res.items() if "-" not in k
                  ]
                  logger.info("copypaste: Task: {}".format(task))
                  logger.info(
                      "copypaste: "
                      + ",".join([k[0] for k in important_res])
                  )
                  logger.info(
                      "copypaste: "
                      + ",".join(
                          [
                              "{0:.4f}".format(k[1])
                              for k in important_res
                          ]
                      )
                  )
                  for k in important_res:
                      self.writer.add_scalar(
                          ":".join((task, k[0])), k[1], self.base_iter
                      )
  
      # resume training state if applicable
      self.model.train(is_training)
  
file_path: gluon-cv/gluoncv/torch/utils/task_utils/pose.py
imports: import time
  import logging
  import datetime
  import numpy
  import torch
  from ..None import comm
  from ..utils import AverageMeter
  from ..model_utils import save_model
  from ..optimizer import maybe_add_gradient_clipping
  from ..eval_utils.coco_eval import COCOEvaluator
label_desc: Use image node_id 3 for calling the DirectposePipeline obj's underlying member method code with example usage: obj.validate(val_loader) without return types