1. TP, FP, FN, TN
True Positive
满足以下三个条件被看做是TP
1. 置信度大于阈值(类别有阈值,IoU判断这个bouding box是否合适也有阈值)
2. 预测类型与标签类型相匹配(类别预测对了)
3. 预测的Bouding Box和Ground Truth的IoU大于阈值(框 打对了)。 当存在多个满足条件的预选框,则选择置信度最大的作为TP,其余的作为FP
False Positive
1. 预测的 类别 和 真实的标签类型不匹配(分类错误)
2. 预测的Bounding box和Ground Truth的IoU小于阈值(框 打的不是那么好, 定位错误)
False Negative
分类争取,定位正确,但是被检测成了负样本
True Negative
负样本被检测出的数量,太多了,绝大多数的框都是这个类型。后面计算precision和recall的时候用不到,所以这个东西也就不统计数量了。
2. Precision和Recall
Precision = TP/(TP+FP) = TP/(所有被我判定为正例的个数)
Recall = TP/(TP+FN) = TP/(所有世界是正例的个数)
3. PR曲线
Precision-Recall曲线是根据阈值 从0到1这个区间的变动,每个阈值下模型的precision和recall的值分别作为纵坐标和横坐标来连线绘制而成的。(每个阈值θ对应于一个(Precision,Recall)点,把这些点连起来就是PR曲线)
比如假设我们收集了20个sample的数据,他们的真实标签和置信度如下
此时我们为了绘制PR曲线,计算出了PR曲线上下面这些点的坐标
阈值=0.9——TP=len([ #1, ]) = 1; FP=0; FN=len([#2, #4, #5, #6, #9, #11, #13, # 17, #19])=9——Precision=TP/(TP+FP)=1/(1+0)=1——Recall=TP/(TP+FN)=1/(1+9)= 0.1
阈值0.8——TP=len([#1,#2])=2; FP=0; FN=len([#4, #5, #6, #9, #11, #13, # 17, #19])=8——Precision=2/(2+0)=1; Recall=2/(2+8)=0.2
阈值0.7——TP=len([#1,#2])=2; FP=len([#3])=1, #_of_True=10 ——Precision=2/(2+1)=0.67;Recall=2/10=0.2
阈值0.6——TP=len([#1, #2,#4])=3; FP=len([#3])=1, #_of_True=10——Precision=3/(3+1)=0.75; Recall = 3/10=0.3
阈值0.5——TP=len([#1, #2, #4, #5, #6, #9])=6; FP=len([#3, #7, #8, #10])=4,#_of_True=10——Precision=6/(6+4)=0.6; Recall = 6/10=0.6
阈值0.4——TP=len([#1, #2,#4, #5, #6, #9, #11])=7; FP=len([#3, #7, #8, #10])=4, #_of_True=10——Precision=7/(7+4)=0.64; Recall = 7/10=0.7
阈值0.3——TP=len([#1, #2,#4, #5, #6, #9, #11, #13, #17, #19])=10;FP=len([#3, #7, #8, #10, #12, #14, #15, #16, #18])=9; #_of_True=10; ——Precision=10/(10+9)=0.53; Recall = 10/10=1
用sklearn的下面这段代码就可以计算出答案
import numpy as np
from sklearn.metrics import precision_recall_curve
# 导入数据
y_true = np.array([1,1,0,1,1,1,0,0,1,0,1,0,1,0,0,0,1,0,1,0])
y_scores = np.array([0.9,0.8,0.7,0.6,0.55,0.54, 0.53,0.52,0.51,0.505, 0.4, 0.39,0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
# 计算出每个阈值下,precision和recall的值
precision, recall, thresholds = precision_recall_curve(y_true, y_scores)
# 写上这两行,中间的列就不会被用省略号省略,都显示出来
pd.options.display.max_rows = None
pd.options.display.max_columns = None
#整理成横向的dataframe,方便大家查看
precision = pd.DataFrame(precision).T
recall = pd.DataFrame(recall).T
thresholds= pd.DataFrame(thresholds).T
#纵向拼接
results = pd.concat([thresholds, recall,precision], axis=0)
# 仅仅保留2位小数
results = round(results, 2)
#行名改一下
results.index = ["thresholds", "recall", "precision"]
print(results)
绘制出来的precision-recall曲线是下面这样
import matplotlib.pyplot as plt
def plot_pr_curve(recall, precision):
plt.plot(recall, precision, label='Precision-Recall curve')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('PR Curve')
plt.legend()
plot_pr_curve(recall, precision)
对于PR图中这种类似锯齿状的图形,我们一般采用平滑锯齿的操作。所谓平滑锯齿操作就是在Recall轴上,对于每个阈值θ计算出的Recall点,看看它的右侧(包含它自己)谁的Precision最大,然后这个区间都使用这个Precision值,在下图这个例子中,Recall=(0,0.4] 都使用 Precision=1, Recall=(0.4,0.8] 都使用 Precision=0.57, Recall=(0.8,1) 都使用 Precision=0.5
因此我们这个例子中的图形经过锯齿平滑化以后应该是下面这个样子
Precision和Recall之间的此消彼长的矛盾关系
上图的右下角,recall高,说明所有所有的杀人犯中99%的都被抓住了,那就会造成一个结果,抓的人特别多。和这桩杀人案有一丁点关系的人都被逮捕了。这必然导致,所有被抓的人中,实际是罪犯的比例变得很低,也就是precision低。
OK,如果你希望Police抓的人中,实际是罪犯的比例高一些,(也就是precision高一些)。那Police就不敢乱抓人了,没有十足的证据就不敢去逮人。那结果是啥?那就是大量隐藏额的很好的罪犯都被漏掉了,也就是说所有的罪犯中实际被抓住的比例降低了。也就是recall低了。这种情形对应的就是上图左上角的那个位置。
如何评估一个不同模型的好坏关系
既然一个模型的precision和recall是此消彼长的关系,不可能两个同时大,那怎么判断哪个模型更优呢?答案是,P-R曲线越往右上角凸起的曲线对应的模型越优秀。正如上图中红线A和黑线B都是比模型C要优秀的
但是问题来了,模型A和模型B之间,孰优孰劣呢?那就引出了平衡点("Balanced Error Point" (BEP))这个概念。平衡点就是曲线上的Precision值=Recall值的那个点,也就是上图中那三个点,平衡点的坐标越大,模型越好。
除了平衡点,也可以用F1 score来评估。F1 = 2 * P * R /( P + R )。F1-score综合考虑了P值和R值,是精准率和召回率的调和平均值, 同样,F1值越大,我们可以认为该学习器的性能较好。
4. 从PR曲线到AP
AP的公式如下
AP这个指标的实际意义:
AP是,在“”阈值不同“”引发的“Recall值不同”的情况下,各种Precision值的均值。AP summarizes a precision-recall curve as the weighted mean of precisions achieved at each threshold, with the increase in recall from the previous threshold used as the weight:
AP值可以理解为PR曲线向下、向左到X轴和Y轴这片面积之和
这个阈值到前一个阈值之间的差是长方形的宽,precision值是长方形的高。宽乘以高就是长方形柱子的面积。
AP这就是P-R曲线的积分,也就是面积
用sklearn的公式这样算
from sklearn.metrics import average_precision_score
AP = average_precision_score(y_true, y_scores, average='macro', pos_label=1, sample_weight=None)
print(AP)
# 0.7357475805927818
AP=(0.2-0)× 1 + (0.5-0.2)× 0.83 + (0.6-0.5) × 0.67 + (0.7-0.6)×0.64 +(0.8-0.7)×0.62 +(1-0.8)×0.53=0.7480
和上面那个程序算出来来的有0.1的误差,但是大体区别不大就不去追究是哪个小地方算错了
5. 从AP到mAP
把各个类别(比如汽车、行人、巴士、自行车)的AP值取平均
6. 从mAP到 mAP50, mAP75, mAP95
mAP中也有个阈值, mAP50这个也有IoU阈值,这两个阈值之间是什么关系?有哪些区别
mAP里面那个阈值,是指的分类问题上的阈值(即判断这个目标是人还是汽车还是摩托车 这个分类),如拿着预测某个类别(如:汽车)的置信度 和这个IoU阈值比较,如果置信度大于阈值,则predicted label是True;反之如果predicted confidence低于这个IoU阈值,则predicted label是False
mAP50里面这个IoU指的是定位(打bouding box识别框) 里面 这个定位问题的阈值。 判断predicted bbox和ground truth bbox之间的IoU大于 这个IoU阈值 才能被算作 定位上的True。反之,如果predicted bbox和ground truth bbox之间的IoU 小于 这个IoU阈值 定位上 这两个框之间的匹配关系 就是False
在mAP50里面,这个阈值是针对 定位问题的 交并比(IoU) 的。mAP中的阈值是针对分类问题的。
所以这里的mAP50, mAP75, mAP95里面这些50、75、95是针对 定位的bouding box而言的,阈值分别为0.50、0.75、0.95。
我们在目标检测中常说的mAP实际指的是mAP50-95。这个mAP50-95是mAP阈值为50%到mAP阈值为95,间隔5%,取得10个mAP值,然后对这十个值取平均。后面是这10个IoU阈值[0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95]
mAP50的阈值最低,要求最宽松,因此一般用于人脸识别的性能评估
mAP80到mAP95,要求比较严格,因此多用于一些对准确性和安全性要求比较高的陈景中如自动驾驶
7. 目标检测中mAP50-95是如何计算得出的
Step1 拿到原始数据
定位数据(bouding box)
真实标签 truth label
下面这个矩阵是一张图片的数据
第一列数据,t代表 truth,表示有真实标签中有N个,一行就是一条真实的标注
第二列表示是的是这一个方框里面的object 的 真实类别
第三列和第四列是, 真实的bouding box 左下角点的横坐标 和 纵坐标
第五列和第六列是,真实bouding box右上角点的横坐标和纵坐标
通过这这些数据,图片中的N个object的位置和类别就都表示出来了
你的模型预测的标签 predicted label
这里仍然是一张照片上所有的bouding box的数据和对object类别的分类结果
与true label不同的是,这里的第三列 score是true label所没有的。这就是对于一条数据所框处的这个object属于这个类别的置信度
ground truth对这张图片打了N个方框,predicted 对这张图片打了M个方框。
Step2 定位 构建IoU_mask
这一步专注在定位(打方框)这里
Step2.1 计算真实框和预测框之间的IoU交并比
计算N个真实框和这M个预测边界框之间的IoU值,共有N×M个匹配的IoU值
Step2.2 根据mAP设定的 IoU 阈值来每个预测框和每个真实框 之间的True或False
假定你的mAP是mAP50,那么IoU阈值就是0.5,上面所有的IoU值 只要大于0.5这个阈值,就会变成True,反之就是False。
iou_mask = (iou_between_target_and_pred > 0.5)
也就是说根据你设定的IoU不同,比如说mAP75, mAP95,同样的IoU值就可能从True变成False或者反过来。因此,不同IoU阈值,下面这掩码矩阵mask matrix都是有些许不同的。
需要注意:
- 一个预测框可能与多个真实框的 IOU 都大于等于 0.5,比如第一列
- 一个真实框可能与多个预测框的 IOU 都大于等于 0.5,比如第一行
Step3 分类 构建cls_mask
正如前文讲的mAP是一个分类的评估指标,是Precision-Recall曲线下和X轴、Y轴组成的这篇区域的面积。而Precision-Recall曲线是你设定不同的阈值的情况下,Recall作为横坐标、Precision作为纵坐标形成的点,这些点所连成的曲线。
我们都知道Recall和Precision的计算需要三个东西的个数(1)True Positive, (2)False Negative, (3)False Positive
要拿到这三个数字,你首先得有一些 True和False吧?怎么拿到True和False呢?
看下面这个矩阵第三列这个分类的置信度,如果这个置信度大于所设定的阈值就用True 来代替这个置信度, 小于阈值就用False来代替这个置信度
然后你拿着“predicted ”随着阈值改变的这个由True或False组成的,每个框对应类别的True或False, 和“ground truth”的 类别这一列,都是同一个标签,就赋值为True,反之有一点不同就赋值为False
不管这个predicted的方框是不是距离这个ground truth近,都一一匹配,标注True和False
这样就拿到了下面这个矩阵cls_mask
Step4 综合定位和分类,拿到
对于iou_mask和cls_mask这两个N×M的矩阵 每个元素 之间 做 and 运算,
也就是 只有 两个都为True的时候,matched_mask上这个位置的元素才为True.其他的情况,一个True、一个False, 两个False 的情况 这位位置上的元素都为False
matched_mask = ( (iou_mask == True) and (cls_mask == True) )
得出下面这样的match_mask矩阵
Step 5 按照Step4中匹配为True的位置,得到 target-predicted 匹配的pairs
从上面这个matched_mask里面把值为True的元素取出来,列出 target(matched_mask的横坐标)的序号和predicted的序号(matched_mask的纵坐标)拿出来列在下面
我们这里为了简单,下面的这个配对数据是编造的,假设只有6组配对,计算的是mAP50。下面编造的这组数据和上文的iou_mask, cls_mask, matched_mask里面那些数据无关。
你看到上面这6组配对,你可能一时摸不着头脑,不知道这些数据代表什么含义,又为什么是这些id之间进行配对,而不是一些其他id的target和predicted进行配对。下面我就一一为你揭晓答案。
第一列和第二列写的是index的数字。如第一列和第二列的第一行和第二行表示的是和匹配是一对,和匹配是一对。这两列想表达的就是target中第几个和pred中第几个是可以匹配成一对的。
第三列iou是predicted bouding box和target bouding box之间的IoU(重合面积除以总面积)
第四列是target bbox和 predicted bbox框处的那个object的类别。
第五列是predicted bbox里面是这个类别的置信度。
而对于target bbox里面是这个类别,是数据标注的时候都给好的,那就是这个类别,非要写置信度那就1.00,所以写这个置信度就没啥意义了,所以没有这一列
上图这些配对是根据matched_mask矩阵中为True的元素匹配来的。这样的设计,可以匹配的target和predicted必须同时满足下列两个条件,才会被放进表格里
(条件一):定位方面达标:因为我们这里计算的是mAP50,所以predicted bouding box和target boudingbox这两个方框之间的IoU都必须大于50%的。所以你看上面这个pairs的第三列,全部的IoU都是大于0.50的。
(条件二):类别方面达标:所有配对的这些predicted和target的类别都必须完全相同的,起码是在这一条匹配中,二者的类别标签是完全一样的。比如前三行,target 的index=0和它匹配得上的predicted id=0, id=1, id=2的类别都是 “79”这个类别。(应是用的COCO数据集的列表标签有80个类别,从0到79,所以才会有79这个类别)。但是尽管predicted id=0, id=1, id=2的类别都是 “79”这个类别,他们对于分类到“79”这个类别的置信度是不同的,有的是0.89,有的是0.3,有的是0.15。
这里需要注意,在上面这些配对里面
(1)同一个真实框可能对应多个预测框相匹配,比如和。因此下面我们要去重,使得一个真实框只对应一个预测框。
(2)同一个预测框可能对应多个真实框,比如,它一个预测框在配对中就有两次分别和
————还没写完,有时间,再继续写————
目前还不懂的知识
ROC曲线是什么?表示什么含义?怎么用?
AUC曲线同样的问题
Reference
PR曲线与ROC曲线_roc曲线和pr曲线_THE@JOKER的博客-CSDN博客
为什么平均精准度(Average Precision,AP)就是PR曲线的线下面积? - Mark Lue的回答 - 知乎 https://www.zhihu.com/question/422868156/answer/1523130474
sklearn.metrics.average_precision_score — scikit-learn 1.3.0 documentation
[CV] 目标检测中的map计算 - 知乎
COCO - Common Objects in Context
https://www.cnblogs.com/ywheunji/p/13376090.html
准确率、召回率和mAP、AP50/75_map和ap50_dagongji10的博客-CSDN博客