【目标检测】评价指标:混淆矩阵概念及其计算方法(yolo源码)

news2024/9/28 15:30:33

本篇文章首先介绍目标检测任务中的评价指标混淆矩阵的概念,然后介绍其在yolo源码中的实现方法。

目标检测中的评价指标:

mAP概念及其计算方法(yolo源码/pycocotools)
混淆矩阵概念及其计算方法(yolo源码)

本文目录

  • 1 概念
  • 2 计算方法

1 概念

  在分类任务中,混淆矩阵(Confusion Matrix)是一种可视化工具,主要用于评价模型精度,将模型的分类结果显示在一个矩阵中。多分类任务的混淆矩阵结构如图1所示,其中横轴表示模型预测结果,纵轴表示实际结果,图中的各类指标以cls_1的预测结果为例,其含义如下:

  • True Positive(TP):预测为正样本(cls_1),且实际为正样本(cls_1)
    • 各类别TP:混淆矩阵对角线的值
  • False Positive(FP):预测为正样本(cls_1),但实际为负样本(cls_other)
    • 各类别FP:混淆矩阵每列的和减去对应的TP
  • False Negative(FN):预测为负样本(cls_other),但实际为正样本(cls_1)
    • 各类别(FN:混淆矩阵每行的和减去对应的TP
  • True Negative(TN): 预测为负样本(cls_other),且实际为负样本(cls_other)
    • 各类别FN:混淆矩阵的和减去对应的TP、FP、FN

在这里插入图片描述

图1 分类任务中混淆矩阵

  目标检测的任务为对目标进行分类定位,模型的预测结果p为(cls, conf, pos),其中cls为目标的类别,conf为目标属于该类别的置信度,pos为目标的预测边框。目标检测任务综合类别预测结果预测边框与实际边框IoU,对模型进行评价,其混淆矩阵结构如图2所示,图中的各类指标以cls_1的预测结果为例,其含义如下:

  • 样本匹配(每一张图片):预测结果gt与实际结果dt匹配
    • IoU > IoU_thres
    • 同一个gt至多匹配一个p(若一个gt匹配到多个p,则选择IoU最高的p作为匹配结果)
    • 同一个gt至多匹配一个p(若一个p匹配到多个gt,则选择IoU最高的gt作为匹配结果)
  • background: 未成功匹配的gtdt
  • True Positive(TP):匹配结果为正样本(cls_1),且实际为正样本(cls_1)
  • False Positive(FP):匹配结果正样本(cls_1),但实际为负样本(cls_1 or background)
  • False Negative(FN):匹配结果为负样本(cls_other or backgroun),但实际为正样本(cls_1)
  • True Negative(TN):匹配结果为负样本(cls_other or backgroun),且实际为负样本(cls_other or backgroun)

在这里插入图片描述

图2 目标检测中混淆矩阵

  目标检测任务中的混淆矩阵计算方法如图3所示。
在这里插入图片描述

图3 混淆矩阵计算方法

2 计算方法

基于YOLO源码实现混淆矩阵计算(ConfusionMatrix)

  • 函数
    • process_batch:实现预测结果与真实结果的匹配,混淆矩阵计算
    • plot:混淆矩阵绘制
    • tp_fp:根据混淆矩阵计算TP/FP
class ConfusionMatrix:
    # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix
    def __init__(self, nc, conf=0.25, iou_thres=0.5):
        self.matrix = np.zeros((nc + 1, nc + 1))
        self.nc = nc  # number of classes
        self.conf = conf  # 类别置信度
        self.iou_thres = iou_thres  # IoU置信度

    def process_batch(self, detections, labels):
        """
        Return intersection-ove-unionr (Jaccard index) of boxes.
        Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
        Arguments:
            detections (Array[N, 6]), x1, y1, x2, y2, conf, class
            labels (Array[M, 5]), class, x1, y1, x2, y2
        Returns:
            None, updates confusion matrix accordingly
        """
        if detections is None:
            gt_classes = labels.int()
            for gc in gt_classes:
                self.matrix[self.nc, gc] += 1  # 预测为背景,但实际为目标
            return

        detections = detections[detections[:, 4] > self.conf]  # 小于该conf认为为背景
        gt_classes = labels[:, 0].int()  # 实际类别
        detection_classes = detections[:, 5].int()  # 预测类别
        iou = box_iou(labels[:, 1:], detections[:, :4])  # 计算所有结果的IoU

        x = torch.where(iou > self.iou_thres)  # 根据IoU匹配结果,返回满足条件的索引 x(dim0), (dim1)
        if x[0].shape[0]:  # x[0]:存在为True的索引(gt索引), x[1]当前所有下True的索引(dt索引)
            # shape:[n, 3] 3->[label, detect, iou]
            matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy()
            if x[0].shape[0] > 1:
                matches = matches[matches[:, 2].argsort()[::-1]]  # 根据IoU从大到小排序
                matches = matches[np.unique(matches[:, 1], return_index=True)[1]]  # 若一个dt匹配多个gt,保留IoU最高的gt匹配结果
                matches = matches[matches[:, 2].argsort()[::-1]]  # 根据IoU从大到小排序
                matches = matches[np.unique(matches[:, 0], return_index=True)[1]]  # 若一个gt匹配多个dt,保留IoU最高的dt匹配结果
        else:
            matches = np.zeros((0, 3))

        n = matches.shape[0] > 0  # 是否存在和gt匹配成功的dt
        m0, m1, _ = matches.transpose().astype(int)  # m0:gt索引 m1:dt索引
        for i, gc in enumerate(gt_classes):  # 实际的结果
            j = m0 == i  # 预测为该目标的预测结果序号
            if n and sum(j) == 1:  # 该实际结果预测成功
                self.matrix[detection_classes[m1[j]], gc] += 1  # 预测为目标,且实际为目标
            else:  # 该实际结果预测失败
                self.matrix[self.nc, gc] += 1  # 预测为背景,但实际为目标

        if n:
            for i, dc in enumerate(detection_classes):  # 对预测结果处理
                if not any(m1 == i):  # 若该预测结果没有和实际结果匹配
                    self.matrix[dc, self.nc] += 1  # 预测为目标,但实际为背景

    def tp_fp(self):
        tp = self.matrix.diagonal()  # true positives
        fp = self.matrix.sum(1) - tp  # false positives
        # fn = self.matrix.sum(0) - tp  # false negatives (missed detections)
        return tp[:-1], fp[:-1]  # remove background class

    @TryExcept('WARNING ⚠️ ConfusionMatrix plot failure')
    def plot(self, normalize=True, save_dir='', names=()):
        import seaborn as sn
        plt.rc('font', family='Times New Roman', size=15)
        array = self.matrix / ((self.matrix.sum(0).reshape(1, -1) + 1E-9) if normalize else 1)  # normalize columns
        array[array < 0.005] = 0.00  # don't annotate (would appear as 0.00)

        fig, ax = plt.subplots(1, 1, figsize=(12, 9), tight_layout=True)
        nc, nn = self.nc, len(names)  # number of classes, names
        sn.set(font_scale=1.0 if nc < 50 else 0.8)  # for label size
        labels = (0 < nn < 99) and (nn == nc)  # apply names to ticklabels
        ticklabels = (names + ['background']) if labels else 'auto'
        with warnings.catch_warnings():
            warnings.simplefilter('ignore')  # suppress empty matrix RuntimeWarning: All-NaN slice encountered
            h = sn.heatmap(array,
                           ax=ax,
                           annot=nc < 30,
                           annot_kws={
                               'size': 20},
                           cmap='Reds',
                           fmt='.2f',
                           linewidths=2,
                           square=True,
                           vmin=0.0,
                           xticklabels=ticklabels,
                           yticklabels=ticklabels,
                           )
            h.set_facecolor((1, 1, 1))

            cb = h.collections[0].colorbar  # 显示colorbar
            cb.ax.tick_params(labelsize=20)  # 设置colorbar刻度字体大小。

        plt.xticks(fontsize=20)
        plt.yticks(fontsize=20)
        plt.rcParams["font.sans-serif"] = ["SimSun"]
        plt.rcParams["axes.unicode_minus"] = False
        ax.set_xlabel('实际值')
        ax.set_ylabel('预测值')
        # ax.set_title('Confusion Matrix', fontsize=20)
        fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=100)
        plt.close(fig)

    def print(self):
        for i in range(self.nc + 1):
            print(' '.join(map(str, self.matrix[i])))

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

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

