code: def main(parser_data):
      device = torch.device(
          parser_data.device if torch.cuda.is_available() else "cpu"
      )
      print("Using {} device training.".format(device.type))
  
      # read class_indict
      label_json_path = "./data/pascal_voc_classes.json"
      assert os.path.exists(
          label_json_path
      ), "json file {} dose not exist.".format(label_json_path)
      with open(label_json_path, "r") as f:
          class_dict = json.load(f)
  
      category_index = {v: k for k, v in class_dict.items()}
  
      data_dict = parse_data_cfg(parser_data.data)
      test_path = data_dict["valid"]
  
      # 注意这里的collate_fn是自定义的，因为读取的数据包括image和targets，不能直接使用默认的方法合成batch
      batch_size = parser_data.batch_size
      nw = min(
          [os.cpu_count(), batch_size if batch_size > 1 else 0, 8]
      )  # number of workers
      print("Using %g dataloader workers" % nw)
  
      # load validation data set
      val_dataset = LoadImagesAndLabels(
          test_path,
          parser_data.img_size,
          batch_size,
          hyp=parser_data.hyp,
          rect=True,
      )  # 将每个batch的图像调整到合适大小，可减少运算量(并不是512x512标准尺寸)
  
      val_dataset_loader = torch.utils.data.DataLoader(
          val_dataset,
          batch_size=batch_size,
          shuffle=False,
          num_workers=nw,
          pin_memory=True,
          collate_fn=val_dataset.collate_fn,
      )
  
      # create model
      model = Darknet(parser_data.cfg, parser_data.img_size)
      weights_dict = torch.load(parser_data.weights, map_location="cpu")
      weights_dict = (
          weights_dict["model"]
          if "model" in weights_dict
          else weights_dict
      )
      model.load_state_dict(weights_dict)
      model.to(device)
  
      # evaluate on the test dataset
      coco = get_coco_api_from_dataset(val_dataset)
      iou_types = ["bbox"]
      coco_evaluator = CocoEvaluator(coco, iou_types)
      cpu_device = torch.device("cpu")
  
      model.eval()
      with torch.no_grad():
          for imgs, targets, paths, shapes, img_index in tqdm(
              val_dataset_loader, desc="validation..."
          ):
              imgs = (
                  imgs.to(device).float() / 255.0
              )  # uint8 to float32, 0 - 255 to 0.0 - 1.0
  
              pred = model(imgs)[0]  # only get inference result
              pred = non_max_suppression(
                  pred,
                  conf_thres=0.01,
                  iou_thres=0.6,
                  multi_label=False,
              )
  
              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)
              }
  
              coco_evaluator.update(res)
  
      coco_evaluator.synchronize_between_processes()
  
      # accumulate predictions from all images
      coco_evaluator.accumulate()
      coco_evaluator.summarize()
  
      coco_eval = coco_evaluator.coco_eval["bbox"]
      # calculate COCO info for all classes
      coco_stats, print_coco = summarize(coco_eval)
  
      # calculate voc info for every classes(IoU=0.5)
      voc_map_info_list = []
      for i in range(len(category_index)):
          stats, _ = summarize(coco_eval, catId=i)
          voc_map_info_list.append(
              " {:15}: {}".format(category_index[i + 1], stats[1])
          )
  
      print_voc = "\n".join(voc_map_info_list)
      print(print_voc)
  
      # 将验证结果保存至txt文件中
      with open("record_mAP.txt", "w") as f:
          record_lines = [
              "COCO results:",
              print_coco,
              "",
              "mAP(IoU=0.5) for each category:",
              print_voc,
          ]
          f.write("\n".join(record_lines))
  
imports: import json
  from models import *
  from build_utils.datasets import *
  from build_utils.utils import *
  from train_utils import get_coco_api_from_dataset, CocoEvaluator
label_desc: Use image node_id 2 for calling a global function with example usage: main(parser_data) without return types