Unverified 提交 43569d53 authored 作者: Anton Lebedev's avatar Anton Lebedev 提交者: GitHub

Bug fix mAP0.5-0.95 (#6787)

* Improve mAP0.5-0.95 Two changes provided 1. Added limit on the maximum number of detections for each image likewise pycocotools 2. Rework process_batch function Changes #2 solved issue #4251 I also independently encountered the problem described in issue #4251 that the values for the same thresholds do not match when changing the limits in the torch.linspace function. These changes solve this problem. Currently during validation yolov5x.pt model the following results were obtained: from yolov5 validation Class Images Labels P R mAP@.5 mAP@.5:.95: 100%|██████████| 157/157 [01:07<00:00, 2.33it/s] all 5000 36335 0.743 0.626 0.682 0.506 from pycocotools Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.505 Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.685 These results are very close, although not completely pass the competition issue #2258. I think it's problem with false positive bboxes matched ignored criteria, but this is not actual for custom datasets and does not require an additional solution. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Remove line to retain pycocotools results * Update val.py * Update val.py * Remove to device op * Higher precision int conversion * Update val.py Co-authored-by: 's avatarGlenn Jocher <glenn.jocher@ultralytics.com> Co-authored-by: 's avatarpre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
上级 f43cd53d
...@@ -90,7 +90,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names ...@@ -90,7 +90,7 @@ def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='.', names
p, r, f1 = p[:, i], r[:, i], f1[:, i] p, r, f1 = p[:, i], r[:, i], f1[:, i]
tp = (r * nt).round() # true positives tp = (r * nt).round() # true positives
fp = (tp / (p + eps) - tp).round() # false positives fp = (tp / (p + eps) - tp).round() # false positives
return tp, fp, p, r, f1, ap, unique_classes.astype('int32') return tp, fp, p, r, f1, ap, unique_classes.astype(int)
def compute_ap(recall, precision): def compute_ap(recall, precision):
...@@ -156,7 +156,7 @@ class ConfusionMatrix: ...@@ -156,7 +156,7 @@ class ConfusionMatrix:
matches = np.zeros((0, 3)) matches = np.zeros((0, 3))
n = matches.shape[0] > 0 n = matches.shape[0] > 0
m0, m1, _ = matches.transpose().astype(np.int16) m0, m1, _ = matches.transpose().astype(int)
for i, gc in enumerate(gt_classes): for i, gc in enumerate(gt_classes):
j = m0 == i j = m0 == i
if n and sum(j) == 1: if n and sum(j) == 1:
......
...@@ -79,16 +79,17 @@ def process_batch(detections, labels, iouv): ...@@ -79,16 +79,17 @@ def process_batch(detections, labels, iouv):
""" """
correct = torch.zeros(detections.shape[0], iouv.shape[0], dtype=torch.bool, device=iouv.device) correct = torch.zeros(detections.shape[0], iouv.shape[0], dtype=torch.bool, device=iouv.device)
iou = box_iou(labels[:, 1:], detections[:, :4]) iou = box_iou(labels[:, 1:], detections[:, :4])
x = torch.where((iou >= iouv[0]) & (labels[:, 0:1] == detections[:, 5])) # IoU above threshold and classes match correct_class = labels[:, 0:1] == detections[:, 5]
if x[0].shape[0]: for i in range(len(iouv)):
matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detection, iou] x = torch.where((iou >= iouv[i]) & correct_class) # IoU > threshold and classes match
if x[0].shape[0] > 1: if x[0].shape[0]:
matches = matches[matches[:, 2].argsort()[::-1]] matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy() # [label, detect, iou]
matches = matches[np.unique(matches[:, 1], return_index=True)[1]] if x[0].shape[0] > 1:
# matches = matches[matches[:, 2].argsort()[::-1]] matches = matches[matches[:, 2].argsort()[::-1]]
matches = matches[np.unique(matches[:, 0], return_index=True)[1]] matches = matches[np.unique(matches[:, 1], return_index=True)[1]]
matches = torch.from_numpy(matches).to(iouv.device) # matches = matches[matches[:, 2].argsort()[::-1]]
correct[matches[:, 1].long()] = matches[:, 2:3] >= iouv matches = matches[np.unique(matches[:, 0], return_index=True)[1]]
correct[matches[:, 1].astype(int), i] = True
return correct return correct
...@@ -265,7 +266,7 @@ def run( ...@@ -265,7 +266,7 @@ def run(
tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names) tp, fp, p, r, f1, ap, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names)
ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95 ap50, ap = ap[:, 0], ap.mean(1) # AP@0.5, AP@0.5:0.95
mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean() mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean()
nt = np.bincount(stats[3].astype(np.int64), minlength=nc) # number of targets per class nt = np.bincount(stats[3].astype(int), minlength=nc) # number of targets per class
else: else:
nt = torch.zeros(1) nt = torch.zeros(1)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论