COCO目標(biāo)檢測(cè)測(cè)評(píng)指標(biāo)

紀(jì)念版的評(píng)分圖:

  • 在COCO數(shù)據(jù)中,默認(rèn)AP就是mAP。
  • mAP@.5IOU=AP@.5IOU, mAP@.75IOU=AP@.75IOU。以此類推
  • 在更早的數(shù)據(jù)集VOC上的mAP指標(biāo)就是COCO的AP@.5IOU。

COCO Detection Evaluation翻譯

來(lái)自百度翻譯:

1.Detection Evaluation

本頁(yè)描述了COCO使用的檢測(cè)評(píng)估指標(biāo)。這里提供的評(píng)估代碼可用于獲得公開可用的COCO驗(yàn)證集上的結(jié)果。它計(jì)算了下面描述的多個(gè)度量。為了在隱藏了基本真值注釋的COCO測(cè)試集上獲得結(jié)果,生成的結(jié)果必須上傳到評(píng)估服務(wù)器。下面描述的完全相同的評(píng)估代碼用于評(píng)估測(cè)試集上的結(jié)果。

2.Metrics

以下12個(gè)度量用于表征COCO上的目標(biāo)檢測(cè)器的性能:

  • 1)除非另有說(shuō)明,否則AP和AR在多個(gè)交匯點(diǎn)(IoU)值上取平均值。具體來(lái)說(shuō),我們使用10個(gè)IoU閾值0.50:0.05:0.95。這是對(duì)傳統(tǒng)的一個(gè)突破,其中AP是在一個(gè)單一的0.50的IoU上計(jì)算的(這對(duì)應(yīng)于我們的度量APIoU=.50 )。超過均值的IoUs能讓探測(cè)器更好定位。

  • 2)AP是所有類別的平均值。傳統(tǒng)上,這被稱為“平均準(zhǔn)確度”(mAP,mean average precision)。我們沒有區(qū)分AP和mAP(同樣是AR和mAR),并假定從上下文中可以清楚地看出差異。

  • 3)AP(所有10個(gè)IoU閾值和所有80個(gè)類別的平均值)將決定贏家。在考慮COCO性能時(shí),這應(yīng)該被認(rèn)為是最重要的一個(gè)指標(biāo)。

  • 4)在COCO中,比大物體相比有更多的小物體。具體地說(shuō),大約41%的物體很?。娣e<322),34%是中等(322 < area < 962)),24%大(area > 962)。測(cè)量的面積(area)是分割掩碼(segmentation mask)中的像素?cái)?shù)量。

  • 5)AR是在每個(gè)圖像中檢測(cè)到固定數(shù)量的最大召回(recall),在類別和IoU上平均。AR與提案評(píng)估(proposal evaluation)中使用的同名度量相關(guān),但是按類別計(jì)算。

  • 6)所有度量標(biāo)準(zhǔn)允許每個(gè)圖像(在所有類別中)最多100個(gè)最高得分檢測(cè)進(jìn)行計(jì)算。

  • 7)除了IoU計(jì)算(分別在框(box)或掩碼(mask)上執(zhí)行)之外,用邊界框和分割掩碼檢測(cè)的評(píng)估度量在所有方面是相同的。

3. Evaluation Code

評(píng)估代碼可在COCO github上找到。 具體來(lái)說(shuō),分別參見Matlab或Python代碼中的CocoEval.m或cocoeval.py。另請(qǐng)參閱Matlab或Python代碼(demo)中的evalDemo。在運(yùn)行評(píng)估代碼之前,請(qǐng)按結(jié)果格式頁(yè)面上描述的格式準(zhǔn)備結(jié)果(查看具體的結(jié)果格式MS COCO數(shù)據(jù)集比賽參與(participate)(來(lái)自官網(wǎng)))。

評(píng)估參數(shù)如下(括號(hào)中的默認(rèn)值,一般不需要改變):

