用商汤的mmdetection 学习目标检测中的 Recalls, Precisions, AP, mAP 算法 Part1

本文深入解析目标检测评估指标,如recall、precision及mAP的计算方法。通过实例演示混淆矩阵的作用,详细介绍如何利用mmdetection代码计算各类别AP,帮助读者理解目标检测模型的性能评估。

学习目标检测一定少不了的评测方式, 就是透过recalls, precisions, 来计算出类别的AP, 以及最后所有AP的平均值 mAP(mean Average Precision) 也就是我们最关心的数值

这边先简单的了解一下confusion matrix, 也就是所谓的混肴矩阵, 我个人不觉得这是一个很好的翻译, 最好记得英文就行, 在分类任务中这是一个非常重要的评测指标

下图是一个基本的confusion matrix
在这里插入图片描述
下面我直接带入例子会比较好解释

假设你的数据集一共是2分类, 第一类是人, 第二类是汽车
而测试集只有两张图片

Actual Value and Predicted Value

Actual value :实际的值, 在目标检测领域中, 我们可以理解为ground truth, 就是人或者是汽车在图片上的真实坐标

predicted value:这个就很好理解了, 就是指我们模型预测出来的坐标

pos 和 neg 这边不先定义, 我讲下去你就知道了

TP FP FN TN

这里通常很容易被弄混, 难怪叫做混肴矩阵, 跟着我的步伐走就没问题,强烈建议拿出纸笔把矩阵画一次就清楚了

  • TP (TruePositive): 正确预测出类别的 (正确识别为人或是汽车)
  • FP (FalsePositive):错误预测类别的 (人当成汽车)
  • FN(FalseNegative): ground truth中没有被检测到的
  • TN(TrueNegative):理论上来讲就是检测出不是这个类别的数量, 但是并不适用在目标检测领域, 因为通常一张图后会有非常多的bbox是没有检测到groundtruth的, 所以这无法计算, 并不影响, 因为也用不上

Recalls and Precisions

Recalls

可以叫做查全率又或者是召回率, 可以当做是所有类别x中预测为正确的
也就是 TPTP+FN\frac{TP}{TP+FN}TP+FNTP , 对应图片的蓝框公式很直观, 就是所有的ground truth(所有测试集中的样本每张图片上的人 或者 汽车的总数)里面检测出人 或者 汽车的数量

比如图中有5个标注为汽车的ground truth, 那么你检测到的汽车有两个, 那么对于这张图, 汽车类的 recalls 就是 2/5

Precisions

可以叫做精准率, 就是你检测到结果里面, 实际上真的正确的为多少?TPTP+FP\frac{TP}{TP+FP}TP+FPTP
TP就是检测正确的, FP就是检测错误的, 那么加起来不就是你所有检测的结果? 对应图中红框

比如图中有3个人的ground truth, 你检测到的也是三个框, 但是其中只有一个框检测吻合到你的ground truth,另外两个检测成人了, TP = 1, FP = 2, 那么precision 就是 1/3

到这边如果没明白就先理清楚在往下看吧

首先来用mmdetection 的检测代码mean_ap.py来说明会更清晰
我不打算放出全部代码, 这样太乱了 我们看最主要的部分加深印象就行 !

首先看到eval_map这个函数, 看名字就很直观 evaluation mAP

def eval_map(det_results,
             gt_bboxes,
             gt_labels,
             gt_ignore=None,
             scale_ranges=None,
             iou_thr=0.5,
             dataset=None,
             print_summary=True):

说几个重要的参数就好

  1. det_results 就是检测到的结果
  2. gt_bboxes 就是ground truth 的框
  3. gt_labels 就是类别标签, 比如人是1, 汽车是2
  4. gt_ignore 这如果没有标注difficulty 不用理会
  5. iou_thr 就是检测出的和groud truth 的 iou 阈值

也就是说如果要检测出recall precision mAP这些指标, 就要以上这些重要的值

那么计算recall precision 之前 我们就得先算出 TP FP FN 这些重要的指标, 所有一开始的矩阵是不是很重要?

函数tpfp_default 就是负责计算出TP FP的
我们需要以下参数, 注意该函数是针对单张图像的

def tpfp_default(det_bboxes, 
				gt_bboxes, 
				gt_ignore, 
				iou_thr, 
				area_ranges=None):

我们的训练集只有两张
如果人label = 1, 汽车label=2, 下面直接用vector表示

  1. 第一张图label = [1, 1, 2, 1, 1] 也就是说有四个人一台车, 一共五个ground truth
  2. 第二张图 label = [2, 2, 1, 2] 三台车 一个人的ground truth

搬出ground truth

ground truth 最后面的#1 or #2表示label
#groubd
gt_bbox1 = np.array([[358, 288, 498, 387], #1
                    [356, 425, 525, 570], #1
                    [377, 119, 478, 189], #2
                    [180, 68, 314, 142], #1
                    [417, 159, 575, 240]], dtype=np.float32)#1

gt_bbox2 = np.array([[258, 188, 398, 287], #2
                     [256, 325, 425, 470], #2
                     [277, 19, 378, 89], #1
                     [280, 168, 414, 242]], dtype=np.float32)#2