相关文章

《安富莱嵌入式周报》第330期:开源ECU模组,开源USB PD供电SMD回流焊,嵌入式系统开发C代码参考指南,旨在提升C语言编写的源码质量

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程 BSP视频教程第29期&#xff1a;J1939协议栈CAN总线专题&#xff0c;源码框架&#xff0c;执行流程和…

从零学Java Map集合

Java Map集合 文章目录 Java Map集合1 Map 结构2 Map 父接口2.1 Map接口的特点2.2 常用方法 3 Map集合的实现类3.1 HashMap【重点】3.2 LinkedHashMap3.3 TreeMap3.4 Hashtable&#xff08;了解&#xff09;3.5 Properties 属性集合 4 HashMap 源码分析 1 Map 结构 概念: 将键…

react输入框检索树形(tree)结构

input搜索框搜索树形子级内容1. input框输入搜索内容2. 获取tree结构数据3. 与tree匹配输入的内容&#xff0c;tree是多维数组&#xff0c;一级一级的对比输入的内容是否匹配&#xff0c;用forEach循环遍历数据&#xff0c;匹配不到在往下找&#xff0c;直到找到为null &#x…

2024年甘肃省职业院校技能大赛信息安全管理与评估 样题二 模块二

竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 1.第一阶段&#xff1a;模块一 网络平台搭建与设备安全防护&#xff08;180 分钟&#xff0c;300 分&#xff09;。 2.第二阶段&#xff1a;模块二…