運(yùn)行評(píng)估代碼通過調(diào)用evaluate和accumulate產(chǎn)生兩個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)衡量檢測(cè)質(zhì)量。這兩個(gè)結(jié)構(gòu)分別是evalImgs和eval,它們分別衡量每個(gè)圖像的質(zhì)量并聚合到整個(gè)數(shù)據(jù)集中。evalImgs結(jié)構(gòu)體具有KxA條目,每個(gè)評(píng)估設(shè)置一個(gè),而eval結(jié)構(gòu)體將這些信息組合成 precision 和 recall 數(shù)組。這兩個(gè)結(jié)構(gòu)的細(xì)節(jié)如下(另請(qǐng)參閱CocoEval.m或cocoeval.py):

最后,summary()根據(jù)eval結(jié)構(gòu)計(jì)算前面定義的12個(gè)檢測(cè)指標(biāo)。

4. Analysis Code

除了評(píng)估代碼外,我們還提供一個(gè)函數(shù)analyze()來(lái)執(zhí)行誤報(bào)的詳細(xì)分類。這受到了Derek Hoiem等人在診斷物體檢測(cè)器中的錯(cuò)誤(Diagnosing Error in Object Detectors)的啟發(fā),但在實(shí)現(xiàn)和細(xì)節(jié)方面卻有很大不同。代碼生成這樣的圖像:

這兩幅圖顯示了來(lái)自2015年檢測(cè)挑戰(zhàn)賽獲勝者Kaiming He等人的ResNet(bbox)檢測(cè)器的分析結(jié)果。左圖顯示了ResNet的人員類別錯(cuò)誤;右圖是ResNet對(duì)所有類別平均值的整體分析。每個(gè)繪圖是一系列精確召回(precision recall)曲線,其中每個(gè)PR曲線被保證嚴(yán)格地高于之前的評(píng)估設(shè)置變得更寬容。曲線如下:

1)C75:在IoU = 0.75(嚴(yán)格的IoU的AP)的PR(precision),對(duì)應(yīng)于APIoU=.75度量曲線下的面積(area under curve )。

2)C50:IoU = 0.50處的PR(PASCAL IoU處的AP),對(duì)應(yīng)于APIoU=.50度量曲線下面積。

3)Loc:在IoU =0 .10的PR(定位誤差(localization errors ignored)被忽略,但不重復(fù)檢測(cè))。 所有其余的設(shè)置使用IoU = 0.1。

4)Sim:超類別誤報(bào)(fps,supercategory false positives)被移除后的PR值。具體而言,與具有不同類標(biāo)簽但屬于同一個(gè)超類別的對(duì)象的任何匹配都不會(huì)被視為fp(或tp)。通過設(shè)置同一超類別中的所有對(duì)象與所討論的類具有相同的類標(biāo)簽并將它們的忽略標(biāo)志設(shè)置為1來(lái)計(jì)算Sim。注意,該人是單例超類別,因此其Sim結(jié)果與Loc完全相同。

5)Oth:所有類型混亂被移除后的PR值。與Sim類似,除了現(xiàn)在如果檢測(cè)與任何其他對(duì)象匹配,則不再是fp(或tp)。計(jì)算Oth的方法是將所有其他對(duì)象設(shè)置為與所討論的類具有相同的類標(biāo)簽,并將忽略標(biāo)志設(shè)置為1。

6)BG:所有背景誤報(bào)(和類混亂(class confusion))被移除后的PR。 對(duì)于單個(gè)類別,BG是一個(gè)階躍函數(shù),直到達(dá)到最大召回后才降為0(跨類別平均后曲線更平滑)。

7)FN:在所有剩余錯(cuò)誤都被刪除后(平均AP = 1)的PR。

每條曲線下面的區(qū)域顯示在圖例的括號(hào)中。在ResNet檢測(cè)器的情況下,IoU = 0.75的整體AP為0.399,完美定位將使AP增加到0.682。有趣的是,消除所有類別混亂(超范疇內(nèi)和超范疇內(nèi))只會(huì)將AP略微提升至0.713。除去背景fp會(huì)將性能提高到0.870 AP,而其余的錯(cuò)誤則缺少檢測(cè)(盡管假設(shè)更多的檢測(cè)被添加,這也會(huì)增加大量的fps)??傊琑esNet的錯(cuò)誤來(lái)自不完美的定位和背景混淆。

