code: def evaluate(model, data_loader, coco=None, device=None):
      cpu_device = torch.device("cpu")
      model.eval()
      metric_logger = utils.MetricLogger(delimiter="  ")
      header = "Test: "
  
      if coco is None:
          coco = get_coco_api_from_dataset(data_loader.dataset)
      iou_types = _get_iou_types(model)
      coco_evaluator = CocoEvaluator(coco, iou_types)
  
      for (
          imgs,
          targets,
          paths,
          shapes,
          img_index,
      ) in metric_logger.log_every(data_loader, 100, header):
          imgs = (
              imgs.to(device).float() / 255.0
          )  # uint8 to float32, 0 - 255 to 0.0 - 1.0
          # targets = targets.to(device)
  
          # 当使用CPU时，跳过GPU相关指令
          if device != torch.device("cpu"):
              torch.cuda.synchronize(device)
  
          model_time = time.time()
          pred = model(imgs)[0]  # only get inference result
          pred = non_max_suppression(
              pred, conf_thres=0.01, iou_thres=0.6, multi_label=False
          )
          model_time = time.time() - model_time
  
          outputs = []
          for index, p in enumerate(pred):
              if p is None:
                  p = torch.empty((0, 6), device=cpu_device)
                  boxes = torch.empty((0, 4), device=cpu_device)
              else:
                  # xmin, ymin, xmax, ymax
                  boxes = p[:, :4]
                  # shapes: (h0, w0), ((h / h0, w / w0), pad)
                  # 将boxes信息还原回原图尺度，这样计算的mAP才是准确的
                  boxes = scale_coords(
                      imgs[index].shape[1:], boxes, shapes[index][0]
                  ).round()
  
              # 注意这里传入的boxes格式必须是xmin, ymin, xmax, ymax，且为绝对坐标
              info = {
                  "boxes": boxes.to(cpu_device),
                  "labels": p[:, 5].to(
                      device=cpu_device, dtype=torch.int64
                  ),
                  "scores": p[:, 4].to(cpu_device),
              }
              outputs.append(info)
  
          res = {
              img_id: output
              for img_id, output in zip(img_index, outputs)
          }
  
          evaluator_time = time.time()
          coco_evaluator.update(res)
          evaluator_time = time.time() - evaluator_time
          metric_logger.update(
              model_time=model_time, evaluator_time=evaluator_time
          )
  
      # gather the stats from all processes
      metric_logger.synchronize_between_processes()
      print("Averaged stats:", metric_logger)
      coco_evaluator.synchronize_between_processes()
  
      # accumulate predictions from all images
      coco_evaluator.accumulate()
      coco_evaluator.summarize()
  
      result_info = coco_evaluator.coco_eval[
          iou_types[0]
      ].stats.tolist()  # numpy to list
  
      return result_info
  
file_path: deep-learning-for-image-processing/pytorch_object_detection/yolov3_spp/train_utils/train_eval_utils.py
imports: import sys
  from torch.cuda import amp
  import torch.nn.functional
  from build_utils.utils import *
  from .coco_eval import CocoEvaluator
  from .coco_utils import get_coco_api_from_dataset
  import train_utils.distributed_utils
label_desc: Use image node_id 2 for calling a global function with example usage: evaluate(model, data_loader, coco, device) and returns: result_info