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

学习目标检测一定少不了的评测方式, 就是透过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中预测为正确的
也就是 T P T P + F N \frac{TP}{TP+FN} TP+FNTP , 对应图片的蓝框公式很直观, 就是所有的ground truth(所有测试集中的样本每张图片上的人 或者 汽车的总数)里面检测出人 或者 汽车的数量

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

Precisions

可以叫做精准率, 就是你检测到结果里面, 实际上真的正确的为多少? T P T P + F P \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、付费专栏及课程。

余额充值