對(duì)于一個(gè)給定的探測(cè)器(detector),代碼總共產(chǎn)生了372個(gè)塊(plots)!共有80個(gè)類別(category),12個(gè)超類別(supercategory),1個(gè)總體結(jié)果,總共93個(gè)不同的設(shè)置,分析是在4個(gè)尺度(scale)(全部,小,中,大,所以93 * 4 = 372個(gè)塊)進(jìn)行。 文件命名為[supercategory] - [category] - [size] .pdf(對(duì)于80 * 4每個(gè)分類結(jié)果),overall- [supercategory] - [size] .pdf(對(duì)于12 * 4每個(gè)超類別結(jié)果)全部[[size] .pdf為1 * 4的整體結(jié)果。在所有圖中,通??傮w和超類別的結(jié)果是最感興趣的。

注意:analyze()可能需要很長(zhǎng)時(shí)間才能運(yùn)行,請(qǐng)耐心等待。因此,我們通常不會(huì)在評(píng)估服務(wù)器上運(yùn)行此代碼;您必須使用驗(yàn)證集在本地運(yùn)行代碼。最后,目前analyze()只是Matlab API的一部分; Python代碼即將推出。

PR 圖計(jì)算

兩個(gè)基本的概念 precision and recall
  • 1.上半圖中有兩種形狀。圓形(半圓,整圓)是模型預(yù)測(cè)出來(lái)的結(jié)果,方形是原始測(cè)試數(shù)據(jù)
  • 2.下半圖中有兩種顏色綠色(暗綠,亮綠),紅色。綠色是預(yù)測(cè)正確,紅色當(dāng)然就是錯(cuò)誤預(yù)測(cè)。這里沒有統(tǒng)計(jì)FN。
  • 3.整圓包括true positive and false positive,綠色半圓只有true positive,整圓表示模型的預(yù)測(cè)結(jié)果。整方形true positive and true negative,綠色方形true positive,方形表示原始測(cè)試數(shù)據(jù)。
  • 4.precision表示的是:預(yù)測(cè)的n個(gè)”正樣本positive”中true positive個(gè)數(shù)占預(yù)測(cè)的n個(gè)“正樣本positive”的比例大小。
  • 5.recall表示的是:預(yù)測(cè)的n個(gè)”正樣本positive”中true positive個(gè)數(shù)占該模型測(cè)試的所有樣本中true positive的比例大小。解釋TP
舉例

在對(duì)多標(biāo)簽圖像分類時(shí),首先用訓(xùn)練好的模型得到所有測(cè)試樣本的confidence score,每一類(如car)的confidence score都保存到一個(gè)文件中(如test_car.txt)。假設(shè)該文件包含20個(gè)測(cè)試樣本(即對(duì)應(yīng)圖1中的矩形),每個(gè)id, confidence score, ground truth label如下:
接下來(lái)按照confidence score從大到小排序

上面雖然有分?jǐn)?shù),但是我們沒有判定每個(gè)id是屬于哪個(gè)類別。這里有兩種方法。

  • 1.設(shè)定閾值,比如score >= 50。
  • 2.或者每一類的前五必為該類。
    這里懸著第二種方法:

前五如下:


true positives就是指第4和第2張圖片,false positives就是指第13,19,6張圖片。

前五之后如下:

其中,false negatives是指第9,16,7,20張圖片,true negatives是指第1,18,5,15,10,17,12,14,8,11,3張圖片

計(jì)算Precision @ Recall
  • Precision=2/5=40%,意思是對(duì)于car這一類別,我們選定了5個(gè)樣本,其中正確的有2個(gè),即準(zhǔn)確率為40%
  • Recall=2/6=30%,意思是在所有測(cè)試樣本中,共有6個(gè)car,但是因?yàn)槲覀冎徽倩亓?個(gè),所以召回率為30%。
