这样的标准上海市疫情防控工作领导小组也好意思发布出来?

人民日报林治波社长发出灵魂拷问:你们是没有常识,还是没有良知?

伊朗著名美女明星、奥斯卡影后被捕!

母子乱伦:和儿子做了,我该怎么办?

阳了后,14亿人民才发现集体被忽悠了!

生成图片,分享到微信朋友圈

自由微信安卓APP发布,立即下载! | 提交文章网址
查看原文

目标检测 评价指标

The following article is from CV算法恩仇录 Author 悬鱼铭

点击下方卡片,关注“新机器视觉”公众号

重磅干货,第一时间送达

今天通俗介绍了目标检测的评价指标,有基本原理及代码实现,非常适合初学者。

目录

  • 正样本与负样本
  • 真正 (TP)、假正 (FP)、真负 (TN)、假负 (FN)
  • 交并比(IoU)
  • 准确率(Precision)
  • 召回率 (Recall)
  • 几何平均分(F Score)
  • 单类平均准确率 (Average-Precision)
  • 代码实现 mAP

正样本与负样本

样本在计算机视觉的评价中是非常重要的概念,正样本比较好理解,是要检测的物体,负样本是不要检测的目标。这里负样本会有一些问题,首先负样本定义比较主观,其次负样本和正样本的量纲不在一个级别,那么实际算法中会把检测出的待选区域中的一部分作为正样本,一部分作为负样本,例如 Faster-RCNN 及 SSD 等。

真正(TP)、假正(FP)、真负(TN)、假负(FN)

正确的正向预测(True Positive,TP):正样本被正确检测的数量,需要满足 3 个条件:

  • 置信度(Confidence Score)大于阈值,实际上预测出的所有的框都要满足这个条件;
  • 预测类型与标签类型匹配;
  • 预测的 Bounding Box 与 Ground Truth 的交并比 (Intersection over Union,IoU,后续会详细介绍) 大于阈值 (e.g. 0.5) ,当有多个满足条件的预选框,则选择置信度最大的作为TP,其余的作为 FP。

错误的正向预测(False Positive,FP):负样本被检测为正样本的数量,也称误报,预测的 Bounding Box 与 Ground Truth 的 IoU 小于阈值的检测框(定位错误)或者预测的类型与标签类型不匹配(分类错误)。

错误的负向预测(False Negative,FN):正样本没被检测为负样本的数量,也称漏报,指没有检测出的 Ground Truth 区域。

正确的负向预测(True Negative,TN):是负样本且被检测出的数量,无法计算,在目标检测中,通常也不关注 TN。

交并比(IoU)

交并比 (Intersection over Union,IoU) 又称交并比,计算 2 个区域的重叠比,用 2 个区域的交集除以其并集,公式如下,DR 表示检测结果,GT 表示 Ground Truth。


以下是 IoU 的示意图:

图 1:IoU示意图

目标检测中的 IoU 是矩形框计算,计算并集部分通过 2 个计算区域的面积减去交集部分即可,重叠情况如下图所示:

图 2:重叠情况

在计算重叠区域面积是在找其中计算区域的 min、max 关系,用  表示重叠区域宽度,用  表示重叠区域高度, 选择传入参数中较小值, 选择传入参数中较大值,通过计算得到重叠区域的宽与高,关系如下:




代码实现如下:

'''
dr_box  [xmin,ymin,xmax,ymax]
gt_box  [xmin,ymin,xmax,ymax]
'''

def iou(dr_box,gt_box):
    union_height = min(dr_box[2], gt_box[2]) - max(dr_box[0], gt_box[0])
    union_width = min(dr_box[3], gt_box[3]) - max(dr_box[1], gt_box[1])
    inter = 0 if union_height<0 or union_width<0 else union_height*union_width
    union = (dr_box[2] - dr_box[0]) * (dr_box[3] - dr_box[1]) + \
            (gt_box[2] - gt_box[0]) * (gt_box[3] - gt_box[1]) - inter
    iou = inter / union
    return iou

准确率(Precision)

准确度 (Percision) 也叫查准率,是在识别出的物体中,正确的正向预测 (True Positive,TP) 所占的比率。



 代表一共识别出的物体数量,例如下图 3 所示口罩人脸检测的一个效果图,图中 9 个检测框,7 个正确检测出口罩,,2 个未正确检测出口罩,,参照公式 

