指标:mAP
mAP 是目标检测、重识别等领域的重要指标。计算 mAP 的关键是计算 AP,而计算 AP 关键的是 TP, FP, FN 的定义,如果我们能够将一个输出序列标注为 TP, FN,并且得到它们的置信度,那么剩余的其实直接套公式计算即可。
Recall/Precision 的计算
1. TP/FP/TN/FN的定义
首先我们要知道 T/F, P/N 的定义:
- Positive or Negative: 表示分类给出的结果
- True or False: 表示分类结果是否正确
那么组合以下:
- TP: True Positive;
- FP: False Positive;
- TN: True Negative;
- FN: False Negative; 表示分为负样本,但是分错的样本 => 真实值为正样本
所以易得 Precision 和 Recall 的公式:
通俗地说:
- Recall: 真实的样本被分对了多少
- Precision: 分类的结果中有多少是对的
多分类情况下,对各类,recall 选出真实值为第 i 类的样本,输出 accuracy,precision 选出预测结果为第 i 类的样本,输出 accuracy。
计算:
1 | import numpy as np |
AP/mAP
- AP: 仅在二分类下使用,表示 Precision-Recall(P-R)曲线下的面积
- mAP: 多分类下使用,每类的 AP 的平均
二分类情况下AP:
理论计算
给定 ground truth: ,模型预测的概率为 ,调整 threshold 可以得到不同的 precision/recall,构成 P-R 曲线,计算曲线下的面积即为 AP。
理解:precision, recall 仅针对正类,根据 precision 和 recall 的公式:
- recall 的分母和预测的结果无关,是定值,所以当 threshold 降低时,TP 的数量是非严格单调递增的,所以 recall 也是非严格单调递增的。特别的,当
threshold=1
时,recall=0
,当threshold=0
时,recall=1
。 - precision 的分母和分子都和预测结果有关,所以值是波动的,特别的,当
TP+FP=0
时,规定precision = 1
。
实际计算
计算
可以用 scikit 的 sklearn.metrics.average_precision_score 计算 AP,输入为 y_true
, y_pred
。
1 | import numpy as np |
深入实际计算
- 如果我们有 (precision, recall) 对,计算 AP:
实际上 average_precision_score
不进行插值计算面积,而是采用以下的公式:
其中 是不同 thresholds 下得到的 P-R 对(并且按 recall 的升序排列),相当于计算多个矩形的面积,而且矩形的高是右边的数值(如果用左边的话会感觉虚高)。 而且从公式中可以看成是 precisions 的加权平均。
1 | # 假设已有 precisions 和 recalls |
- 更加快速的计算方式:
如何得到 precision 和 recall 对? 一种广泛使用的方法是将阈值直接取为 y_pred
,而且 y_pred
从大到小排序,每次得到一对 precision 和 recall,这种方法可以很更快地计算 TP, FP 等值。
如下表:是一个向下累加的过程:
y_pred | y_true | threshold | TP | FP | TP + FP | FN + TP | recall | precision |
---|---|---|---|---|---|---|---|---|
0.98255475 | 0 | 0.98255475 | 0 | 1 | 1 | 2 | 0 | 0 |
0.96782305 | 0 | 0.96782305 | 0 | 2 | 2 | 2 | 0 | 0 |
0.95248108 | 1 | 0.95248108 | 1 | 2 | 3 | 2 | 0.33 | 0.5 |
0.94590941 | 1 | 0.94590941 | 2 | 2 | 4 | 2 | 0.5 | 1 |
0.90657107 | 0 | 0.90657107 | 2 | 3 | 5 | 2 | 0.4 | 1 |
随着阈值从大到小被取为不同的 y_pred
:
- TP 其实就是
y_true
的累加值 - TP + FP 其实就是当前阈值下所有预测结果为 1 的样本数量,也就是表格中阈值以上的所有样本的数量,就是 1,2,3, …
TP + FN
就是y_true
的和,表示所有真实值为 1 的样本个数,是不变的- 最后我们还需要添加
threshold=1
的情况(并不在上面表格中),此时 precsion, recall 为 (1, 0)。
完整代码即为:
1 | import numpy as np |
在不同任务下的 AP 计算可以采用相似的办法,不同点在于 TP, FP 怎么取。
mAP
mAP (mean Average Precision),顾名思义,就是 AP 的平均。在多分类任务下,我们对每个类别计算一个 AP 值,然后取平均,得到 mAP。
假设我们得到的输出为矩阵 ,N 表示样本个数,C 表示类别个数, 表示为第 个样本被分为第 类的置信度。
- 首先根据置信度,我们根据每个样本的置信度将它分类为置信度最高的那一类,并得到相应的置信度。
- 对单个类别计算 AP,我们仅针对所有被模型分为该类的样本,
y_pred
就是每个样本的置信度,而y_true
就是该样本是否被正确分类。带入average_precision_score
即可得到。
见以下代码:
1 | import numpy as np |
其他任务下的 AP/mAP
Detection下的AP/mAP
mAP 计算输入:
- 模型输出 boxes + pred_logits(N 类),选取 confidence 最高的那类,得到 boxes + confidence + pred_classes
- ground truth: 每个 gt 框的 gt_boxes + gt_classes
计算过程:
-
首先对单个 class i 计算 AP:
- 筛选出每个 image 中 pred_classes 为 i 的数据: cls_dets
- 筛选出每个 image 中 gt_classes 为 i 的数据: cls_gts
-
对每张 image 进行 TP/FP 的分配:
- 如果 gt 框的数量为 0,那么所有的 det 都分配为 FP(当然 det 的数量也可能为 0,那就什么都没有)。
- 计算所有 gt_boxes 和 det_boxes 的 iou,得到 iou 的矩阵(MxN, M 为 det_boxes 的数量,N 对应 gt_boxes)
- 对每个 det_boxes,选取和它最重叠的 gt_boxes ,得到两两的 pairs,进入下面的分配。
- 按照 confidence 从大到小排序 det_boxes
- 对每个 det_boxes,如果:
- 和 gt_boxes 的 iou 大于 iou_thresh: 如果 gt_boxes 已经在之前被匹配,那么标记为 fp,否则标记为 tp。
-
得到所有的 tp 和 fp,以及每个 boxes 的 confidence,各 concat 成一个向量。按照 confidence 从大到小的顺序排序 tp 和 fp,然后按照累加和的计算公式计算 tp 和 fp。
1 | precisions = tp / (tp + fp) |
- 计算 ap,然后计算 mAP。
除此之外,可能需要考虑的其他问题:
- 规定 iou_thresh 如果小于某个值
min_area
,对它忽略,因为可能检测到未标记的 gt 样本。 - 计算 recalls 和 precisions 需要注意分母需要 eps。
- 等等
根据以上思路的简单样例代码
ReID下的mAP
ReID 下的 mAP 比较好理解,计算也更简单:就是对每个 probe,计算 AP,最后再对所有 probe 取平均。
单个 probe 的 AP 计算:首先根据 ground truth,可以得到每个 gallery 的 gt_label 作为y_true
,其次 gallery 和 probe 的 feature 计算相似度,得到预测概率作为 y_pred
,就可以用于计算 AP。
Person Search 下的 mAP
Person Search 下的 mAP 其实和 ReID 的指标非常类似,因为 mAP 在 Person Search 中也是用于衡量搜索的好坏。唯一不同是TP 的定义上还要考虑定位准不准。简单来说,在 Person Search 中,对一个 probe target,在一张 gallery 图像中,首先按照相似度将该图像内的所有 candidate persons 排序,然后按照相似度从大到小的第一个和 gt boxes IoU 大于给定阈值(0.5)的 person 作为 TP,取它的相似度作为置信度分数,其余的都作为 FP。
mAP 涨点
从 AP/mAP 的定义就可以看出,实际上 AP/mAP 不关心最终的置信度是多少,而关心样本置信度的相对大小( recall threshold 从大取到小),我把这个样本的排列称为 rank_list
。AP 涨点的关键就是要使得 TP 尽可能地排在 rank_list
的前面,当所有的 TP 都排在最前面时,AP 就可以达到最大值 1 。