zoukankan      html  css  js  c++  java
  • 目标检测中的AP计算

    转载自:https://blog.csdn.net/lppfwl/article/details/108018950

    目标检测中的AP计算

    最近在学习目标检测,对模型评价指标AP的计算过程有点疑问,经过查找资料、问师兄,最终算是有了一个相对明确的了解,特此记录一下,方便以后查看,不足之处还请大家批评指正!
    AP(average precision)是目标检测论文中广泛使用的模型评价指标,VOC的AP计算方法在2010年的时候发生过一次更改,现在常用的是2010年之后更改的AP计算方法,该计算方法相比于之前也更为合理,本文的AP计算也是2010年之后的计算方法。官方的定义如下:
    ()在这里插入图片描述
    (图片源自博客https://blog.csdn.net/hsqyc/article/details/81702437

    AP计算涉及到一些其他的知识,如TP,FP,TN,FN,precision,recall,IOU等等,下面进行简单介绍:

    TP,FP,TN,FN,precision,recall

    TP:真正例 true positive
    FP:假正例 false positive
    TN:真负例 true negative
    FN:假负例 false negative
    precision:准确率
    recall:召回率
    这几个名词的介绍我觉得这篇博客(https://blog.csdn.net/qq_41994006/article/details/81051150)里的一张图说的很清晰,这里直接摘下来了(略懒。。。)
    在这里插入图片描述

    IOU

    IOU(交并比)就是两个bounding box的交集与并集之比,这里再摘一张图。。。(源自博客https://blog.csdn.net/hsqyc/article/details/81702437

    在这里插入图片描述
    具体实现的python代码如下:

    def box_iou(b1,b2):
        '''b1,b2均为[x1,y1,x2,y2]'''
        x1_1,y1_1,x2_1,y2_1=b1
        x1_2,y1_2,x2_2,y2_2=b2
        
        x1=max(x1_1,x1_2)
        y1=max(y1_1,y1_2)
        x2=min(x2_1,x2_2)
        y2=min(y2_1,y2_2)
        
        if x2-x1+1<=0 or y2-y1+1<=0:
            return 0
        else:
            inter=(x2-x1+1)*( y2-y1+1)
            union=(x2_1-x1_1+1)*(y2_1-y1_1+1)+(x2_2-x1_2+1)*(y2_2-y1_2+1)-inter
            iou=inter/union
            return iou

    AP计算

    说完上面这些,终于可以开始讲正题了。这里写个小插曲,对于模型评价指标,听师兄讲解就是,VOC里面是叫AP,而COCO数据集里叫mAP,主要是因为COCO数据集里mAP计算是针对10个IOU阈值下的AP值取平均(这是个IOU阈值好像是np.linspace(0.5,0.95,10),有点忘了,如果错了请批评指出)

    计算AP首先需要绘制P-R曲线,也就是准确率-召回率曲线,至于怎么画,下面以一个例子来说明:
    模型的evaluation过程就是:网络模型输出—>NMS—>AP计算
    这里以测试集为一张图片为例,假设共有(1,2,3)三种目标类别,经过NMS后该图片中保留的bounding boxes及其对应的confidence score、prediction label如下表:
    在这里插入图片描述
    至于上述的bounding boxes是TP还是FP就需要计算其与ground truth的IOU值是否大于iou_thres来判断,iou_thes的取值不同即为不同的AP类型,如iou_thres=0.5对应AP50,iou_thres=0.75对应AP75等等。
    IOU的计算前面已经介绍过了,判断bounding boxes是TP还是FP的过程如下:
    对于每个预测的bounding box,如上表id=1的box,其pred_label为1,则计算其与该图片中所有类别为1的ground truth box的IOU值,取其中最大IOU值iou_max对应的ground truth box作为该预测box对应的ground truth box,如果iou_max>iou_thres,则该预测box即为TP,否则为FP。
    上表中的各预测box的tp_label如下表所示(已按conf_score排序),TP为1,FP为0:
    在这里插入图片描述

    对每个类别需要单独计算AP,最后所有类别取平均。
    下面以类别1为例,假设该测试集图片中共有3个类别1的标注框(ground truth boxes),显然上述预测结果并没有将全部真值召回。
    绘制P-R曲线,结果如下表:
    在这里插入图片描述
    P-R曲线如下图(准确率两端补0,召回率两端分别补0和1):
    在这里插入图片描述
    (画的略丑,手边真没啥工具,就一支笔。。。)
    AP值即为涂黑线的区域面积,计算公式:
    (1/3-0)1+(2/3-1/3)(2/3)=5/9

    下面贴上AP计算的python代码(源自https://github.com/eriklindernoren/PyTorch-YOLOv3

    def ap_per_class(tp, conf, pred_cls, target_cls):
        """ Compute the average precision, given the recall and precision curves.
        Source: https://github.com/rafaelpadilla/Object-Detection-Metrics.
        # Arguments
            tp:    ground truth label (np array),true positive为1,false positive为0
            conf:  Objectness value from 0-1 (np array).
            pred_cls: Predicted object classes (np array).
            target_cls: True object classes (np array).
        # Returns
            The average precision as computed in py-faster-rcnn.
        """
    
        # Sort by objectness
        i = np.argsort(-conf)
        tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
    
        # Find unique classes
        unique_classes = np.unique(target_cls)
    
        # Create Precision-Recall curve and compute AP for each class
        ap, p, r = [], [], []
        for c in tqdm.tqdm(unique_classes, desc="Computing AP"):
            i = pred_cls == c
            n_gt = (target_cls == c).sum()  # Number of ground truth objects
            n_p = i.sum()  # Number of predicted objects
    
            if n_p == 0 and n_gt == 0:
                continue
            elif n_p == 0 or n_gt == 0:
                ap.append(0)
                r.append(0)
                p.append(0)
            else:
                # Accumulate FPs and TPs
                fpc = (1 - tp[i]).cumsum()      #累加和列表
                tpc = (tp[i]).cumsum()
    
                # Recall
                recall_curve = tpc / (n_gt + 1e-16)
                r.append(recall_curve[-1])
    
                # Precision
                precision_curve = tpc / (tpc + fpc)
                p.append(precision_curve[-1])
    
                # AP from recall-precision curve
                ap.append(compute_ap(recall_curve, precision_curve))
    
        # Compute F1 score (harmonic mean of precision and recall)
        p, r, ap = np.array(p), np.array(r), np.array(ap)
        f1 = 2 * p * r / (p + r + 1e-16)
    
        return p, r, ap, f1, unique_classes.astype("int32")
    
    
    def compute_ap(recall, precision):
        """ Compute the average precision, given the recall and precision curves.
        Code originally from https://github.com/rbgirshick/py-faster-rcnn.
    
        # Arguments
            recall:    The recall curve (np.array).
            precision: The precision curve (np.array).
        # Returns
            The average precision as computed in py-faster-rcnn.
        """
        # correct AP calculation
        # first append sentinel values at the end
        mrec = np.concatenate(([0.0], recall, [1.0]))
        mpre = np.concatenate(([0.0], precision, [0.0]))
    
        # compute the precision envelope
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
    
        # to calculate area under PR curve, look for points
        # where X axis (recall) changes value
        i = np.where(mrec[:-1] != mrec[1:])[0]     #错位比较,前一个元素与其后一个元素比较,np.where()返回下标索引数组组成的元组
    
        # and sum (Delta recall) * prec
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
        return ap
     

    OK,终于写完了。
    以前没有写博客记笔记的习惯,以后得多记笔记!
    原创不易,花了挺多时间,转载请注明出处!

  • 相关阅读:
    量子和量子化?
    ARM内核和架构都是什么意思,内核和架构的关系是什么?(转)
    线程,进程,协程
    关于Redis的问题
    python一些语法糖用法
    Python装饰器详解
    Python基础知识
    Pyinstaller安装以及参数使用
    正则表达式(特殊字符)/Xpath语法/CSS选择器
    还在为身份验证引入的Microsoft.AspNet.Identity.EntityFramework导致多上下文,生成的DB改名困扰吗?
  • 原文地址:https://www.cnblogs.com/hanhao970620/p/13880540.html
Copyright © 2011-2022 走看看