图3:人脸口罩示例

召回率 (Recall)

召回率 (Recall),是正确识别出的物体占总物体数的比率。



 表示一共有多少个需要检测的物体,继续参照图 3,图中一共 8 个带着口罩的目标,其中 7 个正确检测出口罩,,1 个未检测出口罩,,参照公式得出 

几何平均分(F Score)

Precision 与 Recall 看起来很相似,实际上这两个是“冤家”。为什么这么说呢?因为在大多数情况下,这两者有一定的互斥性。

理想状态下,模型可以检测出所有要检测的物体,并且没有误报,两个指标都是 100%,实际中不太可能出现。

模型检测出的检测框有一个分类类别和相应的置信度,在稍微复杂的场景下,并不是所有要检测的物体的置信度都很高,或者都能检测出来,也不是所有检测出的全部物体是我们所想要的目标。图 4 展示了 Precision 与 Recall 的关系,随着 Recall 的提高,Precision 值降低了。

图 4:Precision 与 Recall 的关系

接下来用一个例子说明 Precision 与 Recall 的关系,有一个物体检测结果,一个图里的检测出的物体按照置信度倒叙排列进行编号。

按照顺序逐个计算 Precision 及 Recall 值,相当于逐渐在降低阈值(threshold),其结果如下方表格所示。

图5:物体检测结果

Precision 与 Recall 单独拿出来作为评价标准都太过片面,可以设置一个较大的阈值来获取高 Precision 或者通过设置个较低的阈值来获得较高的 Recall 值。我们还是希望有一个数能够衡量性能,所以综合 Precision 和 Recall,可以得到一个 F Score,计算公式如下:



F Score 是 Precision 和 Recall 的调和平均数 (harmonic mean),B 的作用是个权重,调整 P 与 R 的比重关系。平均数很好理解,加权平均也不复杂,那“调和”是什么意思呢?调和平均数(harmonic mean)有个特点,Precision 与 Recall 其中有一个值较小,那么整体就会很小,也就是对两个数中如果有特别小的数的惩罚(penalty)比较大。

在论文中,经常可以看到用 F1 值作为评价标准之一,将 B 设置成 1,这就是 F1 Score。

单类平均准确率(Average-Precision)

平均准确度 (Average Precision,AP) 是非常流行的目标检测器 (目标检测算法模型) 的度量指标,从字面上来看 AP 是平均精准度,对于单独的追求 Precision 的数值并不能很好的衡量模型的效果,所以 AP 的计算方式并不是简单的求平均的过程。

在下图中的 Precision 呈现 ”Z“ 形状,随着 TP 增加,FP 减少。

图6:Precision-Recall plot曲线

一般定义 AP 为 PR 曲线之下的面积,公式如下:

Precision 与 Recall 的值域在 0 到 1 之间,所以 AP 的值域也是在 [0, 1] 这个范围。知道了 AP 的值域还有定义,在计算前还有个棘手的问题,这里的 P(r) 并不是一个具体的函数,而是根据样本进行计算,是一个数值,在图中是一个点,可以描绘成折线图。

请看图 6 中,在 Recall = 0.7 的时候,Precision 的值是多少?这样的一个问题我们是没办法简单的用插值的形式来进行求解的,同样的我们也没法用函数计算的方式去解决,所以前人就提出一种差值方法:给任意一个 Recall 值,它对应的 Precision 值就等于它最近的右侧的哪个“有值” Precision 中最大的值。

举个例子,以图 6 中的 PR 曲线,Recall = 0.7 的点, Precision 取值为 0.67,求 AP 的过程中,在计算之前,我们需要对图像中的 “Z” 部分做个“平滑”处理,如图所示:

图7:smooth Precision-Recall plot

我们将每个 Precision 值替换为该 Recall 值右侧的 Precision 值,这么说比较拗口,看图中红线部分,Precision-Recall 曲线变成了单调减小,不再是之前的 "Z" 形变化。这时候计算出的 AP 值将不太容易受到排名的微小变化的影响。公式变成如下:

