上篇文章我们详细说了一下Detection中的Recall和Precision的计算,P-R曲线就是Precision和Recall画出的曲线。横轴是Recall,纵轴是Precision,那是什么的变化产生了这么多组PR值的呢?
答案:置信度。
举个栗子,已知在IOU为0.5的时候,一个检测网络检测猫狗鸡三种目标,输出如下结果:
以检测猫为例,画出P-R曲线?
首先,我们要计算出每个置信度下的TP和FP,以及TP+FN
计算过程,当我们只看第一个置信度最高的检测结果的时候,结果如下,计算出一组P,R
当我们把置信度拉到0.95,只看前两个计算结果的时候,计算出一组P,R
然后将Recall作为横轴,Precision作为纵轴,画图
这样,我们就画出了在IOU0.5下模型检测猫的P-R曲线
有了P-R曲线,要计算AP(Average Precision)直接求P-R曲线下的面积就行了,通常来说就是一个积分:
A P = ∫ 0 1 p ( r ) d r AP=\int_0^1 p(r) \mathrm{d}r AP=∫01p(r)dr
当然,不可导的地方我们可以分段积分。
但是,一般我们不直接去这么算,会简化一下,求个近似:
p i n t e r p ( r ) = max r ~ ≥ r p ( r ~ ) p_{interp}(r)=\max_{\tilde{r}\geq r} p(\tilde{r}) pinterp(r)=r~≥rmaxp(r~)
如图中橙色曲线所示:
橙色曲线下的面积就很容易求了,Pascal VOC2008是使用11点[0,0.1,0.2,0.3…0.9,1.0]对应点的转换精度值 P i n t e r p P_{interp} Pinterp相加然后除以11得到AP。
在我们这个例子中, 最终猫分类的AP=(1+1+1+0.8+0.8+0.75+0.75+0.72+0.72+0.57+0.57)/11=0.789
VOC2010~2012之后会对每个Recall都计算一下 P i n t e r p P_{interp} Pinterp,然后相乘相加,道理是一样的。
mAP(mean average precision)
同样的道理,我们可以算出狗分类的AP和鸡分类的AP,三个AP求平均就是mAP
在COCO中,参见COCO的说明
coco的AP和mAP是一个概念,都是跨类别的求平均,非但如此,上图中coco的primary challenge metric(主要评价指标)AP还使用了不同的10个IOU得到的结果进行了平均,IOU取值范围0.5到0.95,取值间隔0.05. 所以无需纠结到底是AP还是mAP,最终还是要看具体的实现是怎样。
还是以https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/datasets/voc_eval.py为例
def voc_ap(rec, prec, use_07_metric=False):
""" ap = voc_ap(rec, prec, [use_07_metric])
Compute VOC AP given precision and recall.
If use_07_metric is true, uses the
VOC 07 11 point method (default:False).
"""
if use_07_metric:
# 11 point metric
ap = 0.
for t in np.arange(0., 1.1, 0.1):
if np.sum(rec >= t) == 0:
p = 0
else:
p = np.max(prec[rec >= t])
ap = ap + p / 11.
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])
# to calculate area under PR curve, look for points
# where X axis (recall) changes value
i = np.where(mrec[1:] != mrec[:-1])[0]
# and sum (\Delta recall) * prec
ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap
我们可以看到,如果评价指标是VOC2007的话就用11点进行计算,如果不是就按照上述近似的方法求 P i n t e r p P_{interp} Pinterp,然后计算.
ROC是Receiver Operating Characteristic的缩写,中文名字:受试者工作特征曲线
明白了AP曲线ROC曲线也类似,不过需要计算的不是Precision和Recall两个指标,而是TPR和FPR两个指标,FPR TPR实际就是Recall,和PR曲线中的Recall一致。(感谢评论指正)
TPR,True Positive Rate:
真阳率:预测为真,并且预测正确的样本占所有真样本的比例
T P R = T P T P + F N TPR= \frac{TP}{TP+FN} TPR=TP+FNTP
FPR,False Positive Rate:
假阳率:预测为真,但是预测错误的样本占所有非真样本的比例
F P R = F P F P + T N FPR= \frac{FP}{FP+TN} FPR=FP+TNFP
其中关键是理解TN,也就是True Negative是什么。
在这个问题中,FP+TN和TN是等价的,就是所有鸡和狗的GT数量。
原因其实很简单,就是这个FPR的公式是针对二分类问题来讲的,猫狗二分类问题中对猫类来说:FP必然是狗类的TP,所以FP+TN必然等于狗类的GT之和。 但对检测问题就未必了,例如猫狗鸡的识别问题中,识别猫的FP有可能是把一个空地里的杂物识别成了猫,所以无法落到真实负样本中去,但是我们知道狗和鸡一共有多少负样本,所以这边FP+TN就是所有负样本,也就是GT中的8只狗+7只鸡=15。所以对于一个检测问题来说FPR指标的意义确实存在一定的问题。这也是为什么一般我们在检测问题中不使用ROC曲线作为指标。
23年7月12日更新=====有一个网友问如果检测模型只检测猫这1类,如何计算FP+TN?由于背景的GT无法计算,所以可以把所有对于猫类的误报(无中生有)作为FP,但TN是无法定义的,所以最好还是不要使用ROC曲线来作为检测的指标
我们可以统计出不同置信度阈值下狗和鸡识别正确的数量,统计加入下图
我们用FPR作为横轴,TPR作为纵轴,画图:
这就是识别猫在IOU=0.5下的ROC曲线。
为什么这边ROC曲线不过(0,0)点和(1,1)?
对于分类问题的ROC曲线来说,还是以猫狗二分类问题为例,设猫类是正样本,如果全部识别为猫,TPR和FPR都等于1,所以会过(1,1),如果都是别为狗,那TP和FP都是0,所以TPR和FPR都等于0,所以会过(0,0)。但是对于检测问题来说,识别狗识别猫识别鸡不是互斥的问题,我无法保证GT都能被识别出来(无论对错),也无法保证识别出来的检测框和GT对应,所以有可能不过00和11点。
就是ROC曲线下的面积,和AP类似,ImageNet使用的是AUC指标,因为它是一个分类问题。AUC不是ROC曲线的专有名词,PR曲线也有AUC,只不过一般都称作AP或mAP了
A U C R O C AUC_{ROC} AUCROC对正负样本都关心,AP或 A U C P R AUC_{PR} AUCPR只关心正样本。
一个GT只能有一个Positive的检测框,例如当IOU低于0.5的时候,NMS算法有可能无法过滤掉同一个GT的多个检测结果,此时以置信度最高的一个为正样本,其他为负样本。