做PR圖

實(shí)際多類別分類任務(wù)中,通常不滿足只通過top-5來(lái)衡量一個(gè)模型的好壞,而是需要知道從top-1到top-N(N是所有測(cè)試樣本個(gè)數(shù),本文中為20)對(duì)應(yīng)的precision和recall。顯然隨著我們選定的樣本越來(lái)也多,recall一定會(huì)越來(lái)越高,而precision整體上會(huì)呈下降趨勢(shì)。把recall當(dāng)成橫坐標(biāo),precision當(dāng)成縱坐標(biāo),即可得到常用的precision-recall曲線。例子中precision-recall曲線如下:

圖中一共有20個(gè)點(diǎn),也就是使用每個(gè)點(diǎn)作為界限點(diǎn)。

VOC計(jì)算方法

PASCAL VOC CHALLENGE的計(jì)算方法。

    1. 07年的方法:首先設(shè)定一組閾值,[0, 0.1, 0.2, …, 1]。然后對(duì)于recall大于每一個(gè)閾值(比如recall>0.3),都會(huì)得到一個(gè)對(duì)應(yīng)的最大precision。這樣,就計(jì)算出了11個(gè)precision。AP即為這11個(gè)precision的平均值。這種方法英文叫做11-point interpolated average precision。計(jì)算曲線的下面積 則為AP?。
    1. 10年之后的方法:新的計(jì)算方法假設(shè)這N個(gè)樣本中有M個(gè)正例,那么會(huì)得到M個(gè)recall值(1/M, 2/M, ..., M/M),對(duì)于每個(gè)recall值r,可以計(jì)算出對(duì)應(yīng)(r' > r)的最大precision,然后對(duì)這M個(gè)precision值取平均即得到最后的AP值。計(jì)算方法如下:

對(duì)于上面的例子中。一共有20個(gè)測(cè)試,但是只有6個(gè)正的測(cè)試樣本。

上表中的最后一欄就是car這類的AP。而mAP就是10個(gè)種類的AP求平均值。
從表中g(shù)t_label可以看出正例是6個(gè),其他是負(fù)例。分別為1/6,2/6,3/6,4/6,5/6,6/6。對(duì)于每個(gè)recall值,都對(duì)應(yīng)著很多種top取法,所以每個(gè)recall值對(duì)應(yīng)的諸多取法中(包括等于此recall的取法)有一個(gè)最大的precision,把每種recall對(duì)應(yīng)最大的precision求和取平均即AP。

比如2/6的recall,查找上表,能得到recall2/6值的種類:從第2個(gè)開始到第5個(gè),而到上表第6個(gè),因?yàn)閷?duì)應(yīng)的是正例,所以就不是recall為2/6的范圍了(因?yàn)榍懊嬉呀?jīng)有2個(gè)正例,如果再加一個(gè)正例,recall值就是3/6了),這幾個(gè)取法對(duì)應(yīng)最大的precision是2/2。同理,recall 4/6的取法就是第四個(gè)正例開始(4/7)到第5個(gè)正例前(4/10)之間的范圍,對(duì)應(yīng)最大的pricision是4/7。

相應(yīng)的Precision-Recall曲線(這條曲線是單調(diào)遞減的)如下:?

AP衡量的是學(xué)出來(lái)的模型在每個(gè)類別上的好壞,mAP衡量的是學(xué)出的模型在所有類別上的好壞,得到AP后mAP的計(jì)算就變得很簡(jiǎn)單了,就是取所有AP的平均值。

目標(biāo)檢測(cè)計(jì)算mAP

