目标检测评估指标mAP:从Precision,Recall,到AP50-95【未完待续】

news2024/11/26 12:31:17

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])=3FP=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])=6FP=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的公式如下

\text{AP} = \sum_n (R_n - R_{n-1}) P_n

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_{0}pred_{0}匹配是一对,target_{0}和匹配是一对。这两列想表达的就是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)同一个真实框可能对应多个预测框相匹配,比如[(t_{0},p_{1}),(t_{0},p_{1}),(t_{0},p_{2})][(t_{2},p_{2}),(t_{2},p_{3})]。因此下面我们要去重,使得一个真实框只对应一个预测框。

        (2)同一个预测框可能对应多个真实框,比如pred_{1},它一个预测框在配对中就有两次分别和target_{0}, target_{1}

        ————还没写完,有时间,再继续写————

目前还不懂的知识

        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博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1014737.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C高级day5(Makefile)

一、Xmind整理&#xff1a; 二、上课笔记整理&#xff1a; 1.#----->把带参宏的参数替换成字符串 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX(a,b) a>b?a:b #define STR(n) #n int main(int argc, const char *argv…

sheetjs實現頁面的數據導出execl

概述 需要給頁面的table做一個數據導出功能,發現一個好用sheetjs工具 只需要簡單的js語法如下,就可以將table的數據導出來 function load(){var date new Date();date.setTime(date.getTime() (8 * 60 * 60 * 1000));var table document.getElementById("tab");v…

神领物流 day02-网关与支付 Spring Cloud Alibaba 微服务

课程安排 单token存在的问题双token三验证用户端token校验与鉴权对接三方支付平台分布式锁 1、场景说明 新入职的你加入了开发一组&#xff0c;也接到了开发任务&#xff0c;并且你也顺利的修复了bug&#xff0c;完成了快递员、司机的鉴权&#xff0c;现在的你已经对项目的业…

C++qt day8

1.用代码实现简单的图形化界面&#xff08;并将工程文件注释&#xff09; 头文件 #ifndef MYWIDGET_H #define MYWIDGET_H //防止头文件冲突#include <QWidget> //父类的头文件class MyWidget : public QWidget //自定义自己的界面类&#xff0c;公共继承…

Linux vim的常见基本操作

目录 vim是一款多模式的编辑器 命令模式下&#xff1a; 用小写英文字母「h」、「j」、「k」、「l」&#xff0c;分别控制光标左、下、上、右移一格 gg&#xff1a;定位到代码第一行 nshiftg 定位到任意一行/最后一行 「 $ 」&#xff1a;移动到光标所在行的结尾 「 ^ 」&…

无涯教程-JavaScript - COLUMNS函数

描述 COLUMNS函数返回数组或引用中的列数。 语法 COLUMNS (array)争论 Argument描述Required/OptionalarrayAn array or array formula, or a reference to a range of cells for which you want the number of Columns.Required Notes COLUMNS(1:1)返回Excel中的列数,即…

字符串解码

题目链接 字符串解码 题目描述 注意点 s 由小写英文字母、数字和方括号 ‘[]’ 组成1 < s.length < 30s 保证是一个 有效 的输入s 中所有整数的取值范围为 [1, 300] 解答思路 利用栈先进后出的特点&#xff0c;将字符存储进栈中创建两个栈&#xff0c;一个数字栈&am…

照片批量处理 7000张

需求&#xff1a; 有6700照片导入系统&#xff1b; 系统只支持500张/每次&#xff1b; 6700 按机构分类复制提取出来&#xff1b; 分批次导入&#xff1b; 6700 分17份复制到对应文件夹中&#xff1b; 照片按照学号命名的&#xff1b; 20231715401.jpg 开始用bat脚本…

Matlab Simulink支持system generator插件

文章目录 前言一、System Generator 简介二、System Generator 特性三、System Generator 安装1、确定是否已安装 System Generator 工具2、vivado 卸载3、vivado 安装 四、解决版本不兼容问题五、使用 System Generator 前言 目前有在 Simulink 中开发完成后将其转换成 Veril…

七天学会C语言-第一天(C语言基本语句)

一、固定格式 这个是C程序的基本框架&#xff0c;需要记住&#xff01;&#xff01;&#xff01; #include<stdio.h>int main(){return 0; }二、printf 语句 简单输出一句C程序&#xff1a; #include<stdio.h> int main(){printf("大家好&#xff0c;&quo…

浅析Java责任链模式实现

一、概要 定义&#xff1a;责任链模式是一种行为设计模式&#xff0c; 允许你将请求沿着处理者链进行发送。收到请求后&#xff0c; 每个处理者均可对请求进行处理&#xff0c; 或将其传递给链上的下个处理者。 二、应用场景&#xff1a; 1.多条件流程判断&#xff1a;权限相关…

时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测

时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测 目录 时序预测 | MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 基本介绍 MATLAB实现BO-BiGRU贝叶斯优化双向门控循环单元时间序列预测。…

把握经济大势和个人财运密码必须读懂钱—现代金钱的魔力

原出处&#xff1a;天涯论坛之《把握经济大势和个人财运密码必须读懂钱—现代金钱的魔力》 原作者&#xff1a;真立派 原文完整版PDF&#xff08;可能很快就会被河蟹&#xff0c;建议先保存&#xff09;&#xff1a;https://pan.quark.cn/s/20c917683d8f 引子 过去一些年&…

数据结构入门 — 树的概念与结构

本文属于数据结构专栏文章&#xff0c;适合数据结构入门者学习&#xff0c;涵盖数据结构基础的知识和内容体系&#xff0c;文章在介绍数据结构时会配合上动图演示&#xff0c;方便初学者在学习数据结构时理解和学习&#xff0c;了解数据结构系列专栏点击下方链接。 博客主页&am…

【LeetCode-中等题】 151. 反转字符串中的单词

文章目录 题目方法一&#xff1a;双指针去除空格 题目 方法一&#xff1a;双指针去除空格 核心代码去除首尾以及中间多余空格(在原串上修改) //去除首尾以及中间多余空格(在原串上修改)public StringBuilder trimSpaces(String s) { int len s.length();StringBuilder str …

【结构型】代理模式(Proxy)

目录 代理模式(Proxy)适用场景代理模式实例代码&#xff08;Java&#xff09; 代理模式(Proxy) 为其他对象提供一种代理以控制对这个对象的访问。Proxy 模式适用于在需要比较通用和复杂的对象指针代替简单的指针的时候。 适用场景 远程代理 (Remote Proxy) 为一个对象在不同…

linux-线程条件变量(cond)

概述 与互斥锁不同&#xff0c;条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程&#xff0c;直到某特殊情况发生为止。通常条件变量和互斥锁同时使用 。 条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制&a…

Vue2的学习

computed计算属性 概念 基于现有数据&#xff0c;计算出来的新属性&#xff0c;依赖的数据变化&#xff0c;会自动重新计算 语法 声明在computed配置项中&#xff0c;一个计算属性对应一个函数这是一个属性{{计算属性名}}&#xff0c;不是方法注意不要忘记return <body…

无涯教程-JavaScript - ROW函数

描述 ROW函数返回引用的行号。 语法 ROW ([reference]) 争论 Argument描述Required/OptionalReference 您想要其行号的单元格或单元格范围。 如果省略引用,则假定它是出现ROW函数的单元格的引用。 请参阅下面的注释。 Optional Notes 如果引用是一个单元格范围,并且如果将…

【RTOS学习】单片机中的C语言

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 本喵默认各位小伙伴都会C语言&#xff0c;我们平时学习C语言都是在Windows环境下学习的&#xff0…