Python计算PASCAL VOC2012数据集AP分类任务指标

编程入门 行业动态 更新时间:2024-10-09 09:17:09

Python计算PASCAL VOC2012数据集AP分类任务<a href=https://www.elefans.com/category/jswz/34/1768114.html style=指标"/>

Python计算PASCAL VOC2012数据集AP分类任务指标

Python计算PASCAL VOC2012数据集AP分类任务指标

  • 前言
  • TP,TN,FP,FN
  • 召回率(Recall)和精确率(Precision)
  • 如何画PR曲线
  • AP指标
  • 代码
  • 致谢

前言

PASCAL VOC2012数据集竞赛,主要有两个任务,分类和分割,计算分割任务指标的代码已经满大街都是了,这个mAP代码应该是比较权威的了。但是计算分类的指标,我是找了很久都没有找到,只好自己写代码计算一下。

事先说明,计算分类任务AP指标的时候,2010年之前的竞赛和之后的竞赛,虽然都用了AP指标,但计算方式不同,之前的那个算法既然被淘汰了,就不用深究了,这里说的AP指标计算方法,是2010年之后的。两者的区别是,之前的计算方式是通过给Recall取10个阈值,找11个Precision最大值,取平均值;之后的计算方式是每个Recall取一个Precision的最大值,最后算平均。听起来好像之前的计算方式更简单,其实是现在的计算方式更简单。

这里是VOC2012竞赛的说明文档
这里是分类任务AP指标的排行榜。

要计算AP,首先就要了解精确率和召回率;要了解精确率和召回率,首先要了解TP,TN,FP,FN。这玩意儿可以说,如果不彻底搞懂,每次用的时候都得重复看一遍。所以还是彻底搞懂的好。一般讲这个的博客都会给一个二维表格,那个表格是很优雅,但是真的看不懂,记不住。

TP,TN,FP,FN

这里说下我的理解,保证一次记住。T(True)代表分对了,F(False)代表分错了,P(Positive)代表分为正样本,N(Negtive)代表分为负样本。现在问,TP是什么意思,先看后一个字母,是P,代表分成正样本了,然后再看T,代表分对了,那么TP就是分对的正样本,这样自然就知道,groundtruth是什么,模型预测的是什么了。再来一个,FN,N代表负样本,F代表分错了,说明人家本来是一个正样本,结果模型分成负样本了。

召回率(Recall)和精确率(Precision)

有了这个基础,再看精确率和召回率的公式就好多了。通俗的解释,

召回率(Recall):总共有100个正样本,模型预测出来80个,那召回率就是80%,召回率就是单指正样本来说的,只关心你分对的正样本占总共正样本个数的比例。顺便问一下,这80个正样本用TPFN这四个字母来表示,是谁呢?答案应该是TP。那总的正样本个数呢?用字母来表示是谁?应该是TP+FN,没错,是FN,这是和精确率最大的不同。因为FN的groundtruth是正样本,只不过分成了负样本

精确率(Precision):模型分了100个正样本,那就看看这100个里面有多少是对的,多少是错的,例如有70个是正的,那就是70%。同样的,这70个用TPFN来表示,就是TP,精确率的总个数呢,就应该TP+FP。怎么变成FP了呢?因为精确率是以模型预测的正样本为总体的,这里面肯定有对有错,对的就是TP,错的就是FP了

顺便说一下准确率(Accurary),准确率是你没学机器学习之前,自己感觉的那个,就叫准确率。比如给我1000张照片,可能有狗可能没狗,那对于每一张照片,我给一个结果,如果我说对了,就加一分,说对有两种情况,一种是有狗我说有狗,一种是没狗是说没狗。对于有狗我说有狗,这个样本用字母来表示就是TP,没狗我说没狗,用字母来表示就是TN,所以分子就是(TP+TN),分母就是总共的样本个数了。

最后,来看一下这三个公式,是不是豁然开朗了呢
R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP​
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP​
A c c u r a r y = T P + T N T P + F P + T N + F N Accurary=\frac{TP+TN}{TP+FP+TN+FN} Accurary=TP+FP+TN+FNTP+TN​

如何画PR曲线

知道了,Precision和Recall,我们先不算AP,先画一下这个PR曲线,