檢測(cè)出來(lái)的bbox包含score和bbox,按照score降序排序,所以每添加一個(gè)樣本,就代表閾值降低一點(diǎn)(真實(shí)情況下score降低,iou不一定降低)。這樣就是可以有很多種閾值,每個(gè)閾值情況下計(jì)算一個(gè)prec和recall。

  1. 使用區(qū)域選擇算法得到候選區(qū)域
  2. 對(duì)候選區(qū)域,計(jì)算每一個(gè)候選區(qū)域和標(biāo)定框(groud truth)的iou
  3. 設(shè)定一個(gè)iou閾值,大于這個(gè)的標(biāo)為正樣本,小于的標(biāo)為負(fù)樣本,由此得到一個(gè)類似于分類時(shí)的測(cè)試集。
  4. 將給定的測(cè)試集(正負(fù)樣本),通過分類器,算出每一個(gè)圖片是正樣本的score
  5. 設(shè)定一個(gè)score閾值,大于等于此值的視作正樣本,小于的作為正樣本
  6. 根據(jù)上一步的結(jié)果可以算出準(zhǔn)確率和召回率
  7. 調(diào)節(jié)score閾值,算出召回率從0到1時(shí)的準(zhǔn)確率,得到一條曲線計(jì)算曲線的下面積 則為AP(這是07年方法,10年的方法參考上面),這條曲線就是對(duì)每個(gè)類的單獨(dú)計(jì)算出來(lái)的。通過計(jì)算所有類的AP就可以計(jì)算mAP了。

python版本的VOC計(jì)算方式

來(lái)源facebookresearch

def voc_ap(self, rec, prec, use_07_metric=True):
    if use_07_metric:
        ap = 0.
        # 2010年以前按recall等間隔取11個(gè)不同點(diǎn)處的精度值做平均(0., 0.1, 0.2, …, 0.9, 1.0)
        for t in np.arange(0., 1.1, 0.1):
            if np.sum(rec >= t) == 0:
                p = 0
            else:
                # 取最大值等價(jià)于2010以后先計(jì)算包絡(luò)線的操作,保證precise非減
                p = np.max(prec[rec >= t])
            ap = ap + p / 11.
    else:
        # 2010年以后取所有不同的recall對(duì)應(yīng)的點(diǎn)處的精度值做平均
        # first append sentinel values at the end
        mrec = np.concatenate(([0.], rec, [1.]))
        mpre = np.concatenate(([0.], prec, [0.]))

        # 計(jì)算包絡(luò)線,從后往前取最大保證precise非減
        for i in range(mpre.size - 1, 0, -1):
            mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])

        # 找出所有檢測(cè)結(jié)果中recall不同的點(diǎn)
        i = np.where(mrec[1:] != mrec[:-1])[0]

        # and sum (\Delta recall) * prec
        # 用recall的間隔對(duì)精度作加權(quán)平均
        ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

