YoungXIAO13 / FewShotDetection

(ECCV 2020) PyTorch implementation of paper "Few-Shot Object Detection and Viewpoint Estimation for Objects in the Wild"
http://imagine.enpc.fr/~xiaoy/FSDetView/
MIT License
210 stars 33 forks source link

Wrong category indexing in coco evaluation (might be the cause for AP(novel)>AP(base)) #35

Open Jonas-Meier opened 3 years ago

Jonas-Meier commented 3 years ago

I probably found an issue with the indexing of categories at coco evaluation. This might cause interchanged results for each category which would also affect AP(novel) and AP(base) since it is unknown which result belongs to which category #30 . The overall mAP is unaffected by this issue.

At inference, the test-class puts the detections inside the variable all_boxes where the classes are indexed by their position in imdb.classes (which is Background-Class + Base-Classes + Novel-Classes, as defined in the constructor of coco.py).

As coco.py does the evaluation, the following happens:

Now we have two problematic situations inside _print_detection_eval_metrics() method of coco.py:

To solve the stated problems, I would suggest the following changes (for _print_detection_eval_metrics, line 245-259)

cat_ids = self._COCO.getCatIds()
cats = self._COCO.loadCats(cat_ids)
cat_name_to_ind = dict(list(zip([c['name'] for c in cats], range(len(cats)))))
for cls_ind, cls in enumerate(cat_name_to_ind.keys()):
    # no check for cls == '__background__' needed due to new list we're iterating over
    precision = coco_eval.eval['precision'][ind_lo:(ind_hi + 1), :, cls_ind, 0, 2]  # no index shift necessary
    ap = np.mean(precision[precision > -1])
    print('{}: {:.1f}'.format(cls, 100 * ap))

print('~~~~ Summary Base metrics ~~~~')
categoryId = list(map(lambda cls: cat_name_to_ind[cls], self._base_classes))  # use correct indices now
coco_eval.summarize(categoryId)

print('~~~~ Summary Novel metrics ~~~~')
categoryId = list(map(lambda cls: cat_name_to_ind[cls], self._novel_classes))  # use correct indices now
coco_eval.summarize(categoryId)

self._base_classes and self._novel_classes are the lists of base and novel class names which I used to create self._classes in the constructor.

Some final thoughts on the issue:

YoungXIAO13 commented 3 years ago

Hi @Jonas-Meier

Thanks for spotting it and sorry for being not very responsive at this moment. This might be an actual issue, I will look further into it. My guess is that a new training strategy needs to be found if this is actually the case.

And potentially I will update the code with newer few-shot object detection code built upon detectron such like frustratingly simple ICML-2020 or contrastive CVPR-2021.