Skip to content

Commit 541222d

Browse files
authored
[Enhance] Accelerate analyze result (#7891)
* analyze_time * accelerate * update * fix bug * update * unmerge * update comments * add unit test
1 parent ad5776c commit 541222d

File tree

3 files changed

+92
-27
lines changed

3 files changed

+92
-27
lines changed

mmdet/core/evaluation/mean_ap.py

+49-20
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def tpfp_imagenet(det_bboxes,
6262
gt_bboxes_ignore=None,
6363
default_iou_thr=0.5,
6464
area_ranges=None,
65-
use_legacy_coordinate=False):
65+
use_legacy_coordinate=False,
66+
**kwargs):
6667
"""Check if detected bboxes are true positive or false positive.
6768
6869
Args:
@@ -170,7 +171,8 @@ def tpfp_default(det_bboxes,
170171
gt_bboxes_ignore=None,
171172
iou_thr=0.5,
172173
area_ranges=None,
173-
use_legacy_coordinate=False):
174+
use_legacy_coordinate=False,
175+
**kwargs):
174176
"""Check if detected bboxes are true positive or false positive.
175177
176178
Args:
@@ -275,7 +277,8 @@ def tpfp_openimages(det_bboxes,
275277
use_legacy_coordinate=False,
276278
gt_bboxes_group_of=None,
277279
use_group_of=True,
278-
ioa_thr=0.5):
280+
ioa_thr=0.5,
281+
**kwargs):
279282
"""Check if detected bboxes are true positive or false positive.
280283
281284
Args:
@@ -585,7 +588,13 @@ def eval_map(det_results,
585588
area_ranges = ([(rg[0]**2, rg[1]**2) for rg in scale_ranges]
586589
if scale_ranges is not None else None)
587590

588-
pool = Pool(nproc)
591+
# There is no need to use multi processes to process
592+
# when num_imgs = 1 .
593+
if num_imgs > 1:
594+
assert nproc > 0, 'nproc must be at least one.'
595+
nproc = min(nproc, num_imgs)
596+
pool = Pool(nproc)
597+
589598
eval_results = []
590599
for i in range(num_classes):
591600
# get gt and det bboxes of this class
@@ -603,21 +612,38 @@ def eval_map(det_results,
603612
if not callable(tpfp_fn):
604613
raise ValueError(
605614
f'tpfp_fn has to be a function or None, but got {tpfp_fn}')
606-
args = []
607-
if use_group_of:
608-
# used in Open Images Dataset evaluation
609-
gt_group_ofs = get_cls_group_ofs(annotations, i)
610-
args.append(gt_group_ofs)
611-
args.append([use_group_of for _ in range(num_imgs)])
612-
if ioa_thr is not None:
613-
args.append([ioa_thr for _ in range(num_imgs)])
614-
# compute tp and fp for each image with multiple processes
615-
tpfp = pool.starmap(
616-
tpfp_fn,
617-
zip(cls_dets, cls_gts, cls_gts_ignore,
618-
[iou_thr for _ in range(num_imgs)],
619-
[area_ranges for _ in range(num_imgs)],
620-
[use_legacy_coordinate for _ in range(num_imgs)], *args))
615+
616+
if num_imgs > 1:
617+
# compute tp and fp for each image with multiple processes
618+
args = []
619+
if use_group_of:
620+
# used in Open Images Dataset evaluation
621+
gt_group_ofs = get_cls_group_ofs(annotations, i)
622+
args.append(gt_group_ofs)
623+
args.append([use_group_of for _ in range(num_imgs)])
624+
if ioa_thr is not None:
625+
args.append([ioa_thr for _ in range(num_imgs)])
626+
627+
tpfp = pool.starmap(
628+
tpfp_fn,
629+
zip(cls_dets, cls_gts, cls_gts_ignore,
630+
[iou_thr for _ in range(num_imgs)],
631+
[area_ranges for _ in range(num_imgs)],
632+
[use_legacy_coordinate for _ in range(num_imgs)], *args))
633+
else:
634+
tpfp = tpfp_fn(
635+
cls_dets[0],
636+
cls_gts[0],
637+
cls_gts_ignore[0],
638+
iou_thr,
639+
area_ranges,
640+
use_legacy_coordinate,
641+
gt_bboxes_group_of=(get_cls_group_ofs(annotations, i)[0]
642+
if use_group_of else None),
643+
use_group_of=use_group_of,
644+
ioa_thr=ioa_thr)
645+
tpfp = [tpfp]
646+
621647
if use_group_of:
622648
tp, fp, cls_dets = tuple(zip(*tpfp))
623649
else:
@@ -660,7 +686,10 @@ def eval_map(det_results,
660686
'precision': precisions,
661687
'ap': ap
662688
})
663-
pool.close()
689+
690+
if num_imgs > 1:
691+
pool.close()
692+
664693
if scale_ranges is not None:
665694
# shape (num_classes, num_scales)
666695
all_ap = np.vstack([cls_result['ap'] for cls_result in eval_results])

tests/test_metrics/test_mean_ap.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,27 @@ def test_eval_map():
8484
mean_ap, eval_results = eval_map(
8585
det_results, annotations, use_legacy_coordinate=True)
8686
assert 0.291 < mean_ap < 0.293
87-
eval_map(det_results, annotations, use_legacy_coordinate=False)
87+
mean_ap, eval_results = eval_map(
88+
det_results, annotations, use_legacy_coordinate=False)
89+
assert 0.291 < mean_ap < 0.293
90+
91+
# 1 image and 2 classes
92+
det_results = [[det_bboxes, det_bboxes]]
93+
94+
labels = np.array([0, 1, 1])
95+
labels_ignore = np.array([0, 1])
96+
gt_info = {
97+
'bboxes': gt_bboxes,
98+
'bboxes_ignore': gt_ignore,
99+
'labels': labels,
100+
'labels_ignore': labels_ignore
101+
}
102+
annotations = [gt_info]
103+
mean_ap, eval_results = eval_map(
104+
det_results, annotations, use_legacy_coordinate=True)
105+
assert 0.291 < mean_ap < 0.293
106+
mean_ap, eval_results = eval_map(
107+
det_results, annotations, use_legacy_coordinate=False)
88108
assert 0.291 < mean_ap < 0.293
89109

90110

tools/analysis_tools/analyze_results.py

+22-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) OpenMMLab. All rights reserved.
22
import argparse
33
import os.path as osp
4+
from multiprocessing import Pool
45

56
import mmcv
67
import numpy as np
@@ -12,7 +13,7 @@
1213
from mmdet.utils import replace_cfg_vals, update_data_root
1314

1415

15-
def bbox_map_eval(det_result, annotation):
16+
def bbox_map_eval(det_result, annotation, nproc=4):
1617
"""Evaluate mAP of single image det result.
1718
1819
Args:
@@ -27,6 +28,9 @@ def bbox_map_eval(det_result, annotation):
2728
- bboxes_ignore (optional): numpy array of shape (k, 4)
2829
- labels_ignore (optional): numpy array of shape (k, )
2930
31+
nproc (int): Processes used for computing mAP.
32+
Default: 4.
33+
3034
Returns:
3135
float: mAP
3236
"""
@@ -39,11 +43,24 @@ def bbox_map_eval(det_result, annotation):
3943
# mAP
4044
iou_thrs = np.linspace(
4145
.5, 0.95, int(np.round((0.95 - .5) / .05)) + 1, endpoint=True)
42-
mean_aps = []
46+
47+
processes = []
48+
workers = Pool(processes=nproc)
4349
for thr in iou_thrs:
44-
mean_ap, _ = eval_map(
45-
bbox_det_result, [annotation], iou_thr=thr, logger='silent')
46-
mean_aps.append(mean_ap)
50+
p = workers.apply_async(eval_map, (bbox_det_result, [annotation]), {
51+
'iou_thr': thr,
52+
'logger': 'silent',
53+
'nproc': 1
54+
})
55+
processes.append(p)
56+
57+
workers.close()
58+
workers.join()
59+
60+
mean_aps = []
61+
for p in processes:
62+
mean_aps.append(p.get()[0])
63+
4764
return sum(mean_aps) / len(mean_aps)
4865

4966

@@ -130,7 +147,6 @@ def evaluate_and_show(self,
130147
mAP = eval_fn(result, data_info['ann_info'])
131148
_mAPs[i] = mAP
132149
prog_bar.update()
133-
134150
# descending select topk image
135151
_mAPs = list(sorted(_mAPs.items(), key=lambda kv: kv[1]))
136152
good_mAPs = _mAPs[-topk:]

0 commit comments

Comments
 (0)