# 計(jì)算每個(gè)類別對(duì)應(yīng)的AP,mAP是所有類別AP的平均值
def voc_eval(self, detpath,
             classname,
             ovthresh=0.5,
             use_07_metric=True):
    # 提取所有測(cè)試圖片中當(dāng)前類別所對(duì)應(yīng)的所有g(shù)round_truth
    class_recs = {}
    npos = 0
    # 遍歷所有測(cè)試圖片
    for imagename in imagenames:
        # 找出所有當(dāng)前類別對(duì)應(yīng)的object
        R = [obj for obj in recs[imagename] if obj['name'] == classname]
        # 該圖片中該類別對(duì)應(yīng)的所有bbox
        bbox = np.array([x['bbox'] for x in R])
        difficult = np.array([x['difficult'] for x in R]).astype(np.bool)
        # 該圖片中該類別對(duì)應(yīng)的所有bbox的是否已被匹配的標(biāo)志位
        det = [False] * len(R)
        # 累計(jì)所有圖片中的該類別目標(biāo)的總數(shù),不算diffcult
        npos = npos + sum(~difficult)
        class_recs[imagename] = {'bbox': bbox,
                                'difficult': difficult,
                                'det': det}

    # 讀取相應(yīng)類別的檢測(cè)結(jié)果文件,每一行對(duì)應(yīng)一個(gè)檢測(cè)目標(biāo)
    if any(lines) == 1:
        # 某一行對(duì)應(yīng)的檢測(cè)目標(biāo)所屬的圖像名
        image_ids = [x[0] for x in splitlines]
        # 讀取該目標(biāo)對(duì)應(yīng)的置信度
        confidence = np.array([float(x[1]) for x in splitlines])
        # 讀取該目標(biāo)對(duì)應(yīng)的bbox
        BB = np.array([[float(z) for z in x[2:]] for x in splitlines])

        # 將該類別的檢測(cè)結(jié)果按照置信度大小降序排列
        sorted_ind = np.argsort(-confidence)
        sorted_scores = np.sort(-confidence)
        BB = BB[sorted_ind, :]
        image_ids = [image_ids[x] for x in sorted_ind]
        # 該類別檢測(cè)結(jié)果的總數(shù)(所有檢測(cè)出的bbox的數(shù)目)
        nd = len(image_ids)
        # 用于標(biāo)記每個(gè)檢測(cè)結(jié)果是tp還是fp
        tp = np.zeros(nd)
        fp = np.zeros(nd)
        # 按置信度遍歷每個(gè)檢測(cè)結(jié)果
        for d in range(nd):
            # 取出該條檢測(cè)結(jié)果所屬圖片中的所有g(shù)round truth
            R = class_recs[image_ids[d]]
            bb = BB[d, :].astype(float)
            ovmax = -np.inf
            BBGT = R['bbox'].astype(float)
            # 計(jì)算與該圖片中所有g(shù)round truth的最大重疊度
            if BBGT.size > 0:
                ......
                overlaps = inters / uni
                ovmax = np.max(overlaps)
                jmax = np.argmax(overlaps)
            # 如果最大的重疊度大于一定的閾值
            if ovmax > ovthresh:
                # 如果最大重疊度對(duì)應(yīng)的ground truth為difficult就忽略
                if not R['difficult'][jmax]:
                    # 如果對(duì)應(yīng)的最大重疊度的ground truth以前沒被匹配過則匹配成功,即tp
                    if not R['det'][jmax]:
                        tp[d] = 1.
                        R['det'][jmax] = 1
                    # 若之前有置信度更高的檢測(cè)結(jié)果匹配過這個(gè)ground truth,則此次檢測(cè)結(jié)果為fp
                    else:
                        fp[d] = 1.
            # 該圖片中沒有對(duì)應(yīng)類別的目標(biāo)ground truth或者與所有g(shù)round truth重疊度都小于閾值
            else:
                fp[d] = 1.

        # 按置信度取不同數(shù)量檢測(cè)結(jié)果時(shí)的累計(jì)fp和tp
        # np.cumsum([1, 2, 3, 4]) -> [1, 3, 6, 10]
        fp = np.cumsum(fp)
        tp = np.cumsum(tp)
        # 召回率為占所有真實(shí)目標(biāo)數(shù)量的比例,非減的,注意npos本身就排除了difficult,因此npos=tp+fn
        rec = tp / float(npos)
        # 精度為取的所有檢測(cè)結(jié)果中tp的比例
        prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
        # 計(jì)算recall-precise曲線下面積(嚴(yán)格來(lái)說(shuō)并不是面積)
        ap = self.voc_ap(rec, prec, use_07_metric)
    # 如果這個(gè)類別對(duì)應(yīng)的檢測(cè)結(jié)果為空,那么都是-1
    else:
        rec = -1.
        prec = -1.
        ap = -1.

    return rec, prec, ap

參考:
深度學(xué)習(xí): COCO目標(biāo)檢測(cè)測(cè)評(píng)指標(biāo)
MS COCO數(shù)據(jù)集目標(biāo)檢測(cè)評(píng)估
COCO: Metrics
淺談VOC數(shù)據(jù)集的mAP的計(jì)算過程
目標(biāo)檢測(cè)中的mAP是什么含義
機(jī)器視覺中的平均精度(AP)
Microsoft COCO 數(shù)據(jù)集解析
voc_eval.py 解
多標(biāo)簽圖像分類任務(wù)的評(píng)價(jià)方法——mAP
MSCOCO數(shù)據(jù)標(biāo)注詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容