Pascal VOC 2008 中设置 IoU 的阈值为0.5,在平滑处理的 PR 曲线上,图 7 中取横轴 0.2-1 的 9 等分点(0.2、0.3、0.4、0.5、0.6、0.7、0.8、0.9、1.0)的 Precision 的值,计算其平均值为最终 AP 的值。


上述计算有两个问题,第一个是使用 9 个采样点在精度方面会有损失。第二个是,在比较两个 AP 值较小的模型时,很难体现出两者的差别。

所以这种方法在 2009 年的 Pascal VOC 之后便不再采用了。在 Pascal VOC 2010 之后,便开始采用这种精度更高的方式。绘制出平滑后的 PR 曲线后,用积分的方式计算平滑曲线下方的面积作为最终的 AP 值,理解为经过插值的 PR 曲线与 X 轴包围的面积,这种方式也称为:AUC (Area under curve)。

上图可知,AP = A1 + A2 + A3,具体计算如下:


mAP (mean Average Precision) 是在每一个类别都计算出 AP 后再计算 AP 的平均值,接下来用代码实现。

代码实现 mAP

这部分学习用代码实现 Pascal mAP 的计算,下面给出最核心的代码。第一部分计算 IoU 和 TP、FP。

# image_ids为列表类型,存放图片数据id,也就是图片名称
# 这里得到的列表并不是全部的训练图片,而是要计算的分类(class)对应的训练图片
nd = len(image_ids)
# 初始化TP与FP
tp = np.zeros(nd)
fp = np.zeros(nd)
# 逐个遍历每个结果
for d in range(nd):
    R = class_recs[image_ids[d]]
    # 预测的Bounding Box信息
    bb = BB[d, :].astype(float)
    # 最大IoU,初始化为极小值
    ovmax = -np.inf
    # GroundTruth Bounding Box
    BBGT = R['bbox'].astype(float)

    if BBGT.size > 0:
        # 通过计算相交顶点来计算相交区域面积
        ixmin = np.maximum(BBGT[:, 0], bb[0])
        iymin = np.maximum(BBGT[:, 1], bb[1])
        ixmax = np.minimum(BBGT[:, 2], bb[2])
        iymax = np.minimum(BBGT[:, 3], bb[3])
        iw = np.maximum(ixmax - ixmin + 1.0.)
        ih = np.maximum(iymax - iymin + 1.0.)
        inters = iw * ih

        # 计算2个矩形面积减去相交面积得到总面积
        uni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +
                (BBGT[:, 2] - BBGT[:, 0] + 1.) *
                (BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)
        # 计算IoU并找到最大的IoU
        overlaps = inters / uni
        ovmax = np.max(overlaps)
        jmax = np.argmax(overlaps)
    # 根据阈值来判断是TP还是FP
    if ovmax > ovthresh:
        if not R['difficult'][jmax]:
            if not R['det'][jmax]:
                tp[d] = 1.
                R['det'][jmax] = 1
            else:
                fp[d] = 1.
     else:
        fp[d] = 1.

有了上面的内容,就可以进行 Precision 与 Recall 的计算。

# 计算FP的数量
fp = np.cumsum(fp)
# 计算TP的数量
tp = np.cumsum(tp)
# npos表示样本数量,根据公式求得recall值
rec = tp / float(npos)
# 根据公式求Precision值,为了防止出现数值问题,这里做了下容错
prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)

有了 Recall 与 Precision 的值,可以通过绘制 Precision-Recall plot 并计算其面积得到 AP 值。

def voc_ap(rec, prec):
    # correct AP calculation
    # first append sentinel values at the end
    mrec = np.concatenate(([0.], rec, [1.]))
    mpre = np.concatenate(([0.], prec, [0.]))

    # 为求得曲线面积,对 Precision-Recall plot进行“平滑”处理
    for i in range(mpre.size - 10-1):
        mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])

    # 找到 recall值变化的位置
    i = np.where(mrec[1:] != mrec[:-1])[0]

    # recall值乘以相对应的 precision 值相加得到面积
    ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
    return ap

今天先分享到这里了,祝你有所进步~


本文仅做学术分享,如有侵权,请联系删文。

—THE END—

文章有问题?点此查看未经处理的缓存