然后我们检测到的结果是下面这样, 都是bbox的坐标值, 一共两张图片, 图上都会有每个检测到的类别的坐标

检测到的结果 det_results
'''det_results 图片 _ 类别'''
det_results1_1 = np.array([[359, 289, 499, 388], 
                    [346, 415, 515, 560], 
                    [367, 109, 468, 179], 
                    [190, 78, 324, 152], 
                        [430, 172, 588, 253]], dtype=np.float32)

det_results1_2 = np.array([[259, 189, 399, 288],
                        [236, 315, 415, 440], 
                        [267, 9, 368, 79],
                        [290, 178, 424, 252]], dtype=np.float32) 
                        
det_results2_1 = np.array([[359, 289, 499, 388],  
                    [346, 415, 515, 560], 
                    [367, 109, 468, 179], 
                    [190, 78, 324, 152],
                        [430, 172, 588, 253], 
                          [230, 72, 388, 53]], dtype=np.float32)

det_results2_2 = np.array([[259, 189, 399, 288], 
                        [236, 315, 415, 440], 
                        [267, 9, 368, 79], 
                        [290, 178, 424, 252],
                          [159, 89, 299, 188]], dtype=np.float32) #not ok

可以看出det_result1_1 表示第一张图的label 1 检测到的框
那么det_result2_2 就表示第二张图检测到label 2的框
所以可以总结

label1 一共检测出11个(TP+FP)
label2 一共检测出 9 个 (TP+FP)

好了, 回到tpfp_default
为了要检查出模型检测的是不是正确的, 也就是TP, 我们就用到了iou_thr这个阈值
一般会是0.5, 那么还要计算出IOU(交并比), 什么是IOU请直走左转找到人就问, 如果连这都写, 篇幅会太长

透过以下的函数进行计算

ious = bbox_overlaps(det_bboxes, gt_bboxes)

得出来的ious会长这样子

#这是label 1的第一张图检测与gt的ious结果
 [[0.9665272  0.         0.         0.        ]
 [0.         0.7804878  0.         0.        ]
 [0.         0.         0.         0.05691057]
 [0.         0.         0.6701031  0.        ]
 [0.         0.         0.         0.6295463 ]]
 
#这是label1 的第二张图检测与gt的结果
 [[0.        ]
 [0.        ]
 [0.        ]
 [0.03430409]
 [0.        ]
 [0.        ]]
#这是label 2的第一张图检测与gt的ious结果
 [[0.00107885]
 [0.        ]
 [0.        ]
 [0.03430409]]
 
 #这是label 2的第二张图检测与gt的ious结果
 [[0.9665272  0.         0.36517328]
 [0.         0.6413269  0.        ]
 [0.         0.         0.        ]
 [0.41336057 0.         0.6701031 ]
 [0.00149158 0.         0.01764335]]

一脸懵?
没事的, 我刚看到也是懵

label1 图1 检测到的不是五个bbox吗 那么拿去和gt计算 就会有五个分数了
那图2 检测到的6个bbox 也当然就有6个分数了

不要太注意shape不同, 只要注意分数就好
很明显的模型在检测 label1 的时候, 在图1的表现好很多 !我们发现到
[0. 0. 0. 0.05691057] 这行分数很低接近于0,因为图1的label是[1, 1, 2, 1, 1]
在第三个值是label 2, 所以算出来的IOU几乎为0, 因为并不属于label1的

在来看到label2 的iou

#这是label 2的第一张图检测与gt的ious结果
 [[0.00107885]
 [0.        ]
 [0.        ]
 [0.03430409]]

分数基本都趋近于0, 就表示模型在图1 完全没找到什么都没检测到
你可以比较一下det_result1_2的坐标和gt_bbox1的坐标就很清楚了, 坐标完全没重合的感觉

如此一来我们就有了label1 和 label2 所有检测到的框和ground truth的 IOU值了
得到了IOU在透过一开始给的iou_thr 阈值, 不就能筛选出谁是TP 谁是 FP了吗?

来, 咱们在复习一次 , 跟着我大声念!

检测大于阈值的叫做TP(TruePositive)
低于阈值的也就是错误的叫做FP (FalsePositive)

喝口水继续
我们将刚刚的ious 进行整理

ious_max = ious.max(axis=1)
ious_argmax = ious.argmax(axis=1)

输出会是下面这个样子, 是不是, 说shape先别在意的 !反正都会变这个样子

ious_max [0.9665272 0.7804878 0.05691057 0.6701031 0.6295463 ]
ious_argmax [0 1 3 2 3]

接下来就是透过阈值筛选, 过程代码比较多, 不全写出来

if ious_max[i] >= iou_thr:
     matched_gt = ious_argmax[i]

tpfp_default函数输出就会是像这样
tp: [[1. 1. 0. 1. 1.]]
fp: [[0. 0. 1. 0. 0.]]

是不是一目了然? 也能够对应到分数?iou高说明检测正确并且归纳在TP 用1表示
而分数低的自然就是FP了 用0表示

拿到了TP FP 就离我们的recalls 和 precisions 不远了啊 !

好了 这只是上半场
由于篇幅的关系 我临时决定分成两章来写完

说老实话, 这要是一篇文章能解决我也是佩服佩服

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值