这是我随机了20个样本数据画出来的,你要画PR曲线,其实就是计算N个Precision和Recall就可以了,然后把Recall当做横坐标,Precision当做纵坐标,用python的plot就可以画了。等等,为什么会有N个Precision和Recall呢?撑死也就一对Precision和Recall呀,N个哪来的呢?N又具体等于几呢?

我们看一个例子,不过就不用20个数据了,我们用5个数据,

predgt
0.861
0.241
0.631
0.340
0.140

pred是模型预测的结果,gt是groundtruth,现在我们来计算Precision和Recall的数组
首先,我们选一个超大的阈值 ∞ \infty ∞,看有哪个样本的pred超过这个阈值的,如果超过了,就把这个样本提取出来,那么现在你看,Recall是多少?不用想就是0,为什么呢?因为一个样本都没有,分子是0,分母是3(分母是3是因为gt只有3个,即TP+FN=3)。那Precision呢,因为一个样本都没有,那我就不用预测了呀,那就算我对吧,所以Precision是1,由此我们跨出了第一步:

PrecisionRecallThreshold
10 ∞ \infty ∞

接下来,把阈值降低,降到多少呢,就降到pred里面阈值最大的那个,即0.86,好了,现在阈值变了,我们是不是可以提取出来一个样本了呢,我们就把pred=0.86,gt=1提取出来了。只要我们提取的样本里阈值大于等于0.86,我们就算他是正样本,OK,现在算一下Precision和Recall。Precision=1,因为我们这个样本预测为1,gt也是1,预测对了,而且总共就一个样本。Recall是1/3,总算有一个样本被召回进来了。于是,我们得到:

PrecisionRecallThreshold
10 ∞ \infty ∞
11/30.86

下面,重复就可以了,阈值接着降低,下一个我们选0.63,再接着选0.34,0.24,得到下表

PrecisionRecallThreshold
10 ∞ \infty ∞
11/30.86
12/30.63
2/32/30.34
1/310.24

ps:这个表格有一处错误,自己计算一下,看看是哪里错了。小错误,不影响阅读,如果找到了,接着读,就可以验证你找的对不对*

有一个问题,为什么阈值不接着往下取了呢,还有0.14呢,这是因为,Recall已经是1了,说明已经全部召回了,就没必要再搞了

由此,我们得到了Precision和Recall的数组,放到plot画出来就得到了PR曲线

AP指标

OK,现在我们会计算Precision和Recall,还会画PR曲线了,终于可以计算AP指标了。其实已经非常简单了。看我们刚才列的表格,把刚才的第一列去掉,因为那个是为了画图方便才设置的(0,1),算AP的时候是不需要的。

PrecisionRecallThreshold
11/30.86
12/30.63
2/32/30.34
1/310.24

可以看到Recall有三个等级,1/3,2/3和1,2/3比较特殊,因为他对应的Precision有两个,取哪个呢?取大的。最后,把这三个Recall对应的Precision求个平均值就可以啦。
这里的AP=0.9166666667,你算对了吗?

代码

最后,我们附上一段代码,都是随机数据,可以直接运行

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import average_precision_score as ap
from sklearn.metrics import precision_recall_curve as pr
def main():data_len = 5 # 更改这个值来尝试更多数据np.random.seed(1001)label = np.random.randint(0, 2, size=data_len)score = np.random.choice(np.arange(0.1, 1, 0.01), data_len)presicion, recall, thresholds = pr(label, score)ap_value = ap(label, score)print(value)print(label)print(score)print(presicion)print(recall)print(thresholds)print(ap_value)## 画图plt.plot(recall, presicion, 'k')plt.title('PR')plt.xlim([-0.01, 1.01])plt.ylim([-0.01, 01.01])plt.ylabel('Precision')plt.xlabel('Recall')plt.show()if __name__ == "__main__":main()print('Done.')

致谢

感谢以下三篇博客的作者,参考了他们的内容和代码,才让我完全理解了AP指标的计算过程
花心大罗博l
东写西读李老湿
张乐乐章

更多推荐

Python计算PASCAL VOC2012数据集AP分类任务指标

本文发布于:2024-03-14 12:33:35,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1736479.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:指标   数据   PASCAL   Python   AP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!