目標檢測中的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,終於寫完了。
以前沒有寫博客記筆記的習慣,以后得多記筆記!
原創不易,花了挺多時間,轉載請注明出處!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM