## mAP
mAP定义及相关概念
- mAP:mean Average Precision,即各类别AP的平均值
- AP:PR曲线下面积
- PR曲线:Precision-Recall曲线
- Precision:TP/(TP+FP)
- Recall:TP/(TP+FN)
- TP:IoU>0.5的检测框数量(同一Ground Truth只计算一次)
- FP:IoU <=0.5的检测框,或者是检测到同一个GT的多余检测框的数量
- FN:没有检测到的GT的数量
图像检索mAP
图像检索中的mAP和目标检测中的mAP几乎一模一样:
以上是图像检索中mAP的计算案例,简要说明如下:
1、查询图片1在图像库中检索相似的图像,假设图像库中有五张相似图像,表示为图片1、……、图片5,排名不分先后
2、检索,返回top-10图像,如上图第二行,橙色表示相似图像,灰色表示无关图像
3、接下来就是precision、recall的计算过程,结合上图比较容易理解,
以返回图片6的节点为例:
top-6中,有3张图像确实为相似的图像,另外三张为无关图像,因此precision = 3/6;同时,总共五张相似图像,top-6检索出来了三张因此,recall = 3/5
4、然后计算AP,可以看右边的计算公式,可以发现是把列出来的查询率(precision)相加取平均,那么最关键的问题来了,为什么选择这几张图像的precision求平均?可惜图中没有告诉我们答案。
其实不难,一句话就是:选择每个recall区间内对应的最高precision;
eg:以上图橙色检索案例为例,当我们只选择top-1作为检索结果返回(即,只返回一个检索结果)时,检索性能为:
top-1:recall = 1 / 5、precision = 1 / 1;# 以下类推;
top-2:recall = 1 / 5、precision = 1 / 2;
top-3:recall = 2 / 5、precision = 2 / 3;
top-4:recall = 2 / 5、precision = 2 / 4;
top-5:recall = 2 / 5、precision = 2 / 5;
top-6:recall = 3 / 5、precision = 3 / 6;
top-7:recall = 3 / 5、precision = 3 / 7;
top-8:recall = 3 / 5、precision = 3 / 8;
top-9:recall = 4 / 5、precision = 4 / 9;
top-10:recall = 5 / 5、precision = 5 / 10;
结合上面清单,先找找recall = 1 / 5区间下的最高precision,对应着precision = 1 / 1;
同理,recall = 2 / 5区间下的最高precision,对应着precision = 2 / 3;
recall = 3 / 5区间下的最高precision,对应着precision = 3 / 6;依次类推;
这样AP = (1 / 1 + 2 / 3 + 3 / 6 + 4 / 9 + 5 / 10) / 5;
那么mAP是啥?计算所有检索图像返回的AP均值,对应上图就是橙、绿突图像计算AP求均值,对应红色框;
这样mAP就计算完毕啦~~~是不是很容易理解?目标检测的mAP也是类似操作了;
目标检测中mAP计算流程
下面以检测人脸为例,gt label表示1为人脸,0为bg,某张图像中一共检测出了20个pred bbox,id:1~20,并对应了confidence score,gt label也很容易获得,pred bbox与gt bbox算IoU,给定一个threshold,那么就知道该pred bbox是否为正确的预测结果,那么就知道该pred bbox是否为正确的预测结果了,就对应了其gt label。---- 其实下表不应该这么理解的,但我们还是先这么认为,忽略差异吧,先直捣黄龙,table 1:
接下来对confidence score排序,得到table 2:
这张表很重要,接下来的precision和recall都是依照这个表计算的,那么这里的confidence score其实就是和图像检索中的相似度关联上了,具体的,就是如第一节的图像检索中,虽然我们计算mAP没在乎其检索返回的先后顺序,但top1肯定是与待检索图像最相似的,对应的similarity score最高,对人脸检测而言,pred bbox的confidence score最高,也说明该bbox最有可能是人脸。
然后计算precision和recall ,这两个标准的定义如下:
上面的图看看就行,能理解就理解,不理解可以参照第一节图像检索的例子来理解;
现以返回的top-5结果为例,如table 3:
在这个例子中,true positives就是指id = 4、2的pred bbox,false positives就是指id = 13、19、6的pred bbox。方框内圆圈外的元素(false negatives + true negatives)是相对于方框内的元素而言,在这个例子中,是指confidence score排在top-5之外的元素,即table 4:
其中,false negatives是指id = 9、16、7、20的4个pred bbox,true negatives是指id = 1、18、5、15、10、17、12、14、8、11、3的11个pred bbox;
那么,这个例子中Precision = 2 / 5 = 40%,意思是对于人脸检测而言,我们选定了5 pred bbox,其中正确的有2个,即准确率为40%;Recall = 2 / 6 = 33%,意思是该图像中共有6个人脸,但是因为我们只召回了2个,所以召回率为33%;
实际的目标检测任务中,我们通常不满足只通过top-5来衡量一个模型的好坏,而是需要知道从top-1到top-N(N是所有pred bbox,本文中为20)对应的precision和recall;显然随着我们选定的pred bbox越来也多,recall一定会越来越高,而precision整体上会呈下降趋势;把recall当成横坐标,precision当成纵坐标,即可得到常用的precision-recall曲线,以上例子的precision-recall曲线如fig 1:
以上图像如何计算的?可以参照第一节图像检索中的栗子,还是比较容易理解的吧;
上面的每个红点,就相当于根据table 2,按照第一节中图像检索的方式计算出来的,也可以直接参照下面的table 5,自己心里算一算;
那么按照选择每个recall区间内对应的最高precision的计算方案,各个recall区间内对应的top-precision,就刚好如fig 1中的绿色框位置,可以进一步结合table 5中的绿色框理解;
好了,那么对这张图像而言,其AP = (1 / 1 + 2 / 2 + 3 / 6 + 4 / 7 + 5 / 11 + 6 / 16)/ 6;这是针对单张图像而言,所有图像也类似方式计算,那么就可以根据所有图像上的pred bbox,采用同样的方式,就计算出了所有图像上人脸这个类的AP;因为人脸检测只有一个类,如Pascal VOC这种20类的,每类都可以计算出一个AP,那么AP_total / 20,就是mAP啦;
但是等等,有没有发现table 5中,计算方式好像跟我们讲的有一点不一样?我们继续看看;
Pascal VOC的两套mAP评估标准
Pascal VOC中对mAP的计算经历了两次迭代,一种是VOC07的计算标准,对应绿色框:
首先设定一组阈值,T = [0、0.1、0.2、…、1],然后对于recall大于每一个阈值Ti(比如recall > 0.3),我们都会在该recall区间内得到一个对应的最大precision,这样我们就计算出了11个precision;----- 这里与上两节介绍的概念是一样的,只不过上面recall的区间是参照gt label来划分的,这里是我们人为划分的11个节点;
AP即为这11个precision的平均值,这种方法英文叫做11-point interpolated average precision;有了一个类的AP,所有类的AP均值即为mAP;
另一种是VOC10的计算标准,对应白色框:
新的计算方法假设N个pred bbox中有M个gt bbox,那么我们会得到M个recall节点(1 / M、2 / M、…、 M / M),对于每个recall值 r,我们可以计算出对应(r’ > r)的最大precision,然后对这M个precision值取平均即得到最后的AP值,计算方法如table 5:
从VOC07的绿框、VOC10的白框对比可知,差异主要在recall = 3 / 6下的precision,可以发现VOC07找的top-precision是在该recall区间段内的,但VOC10相当于是向后查找的,需确保该recall阈值以后的区间内,对应的是top-precision,可知4 / 7 > 3 / 6,因此使用4 / 7替换了3 / 6,其他recall阈值下的操作方式类似;
那么代码的实操中,就得从按照recall阈值从后往前计算了,这样就可以一遍就梭哈出所有结果,如果按recall从前往后计算,就有很多重复性计算(不断地重复向后recall区间内查找top-precision),然后呢,就可以使用到动态规划的方式做了,理论结合实践啊有木有~~~
那么VOC10下,相应的Precision-Recall曲线如fig 2,可以发现这条曲线是单调递减的,剩下的AP计算方式就与VOC07相同了:
这里还需要继续一点,VOC07是11点插值的AP方式,等于是卡了11个离散的点,划分10个区间来计算AP,但VOC10是是根据recall值变化的区间来计算的,在这个栗子里,recall只变化了6次,但如果recall变化很多次,如100次、1000次、9999次等,就可以认为是一种 “伪” 连续的方式计算了;
总结:
AP衡量的是模型在每个类别上的好坏,mAP衡量的是模型在所有类别上的好坏,得到AP后mAP的计算就变得很简单了,就是取所有类别AP的平均值。
代码实现
这个函数假设我们已经得到了排序好的precision、recall的list,对应上图fig 2,进一步可以参照第一节中的清单理解
# VOC-style mAP,分为两个计算方式,之所有两个计算方式,是因为2010年后VOC更新了评估方法,因此就有了07-metric和else...
def voc_ap(rec, prec, use_07_metric=False):
"""
average precision calculations
[precision integrated to recall]
:param rec: recall list
:param prec: precision list
:param use_07_metric: 2007 metric is 11-recall-point based AP
:return: average precision
"""
if use_07_metric:
# 11 point metric
ap = 0.
# VOC07是11点插值的AP方式,等于是卡了11个离散的点,划分10个区间来计算AP
for t in np.arange(0., 1.1, 0.1):
if np.sum(rec >= t) == 0:
p = 0 # recall卡的阈值到顶了,1.1
else:
p = np.max(prec[rec >= t]) # VOC07:选择每个recall区间内对应的最高precision的计算方案
ap = ap + p / 11. # 11-recall-point based AP
else:
# correct AP calculation
# first append sentinel values at the end
mrec = np.concatenate(([0.], rec, [1.]))
mpre = np.concatenate(([0.], prec, [0.]))
# compute the precision envelope
for i in range(mpre.size - 1, 0, -1):
mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) # 这个是不是动态规划?从后往前找之前区间内的top-precision,多么优雅的代码呀~~~
# to calculate area under PR curve, look for points where X axis (recall) changes value
# 上面的英文,可以结合着fig 2的绿框理解,一目了然
# VOC10是是根据recall值变化的区间来计算的,如果recall变化很多次,就可以认为是一种 “伪” 连续的方式计算了,以下求的是recall的变化
i = np.where(mrec[1:] != mrec[:-1])[0]
# 计算AP,这个计算方式有点玄乎,是一个积分公式的简化,应该是对应的fig 2中红色曲线以下的面积,之前公式的推导我有看过,现在有点忘了,麻烦各位同学补充一下
# 现在理解了,不难,公式:sum (\Delta recall) * prec,其实结合fig2和下面的图,不就是算的积分么?如果recall划分得足够细,就可以当做连续数据,然后以下公式就是积分公式,算的precision、recall下面的面积了
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap
修改于:https://zhuanlan.zhihu.com/p/48992451