敞开成长之旅!这是我参与「日新计划 12 月更文挑战」的第1天,点击检查活动概况

目标检测攻坚|一文总结mAP计算方法

看方针检测方面的论文时,都把mAP(mean Average Precision) 当作最终的比较不同模型性能的方针。

平常要用的时分,就调用个开源代码,然后屁颠屁颠地给老板看结果,没想到这次要自己写,找了好几份资料和代码,才把这个概念看懂了大概,看来想在这行有长进,仍是得踏踏实实下苦功。

为了了解mAP的意义,先列出这几个方针检测的基本方针:

– TP:IoU>IoU_Threshold的真值检测框数量。

– FP:IoU≤IoU_Threshold的检测框数量,或者是检测到同一个真值框的多余检测框的数量。

– FN:没有检测到的真值框的数量。

– Precision(精确率):TP/(TP+FP)

– Recall(召回率):TP/(TP+FN)

– F1-Score:2(presicionrecall)/(presicion+recall) 用于衡量precision和recall间的巨细关系

信任了解方针检测的同学们都已经对Presicion和Recall滚瓜烂熟了:

Precision便是想确保没有错检,Recall便是为了确保没有漏检,若提高阈值,错检的个数会削减,但一起漏检的个数会增多,这两个方针不会一起增高,会相互直接拉扯。F1-Score则是为了衡量Recall和Precision间的平衡而提出的方针。

目标检测攻坚|一文总结mAP计算方法

已经有Precision、Recall、F1 score了,为什么还需要mAP呢?

  1. 方针检测任务里常常为多分类问题,上述的方针并不能反映多分类的性能
  2. IoU_threshold和置信度都会影响Precision和 recall的值

我们常常还会在论文里看到mAP@后边带着一个小数,能够分开三部分来看。

  1. “average precision”(AP)指的是PR曲线下的面积

  2. “mean”指的是所有类别的AP平均值

  3. @后边的小数指的是不同iou阈值,即IoU_Threshold,用于衡量定位精度

怎么得出PR曲线呢?

一种常见的方法,便是将置信度分数按从大到小排列,取第一个框,核算第一对recall和precision值,再取前两个框,核算recall和precision,再取前三个框…以此类推,直到所有的检测框都核算完。

关于核算PR曲线下的面积,VOC给出了两种不一样的方法:
  1. voc2007里,对于每个点,取其右边的极大Precision值;每隔0.1个recall取11个点,最终算11个点的precision的平均值作为AP。

目标检测攻坚|一文总结mAP计算方法

(图片来自网络)

  1. voc2012里是直接核算PR曲线围成的面积巨细。

目标检测攻坚|一文总结mAP计算方法

(图片来自网络)

代码核算过程

Step1: 将检测框按置信度从高到低排列,设定IoU_Threshold,核算Recall-Precision曲线
def calc_detection_mAP(all_gt_dict, all_pred_dict,iou_threshold=0.8,use_07_metric=True):
    mAP_dict = {}
    for class_name  in all_gt_dict.keys():
        gt_boxes_list = all_gt_dict[class_name]
        pred_boxes_list = all_pred_dict[class_name]
        npos = len(gt_boxes_list)
        if npos == 0:
            continue
        pred_boxes_list = sorted(pred_boxes_list, key=lambda x: x[4], reverse=True)
        tp = np.zeros(len(pred_boxes_list))
        fp = np.zeros(len(pred_boxes_list))
        for idx, pred_box in enumerate(pred_boxes_list):
            pred_box_restored = list(map(int, pred_box[:4]))
            max_overlap = -1
            for gt_box in gt_boxes_list:
                overlap = iou(pred_box_restored, gt_box)
                if overlap > max_overlap:
                    max_overlap = overlap
            if max_overlap >= iou_threshold:
                tp[idx] = 1
            else:
                fp[idx] = 1
        fp = np.cumsum(fp)
        tp = np.cumsum(tp)
        rec = tp / float(npos)
        prec = tp / np.maximum(tp+fp, np.finfo(np.float64).eps)
        ap = get_ap(rec, prec, use_07_metric)
        mAP_dict[class_name] = ap
     return mAP_dict  
Step2:核算AP的两种不同方法
def get_ap(rec, prec, use_07_metric=False):
    if use_07_metric:
        ap = 0
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                p = np.max(prec[rec >=t])
            ap += p/11
    else:
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))
        for i in range(mpre.size - 1, 0, -1):
            mpre[i-1] = np.maximum(mpre[i-1], mpre[i])
        i = np.where(mrec[1:] != mrec[:-1])[0]
        ap = np.sum((mrec[i+1]-mrec[i]) * mpre[i+1])
    return ap
Step3:核算mAP
def calc_mAP(all_gt_dict, all_pred_dict, iou_threshold=0.5, use_07_metric=True):
    mAP_dict = calc_detection_mAP(all_gt_dict, all_pred_dict, iou_threshold, use_07_metric)
    mAP_list = list(mAP_dict.values())
    mAP = np.mean(mAP_list)
    return mAP

写在后边

这些根底的方针核算说难不难,说容易,又会写错细节。搞算法,花里胡哨的神经网络层出不穷,但更重要的是牢牢掌握根底知识,思路清晰的思考才能够更快速高效地解决问题。