这是我的cv秋招面试的第四篇,此篇我将回顾下关于目标检测评价指标的相关细节。
我将从mAP=精度指标、和FPS-速度指标三个方面进行介绍。其中mAP作为目标检测中最常用的精度指标,我已经在第三篇中描述了关于PR曲线的内容,本篇进行只进行简单的介绍概念,细节部分重要讲解具体的计算过程;FLOPs则作为衡量算法模型的复杂度的指标,而FPS则通常作为目标检测的速度指标,通常需要在相同硬件环境下才能比较。
目标检测的最终目的,是在保证精度的同时,提升检测速度。目标检测技术的很多实际应用在准确度和速度上都有很高的要求,如果不计速度性能指标,只注重准确度表现的突破,但其代价是更高的计算复杂度和更多内存需求,对于全面行业部署而言,可扩展性仍是一个悬而未决的问题。
在目标检测问题中,给定一个图像,找到它所包含的物体,找到它们的位置并对它们进行分类。目标检测模型通常是在一组特定的类集合上进行训练的,所以模型只会定位和分类图像中的那些类。另外,对象的位置通常采用矩形边界框表示。因此,目标检测涉及图像中物体的定位和分类。
目标检测问题中的每个图片都可能包含一些不同类别的物体。如前所述,需要评估模型的物体分类和定位性能。因此,用于图像分类问题的标准指标precision不能直接应用于此。 这就是为什么需要mAP。(1 Accuracy作为指标有哪些局限性)
对于任何算法,评估指标需要知道ground truth(真实标签)数据。 我们只知道训练、验证和测试数据集的ground truth。对于目标检测问题,ground truth包括图像中物体的类别以及该图像中每个物体的真实边界框。
这里给出了一个实际图片(jpg、png等格式),以及相应的文本注释(边界框坐标(x,y,w,h)和类别),如图中红色框以及文本标签所示。
对于这个特殊例子,模型在训练时需要原始的图片:
以及ground truth的3个坐标及类别(这里假定图片大小是1000x800px,所有的坐标值都是以像素为单位的近似值):
类别 | 坐标x | 坐标y | 框宽 | 框高 |
---|---|---|---|---|
Dog | 100 | 600 | 150 | 100 |
Horse | 700 | 300 | 200 | 250 |
Person | 400 | 400 | 100 | 500 |
下面让我们动一下手,去看如何计算mAP。这里我们不谈论不同的目标检测算法,假定我们已经有了一个训练好的模型,现在只需要在验证集上评估其性能。
前面展示了原始图像和以及对应的ground truth。训练集和验证集中所有图像都以此方式标注。
训练好的目标检测模型会给出大量的预测结果,但是其中大多数的预测值都会有非常低的置信度(confidence score),因此我们只考虑那些置信度高于某个阈值的预测结果。
将原始图片送入训练好的模型,在经过置信度阈值筛选之后,目标检测算法给出带有边界框的预测结果:
现在,由于我们人类是目标检测专家,我们可以知道这些检测结果大致正确。但我们如何量化呢?我们首先需要判断每个检测的正确性。这里采用IoU(Intersection over Union),它可以作为评价边界框正确性的度量指标。 这是一个非常简单的指标。(近几年IOU的不断改进,原始IOU已经不能很好的作为指标,关于IOU应该同样会参考别人的写一篇自己的)
IoU是预测框与ground truth的交集和并集的比值。这个量也被称为Jaccard指数,并于20世纪初由Paul Jaccard首次提出。为了得到交集和并集,我们首先将预测框与ground truth放在一起,如图所示。
对于每个类,预测框和ground truth重叠的区域是交集,而横跨的总区域就是并集。其中horse类的交集和并集如下图所示(这个例子交集比较大):
其中蓝绿色部分是交集,而并集还包括橘色的部分。那么,IoU可以如下计算:
为了计算precision和recall,与所有机器学习问题一样,我们必须鉴别出True Positives(真正例)、False Positives(假正例)、True Negatives(真负例)和 False Negatives(假负例)。
为了获得True Positives and False Positives,我们需要使用IoU。计算IoU,我们从而确定一个检测结果(Positive)是正确的(True)还是错误的(False)。最常用的阈值是0.5,即如果IoU> 0.5,则认为它是True Positive,否则认为是False Positive。而COCO数据集的评估指标建议对不同的IoU阈值进行计算,但为简单起见,我们这里仅讨论一个阈值0.5,这是PASCAL VOC数据集所用的指标。
为了计算Recall,我们需要Negatives的数量。由于图片中我们没有预测到物体的每个部分都被视为Negative,因此计算True Negatives比较难办。但是我们可以只计算False Negatives,即我们模型所漏检的物体。
另外一个需要考虑的因素是模型所给出的各个检测结果的置信度。通过改变置信度阈值,我们可以改变一个预测框是Positive还是 Negative,即改变预测值的正负性(不是box的真实正负性,是预测正负性)。基本上,阈值以上的所有预测(Box + Class)都被认为是Positives,并且低于该值的都是Negatives。
对于每一个图片,ground truth数据会给出该图片中各个类别的实际物体数量。我们可以计算每个Positive预测框与ground truth的IoU值,并取最大的IoU值,认为该预测框检测到了那个IoU最大的ground truth。然后根据IoU阈值,我们可以计算出一张图片中各个类别的正确检测值(True Positives, TP)数量以及错误检测值数量(False Positives, FP)。据此,可以计算出各个类别的precision:
精准率:precision = TP/(TP + FP)
既然我们已经得到了正确的预测值数量(True Positives),也很容易计算出漏检的物体数(False Negatives, FN)。据此可以计算出Recall(其实分母可以用ground truth总数):
召回率:recall = TP/(TP + FN)
由于map是数据集中所有类别AP值得平均,所以我们要计算map,首先得知道某一类别的AP值怎么求。不同数据集的某类别的AP计算方法大同小异,主要分为三种:
(1)在VOC2010以前,只需要选取当Recall >= 0, 0.1, 0.2, …, 1共11个点时的Precision最大值,然后AP就是这11个Precision的平均值,map就是所有类别AP值的平均。
(2)在VOC2010及以后,需要针对每一个不同的Recall值(包括0和1),选取其大于等于这些Recall值时的Precision最大值,然后计算PR曲线下面积作为AP值,map就是所有类别AP值的平均。
(3)COCO数据集,设定多个IOU阈值(0.5-0.95,0.05为步长),在每一个IOU阈值下都有某一类别的AP值,然后求不同IOU阈值下的AP平均,就是所求的最终的某类别的AP值。
当比较mAP值,记住以下要点:
1、mAP通常是在一个数据集上计算得到的。
2、虽然解释模型输出的绝对量化并不容易,但mAP作为一个相对较好的度量指标可以帮助我们。 当我们在流行的公共数据集上计算这个度量时,该度量可以很容易地用来比较目标检测问题的新旧方法。
3、根据训练数据中各个类的分布情况,mAP值可能在某些类(具有良好的训练数据)非常高,而其他类(具有较少/不良数据)却比较低。所以你的mAP可能是中等的,但是你的模型可能对某些类非常好,对某些类非常不好。因此,建议在分析模型结果时查看各个类的AP值。这些值也许暗示你需要添加更多的训练样本。
拿单张图片来说吧,首先遍历图片中ground truth对象,然后提取我们要计算的某类别的gt objects,之后读取我们通过检测器检测出的这种类别的检测框(其他类别的先不管),接着过滤掉置信度分数低于置信度阈值的框(也有的未设置信度阈值),将剩下的检测框按置信度分数从高到低排序,最先判断置信度分数最高的检测框与gt bbox的iou是否大于iou阈值,若iou大于设定的iou阈值即判断为TP,将此gt_bbox标记为已检测(后续的同一个GT的多余检测框都视为FP,这就是为什么先要按照置信度分数从高到低排序,置信度分数最高的检测框最先去与iou阈值比较,若大于iou阈值,视为TP,后续的同一个gt对象的检测框都视为FP),iou小于阈值的,直接规划到FP中去。这里置信度分数不同的论文可能对其定义不一样,一般指分类置信度的居多,也就是预测框中物体属于某一个类别的概率。后面我仔细总结一下。
插一段这一过程的代码:
if ovmax > ovthresh: # 若iou大于阈值
if not R['difficult'][jmax]: # 且要检测的gt对象非difficult类型
if not R['det'][jmax]: # 且gt对象暂未被检测
tp[d] = 1. # 此检测框记为TP
R['det'][jmax] = 1 # 并将此gt对象标记为已检测
else: # 若gt对象已被检测,那么此检测框为FP
fp[d] = 1.
else: # iou<=阈值,此检测框为FP
fp[d] = 1.
关于图片中FN的统计就比较简单了,图片中某类别一共有多少个gt我们是知道的,减去TP的个数,剩下的就是FN的个数了,至此我们已经知道如何计算某一类别的percision和recall如何计算。
注:
mAP值计算在NMS之后进行的,mAP是统计我们的检测模型的最终评价指标,是所有操作完成之后,以最终的检测结果作为标准,来计算mAP值的,另外提一点一般只有测试的时候才会作NMS,训练的时候不进行NMS操作,因为训练的时候需要大量的正负样本去学习。
目标检测技术的很多实际应用在准确度和速度上都有很高的要求,如果不计速度性能指标,只注重准确度表现的突破,但其代价是更高的计算复杂度和更多内存需求,对于全面行业部署而言,可扩展性仍是一个悬而未决的问题。一般来说目标检测中的速度评价指标有:
(1)FPS,检测器每秒能处理图片的张数
(2)检测器处理每张图片所需要的时间
但速度评价指标必须在同一硬件上进行,同一硬件,它的最大**FLOPS(每秒运算浮点数代表着硬件性能,此处区分FLOPs)是相同的,不同网络,处理每张图片所需的FLOPs(浮点操作数)**是不同的,所以同一硬件处理相同图片所需的FLOPs越小,相同时间内,就能处理更多的图片,速度也就越快,处理每张图片所需的FLOPs与许多因素有关,比如你的网络层数,参数量,选用的激活函数等等,这里仅谈一下网络的参数量对其的影响,一般来说参数量越低的网络,FLOPs会越小,保存模型所需的内存小,对硬件内存要求比较低,因此比较对嵌入式端较友好。
FLOPs:floating point operations 指的是浮点运算次数,理解为计算量,可以用来衡量算法/模型的复杂度。此处区分一下FLOPS(全部大写),FLOPS指的是每秒运算的浮点数,理解为计算速度,衡量一个硬件的标准。我们要的是衡量模型的复杂度的指标,所以选择FLOPs。
(1)卷积层
FLOPs=(2 * Ci * k * K-1)* H * W * Co(不考虑bias)
FLOPs=(2 * Ci * k * K)* H* W * Co(考虑bias)
Ci为输入特征图通道数,K为过滤器尺寸,H,W,Co为输出特征图的高,宽和通道数。
最后得到的Co张输出特征图,每张特征图上有H * W个像素点,而这其中的每个像素点的值都是由过滤器与输入特征图卷积得到的,过滤器中Ci * k * K个点,每个点都要和输入特征图对应点作一次相乘操作(浮点操作数为ci * k * k),然后将这些过滤器和输入特征图对应点相乘所得的数相加起来(浮点操作数为ci * k * k-1,n个数相加,所需要的浮点操作数为n-1),得到一个值,对应于一张输出特征图中的一个像素,输出特征图有Co张,故有Co个过滤器参与卷积运算,所以卷积层的
FLOPs=(2 * Ci * k * K-1)* H * W * Co
(2)池化层
池化分为最大值池化和均值池化,看别人的博客说网络中一般池化层较少,且池化操作所占用的FLOPs很少,对速度性能影响较小。我在想,最大池化一般是找出输入特征图中过滤器范围内的最大值,以最大值代替,好像不涉及到浮点运算操作。均值池化,要求平均值,先相加再除以总数(输出特征图上一个像素点,需要浮点操作数为:(k * K-1+1)。求平均值,先k * k个数相加,操作数为,k* k-1,然后除以k * k,浮点操作数为1),输出特征图通道数为Co,所以这里浮点操作数应该为
FLOPs = k * k * H * W * Co
(3)全连接层
现在全连接层已经基本不用了,CNN基本用FCN来代表,可用卷积层来实现全连接层的功能。设I为输入神经元个数,O为输出神经元个数,输出的每个神经元都是由输入的每个神经元乘以权重(浮点操作数为I),然后把所得的积的和相加(浮点操作数为I-1),加上一个偏差(浮点操作数为1)得到了,故FLOPs为:
FLOPs=(I+I-1) * O = (2I-1) * O(不考虑bias)
FLOPs=((I+I-1+1)* O = (2I) * O(考虑bias)
信息量有点大,感觉要完全理解目标检测的评价指标必须要在实际项目中,用实际的数据来评价算法的精度和速度,受到不同平台或者不同代码的优化的影响,同一数据集在同一个算法中的效果也并不一定完全一样。
另外,我认为如果要使目标检测能更好的在工业中进行应用,模型的轻量化会是更好的研究方向。此篇作为评估方法的第四篇,也包含了前面部分的知识点,复习时要重点看。
参考:
此博客只作为我自己的cv面试复习资料,转侵删。
1、目标检测模型的评估指标mAP详解(附代码)
2、Measuring Object Detection models - mAP - What is Mean Average Precision?
3、目标检测的性能评价指标