数据结构排序——详细讲解归并排序(c语言实现递归及非递归)

上次是快排和冒泡&#xff1a;数据结构排序——详解快排及其优化和冒泡排序(c语言实现、附有图片与动图示意&#xff09; 今天为大家带来归并排序 文章目录 1.基本思想2.递归实现3.非递归实现 1.基本思想 归并排序是一种分治算法&#xff0c;它将序列分成两个子序列&#xff0…

Docker与微服务实战(高级篇)- 【上】

Docker与微服务实战&#xff08;高级篇&#xff09;- 【上】 一、Docker复杂安装详说1.1 Mysql主从复制--原理-【尚硅谷Mysql高级篇】1.2 Mysql主从复制--【一主一从】搭建步骤1.2.1新建--【主服务器】--容器实例--33071.2.2.进入/app/mysql-master/conf目录下新建my.cnf1.2.3.…

3d建模软件有哪些?3d云渲染推荐

3D建模软件有很多&#xff0c;有的非常复杂难以上手&#xff0c;那么适合新手的有哪些呢&#xff1f;一起来看看吧。 1、SketchUp SketchUp是一个用户友好且直观的建模软件&#xff0c;能与V-Ray渲染器一起使用&#xff0c;适合初学者。2、Blender Blender是一个功能强大且免费…

超声波清洗机可以洗些什么东西?质量比较好的超声波清洗机推荐

超声波清洗机只能清洗眼镜吗&#xff1f;不是的&#xff01;超声波清洗机能够清洗的物品远比我们想象的还多&#xff0c;最常见的还是清洗眼镜&#xff0c;毕竟超声波清洗机最常见就是在眼镜店了&#xff0c;很多朋友都喜欢定期都眼镜店里来清洗一下眼镜&#xff0c;这个习惯其…

录屏怎么打开?看这里,录制视频不费事!

随着科技的快速发展&#xff0c;录屏已经成为人们日常生活中经常使用的功能。无论是录制游戏视频、教程讲解&#xff0c;还是录制在线会议&#xff0c;录屏软件都发挥着重要作用。然而&#xff0c;很多用户并不知道录屏怎么打开&#xff0c;以及如何使用它们。本文将介绍两种常…

爬虫实战丨基于requests爬取比特币信息并绘制价格走势图

