紀(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ì)算方法。
- 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?。
- 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。
- 使用區(qū)域選擇算法得到候選區(qū)域
- 對(duì)候選區(qū)域,計(jì)算每一個(gè)候選區(qū)域和標(biāo)定框(groud truth)的iou
- 設(shè)定一個(gè)iou閾值,大于這個(gè)的標(biāo)為正樣本,小于的標(biāo)為負(fù)樣本,由此得到一個(gè)類似于分類時(shí)的測(cè)試集。
- 將給定的測(cè)試集(正負(fù)樣本),通過分類器,算出每一個(gè)圖片是正樣本的score
- 設(shè)定一個(gè)score閾值,大于等于此值的視作正樣本,小于的作為正樣本
- 根據(jù)上一步的結(jié)果可以算出準(zhǔn)確率和召回率
- 調(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ì)算方式
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)注詳解