> 文章列表 > 【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP

【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP

【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP

20230116:网上好多TP,FP,都感觉有点问题,特意研究了源代码,写下理解。

第一步:需要确定计算TP的准则

一般情况,我们设定Iou_threadhold 阈值∈[0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95],这基于IoU阈值的情况下,计算当前检测结果Dt 与 真值Gt之间的IoU,大于阈值,则算是TP。小于阈值否则视为FP。TP+FP = 全部Dt数量

也可以自定义相关TP的准则,例如我们要求模型需要输出confidence,需要输出位置,速度。confidence需要>0.3,位置与真值需要小于0.1米,速度需要小于0.5m/s,才认为是TP。

参考了:what-is-map-understanding-the-statistic-of-choice-for-comparing-object-detection-models

第二步骤,基于TP数量,基于检测到的数量,基于真值数量,计算FP、FN、TN

基于以下理解,

全部的真值标注框的数量 num_gt,全部检测的框数量为num_dt

True Positive (TP): 检测存在,真值存在,真值标注框与检测框的Iou大于阈值;
False Positive (FP): 检测存在,真值不存在,真值标注框与检测框的Iou小于阈值;
所以:fp_num = num_dt - tp_num

False Negative (FN): 检测不存在,真值是存在,
所以:fn_num = num_gt - tp_num

For calculating Recall, we need the count of Negatives. Since every part of the image where we didn’t predict an object is considered a negative, measuring “True” negatives is a bit futile. So we only measure “False” Negatives ie. the objects that our model has missed out.

True Negative (TN): 检测是不存在,真值不存在。在 mAP 评价指标中不会使用到。

Negative 和Positive 是相对于检测器的Dt而言,Dt输出的是Positive 或者 Negative。
用真值去考核Dt输出的结果为True或者False。

第三步骤:计算整体的Precision 和 Recall

Precision = tp_num / num_dt
Recall = tp_num / num_gt

等价

Precision = tp_num /(tp_num +fp_num )
Recall = TP/(tp_num +fn_num )

计算 AP

AP:在某个IoU阈值下,PR 曲线下面积。
mAP:Iou_threadhold 阈值∈[0.5,0.55,0.6,0.65,0.7,0.75,0.8,0.85,0.9,0.95] 的情况下,可以分别得到AP值,mean Average Precision,即各类别 AP 的平均值。

PR曲线的绘制方法

这篇目标检测中PR曲线和mAP文章,我个人认为有点错误。

我按照源代码的步骤:
假设:目前有101张图片,共有真值 num_gt 397;IoU阈值0.5-0.95,每0.05取一个,共10个;(通过NMS后)输出的检测目标框 2944;
1、每个框的置信度 scores 的尺寸1×2944
2、计算TP的情况:首先设定self.tps 尺寸 101 ×10 ×n,101是图片数量,n是每个图片detection的检测到的框的数目,10是0.5-0.95的Iou阈值。self.tps 里面只存储False或者True。
3、对self.tps 转换到 10 ×2944

tps = torch.cat(self.tps, dim=1)

4、对 score进行排序,

  scores = torch.cat(self.scores, dim=0)scores, sortidx = torch.sort(scores, dim=0, descending=True)# 全部的图片的全部检测的框的得分排序

5、对TP进行排序,按照score进行排序

tps = tps[:,sortidx]返回结果:sortidx tensor([2902, 2922, 2703,  ..., 1245, 1546, 2901])   

6、tps 的尺寸还是 10 ×2944,10行,2944列
7、对tps 的每一列的2944个,累加计算 True 的数目

		tp_sum = torch.cumsum(tps, dim=1)print("tp_sum",tp_sum.shape[0],tp_sum.shape[1])print("tp_sum0",tp_sum[0][0])print("tp_sum100",tp_sum[0][100])print("tp_sum1000",tp_sum[0][1000])print("tp_sum1000",tp_sum[0][-1])
返回结果:
tp_sum 10 2944
tp_sum0 tensor(1.)
tp_sum100 tensor(48.)
tp_sum1000 tensor(126.)
tp_sum1000 tensor(144.)

这里特别说明下, torch.cumsum返回维度dim中输入元素的累计和,维度保持不变,输出的第一个数据和输入一致,输出最后的数据为输入数据的全部的和.

例如
一维数据:

    x1 = torch.arange(0, 6)print(x1)y1 = torch.cumsum(x1, dim=0)  print(y1)

【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP
结果分析:

y1(dim=0)的结果是:第一列不变,后面的列依次在上一列基础上加上自身的数。
第1列,值0,不变,和为本身,即:0;
第2列,值1,累加前一列值0,和为:0+1=1
第3列,值2,累加前一列值1,和为:1+2=3
第4列,值3,累加前一列值3,和为:3+3=6
第5列,值4,累加前一列值6,和为:6+4=10
第6列,值5,累加前一列值10,和为:10+5=15

8、计算fp的情况, tp+fp =2944,所以,直接可以取反得到fp数目

fps = ~tps

9、对 fps 的每一列的2944个,累加计算True的数目

        print("tp_sum0",fp_sum[0][0])print("tp_sum100",fp_sum[0][100])print("tp_sum1000",fp_sum[0][1000])print("tp_sum1000",fp_sum[0][-1])
返回结果
tp_sum0 tensor(0.) 
tp_sum100 tensor(53.)  
tp_sum1000 tensor(875.)
tp_sum1000 tensor(2800.)

10、计算precision 和 recall

        precision = tp_sum / (tp_sum+fp_sum)recall = tp_sum / num_gtprint("num_gt",num_gt)print("precision",precision.shape[0],precision.shape[1])
返回结果
num_gt 397                                                                                                                                                                                                                                   precision 10 2944 

11、初始化PR图片

self.rec_thres = 100
PRcurve = torch.zeros(len(self.iou_thres),len(self.rec_thres))

12、在PR 中填入precision 和 recall,但是要保证图片是单调递减的

        for ti, (prec_T,rc_T) in enumerate(zip(precision, recall)):# 保证了单调降低for i in range(num_dt-1,0,-1):if prec_T[i] > prec_T[i-1]:prec_T[i-1] = prec_T[i]# find the 100 recall pointsidxs = np.searchsorted(rc_T, self.rec_thres, side='left')# fill in the P-R curvefor ri,pi in enumerate(idxs):if pi >= len(prec_T):# reach the upper bound of RecallbreakPRcurve[ti,ri] = prec_T[pi]

13、返回AP的结果,尺寸10×1

APs = self.PRcurve.mean(dim=1)
# 将10× 100的PR表格,压缩到10×1

14、返回最佳阈值

f1 = 2 * (precision*recall) / (precision + recall)
self.best_thres = scores[torch.argmax(f1, dim=1)]

结束
代码,可以参考我的一份gitee代码

other

(1)交并比 - Intersection Over Union (IOU)

交并比(IOU)是度量两个检测框(对于目标检测来说)的交叠程度,公式如下:
【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP
B_gt 代表的是目标实际的边框(Ground Truth,GT),B_p 代表的是预测的边框,通过计算这两者的 IOU,可以判断预测的检测框是否符合条件,IOU 用图片展示如下:
【评价方案】目标检测TP,FP,以及perception recall,以及AP,mAP