文章目录 写在前面实验环境实验描述实验内容 写在后面 写在前面 本期内容&#xff1a;基于requests爬取比特币信息并绘制价格走势图 下载地址&#xff1a;https://download.csdn.net/download/m0_68111267/88734451 实验环境 anaconda丨pycharmpython3.11.4requests 安装r…

多级缓存架构(三)OpenResty Lua缓存

文章目录 一、nginx服务二、OpenResty服务1. 服务块定义2. 配置修改3. Lua程序编写4. 总结 三、运行四、测试五、高可用集群1. openresty2. tomcat 通过本文章&#xff0c;可以完成多级缓存架构中的Lua缓存。 一、nginx服务 在docker/docker-compose.yml中添加nginx服务块。…

canvasdrawer 微信原生小程序生成海报图片

在小程序中生成海报是一种非常有效的推广方式 用户可以使用小程序的过程中生成小程序海报并分享给他人 通过海报的形式&#xff0c;用户可以直观地了解产品或服务的特点和优势 常见绘制海报方式 目前&#xff0c;小程序海报有两种常见的实现方式&#xff1a; canvas 绘制…

Python基础语法汇总【保姆级小白教程】

文章目录 一&#xff1a;Python基础概念1.认识Python&#xff1a;2.Python的优势&#xff1a;3.Python的应用领域&#xff1a;4.Python的执行方式&#xff1a;5.文档&#xff1a; 二&#xff1a;变量与数据类型1.变量&#xff1a;2.id()函数&#xff1a;3.注释&#xff1a;4.基…

SqlAlchemy使用教程(一) 原理与环境搭建

一、SqlAlchemy 原理及环境搭建 SqlAlchemy是1个支持连接各种不同数据库的Python库&#xff0c;提供DBAPI与ORM&#xff08;object relation mapper&#xff09;两种方式使用数据库。 DBAPI方式&#xff0c;即使用SQL方式访问数据库 ORM, 对象关系模型&#xff0c;是用 Python…

竞赛保研 基于深度学习的视频多目标跟踪实现

文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的视频多目标跟踪实现 …

Trans论文复现:基于数据驱动的新能源充电站两阶段规划方法程序代码!

适用平台&#xff1a;MatlabYalmipCplex/Gurobi&#xff1b; 文章提出了一种电动汽车充电站的两阶段规划方法&#xff0c;第一阶段通过蒙特卡洛法模拟充电车辆需求和电池充放电数据来确定充电站位置&#xff1b;第二阶段通过数据驱动的分布鲁棒优化方法优化充电站的新能源和电池…

Jenkins配置发邮件

Jenkins配置发邮件 账号设置 首先这个邮箱账号要支持发邮件&#xff0c;QQ邮箱开通SMTP即可之后要认证 企业微信邮箱 开启IMAP/SMTP服务开启POP/SMTP服务 无论是企业微信邮箱还是QQ邮箱都是SSL协议&#xff0c;在下面的配置中我都会勾选上&#xff01;&#xff01;&#xff0…

Nginx配置jks格式证书,升级https

通常在给服务器升级https&#xff0c;需要在nginx上配置域名对应的https证书&#xff0c;nginx通常配置的是crt和key格式的证书。最近遇到有人提供了jks格式的证书&#xff0c;查阅了几个资料都是需要先将jks转为p12格式&#xff0c;然后再将p12转为crt格式。这里记录一下相关过…

【自控实验】3. 带有饱和非线性环节控制系统相平面分析

本科课程实验报告&#xff0c;有太多公式和图片了&#xff0c;干脆直接转成图片了 仅分享和记录&#xff0c;不保证全对 实验内容&#xff1a; 有无非线性环节的相轨迹对比&#xff0c;并求超调量。 在输入单位阶跃信号Xsr时&#xff0c;用示波器观察和记录系统输入饱和非线…

复选框QCheckBox和分组框QGroupBox

1. 复选框&#xff1a;QCheckBox 实例化 //实例化 // QCheckBox* checkBox new QCheckBox("是否同意该条款",this);QCheckBox* checkBox new QCheckBox(this);1.1 代码实现 1.1.1 复选框的基本函数 复选框选中状态的参数 Qt::Unchecked //未选中状态 Qt::Part…