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

本篇文章首先介绍目标检测任务中的评价指标混淆矩阵的概念,然后介绍其在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])))

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

rime中州韵小狼毫 汉语拼音输入方案

在word中&#xff0c;我们可以轻易的给汉字加上拼音&#xff0c;如下&#x1f447;&#xff1a; 但是&#xff0c;如何单独的输入拼音呢&#xff1f;例如输入 pīn yīn, 再如 zhōng guō。今天我们分享一个使用rime中州韵小狼毫须鼠管输入法配置的输入汉语拼音的输入方案。功…

WPS - 表格虚线变成实线解决方案(Office 同上)

1、选中表格区域&#xff0c;在表格中选中需要调整为实线的表格区域 2、点击设置单元格格式&#xff0c;鼠标进行右击并点击设置单元格格式选项 3、选择实线&#xff0c;在单元格格式下的边框&#xff0c;调整到实线 4、设置为实线&#xff0c;即可将表格的虚线设置为实线

(ros2)gazebo颜色设置

在gazebo当中不用再设置颜色了&#xff0c;因为完全可以使用urdf的设置 <robot name"base" xmlns:xacro"http://wiki.ros.org/wiki/xacro"><xacro:property name"PI" value"3.1415926"/><!--定义一个变量PI&#xff0…

研发日记,Matlab/Simulink避坑指南(三)——向上取整Bug

文章目录 前言 背景 问题 排查 解决 总结 前言 见《研发日记&#xff0c;Matlab/Simulink避坑指南&#xff08;一&#xff09;——Data Store Memory模块执行时序Bug》 见《研发日记&#xff0c;Matlab/Simulink避坑指南(二)——非对称数据溢出Bug》 背景 在一个嵌入式软…

vi/vim 编辑器 --基本命令

1 vi/vim编辑器介绍 vi 是visual interface 的简称&#xff0c;是Linux中最经典的文本编辑器 vim是vi的加强版。兼容了vi的所有指令&#xff0c;不仅能编辑文本&#xff0c;而且具有shell程序编辑的功能&#xff0c;可以通过不同颜色的字体辨别语法的正确性&#xff0c;极大…

七麦数据js逆向(补环境版)

本文目标地址如下&#xff0c;使用base64解码获得 aHR0cHM6Ly93d3cucWltYWkuY24vcmFuay9tYXJrZXRSYW5rL21hcmtldC82L2NhdGVnb3J5LzUvY29sbGVjdGlvbi9hbGwvZGF0ZS8yMDI0LTAxLTEy 本文逆向破解分为扣代码版和补环境版&#xff0c;扣代码版请看专栏另一篇文章 废话不多说了&#…

Docker 安装以及加速器配置

通常我们因为安装docker出现许多错误&#xff0c;使用解压版安装方便快捷&#xff0c;并且增加加速器的配置&#xff0c;以及可视化界面的配置&#xff0c;让我们的成长更近了一步 1. 虚拟机网络配置 虚拟机使用nat模式&#xff0c;配置ens33如下&#xff1a; TYPEEthernet P…

15 个适用于 Windows 的 PDF 解锁工具大全

PDF&#xff08;便携式文件格式&#xff09;是一种文件格式&#xff0c;用于呈现和交换任何独立于任何软件、硬件或操作系统的可靠访问的文档。Adobe 发明了它&#xff0c;但现在它是由国际标准化组织 (ISO) 维护的开放标准。因此&#xff0c;您现在必须了解这些 PDF 解锁工具。…

微软等开源评估ChatGPT、Phi、Llma等,统一测试平台

微软亚洲研究院、中国科学院自动化研究所、中国科学技术大学和卡内基梅隆大学联合开源了&#xff0c;用于评估、分析大语言模型的统一测试平台——PromptBench。 Prompt Bench支持目前主流的开源、闭源大语言模型&#xff0c;例如&#xff0c;ChatGPT、GPT-4、Phi、Llma1/2、G…

PagedAttention: from interface to kernal

1 Overview PagedAttention灵感来自于操作系统中虚拟内存和分页的经典思想&#xff0c;它可以允许在非连续空间立存储连续的KV张量。具体来说&#xff0c;PagedAttention把每个序列的KV缓存进行了分块&#xff0c;每个块包含固定长度的token&#xff0c;而在计算attention时可…

Fabric2.2:在有系统通道的情况下搭建应用通道

写在最前 在使用Fabric-SDK-Go1.0.0操作Fabric网络时遇到了bug。Fabric-SDK-GO的当前版本没有办法在没有系统通道的情况下创建应用通道&#xff0c;而Fabric的最新几个版本允许在没有系统通道的情况下搭建应用通道。为了解决这个矛盾并使用Fabric-SDK-GO完成后续的项目开发&…

谷歌aab包在Android 14闪退而apk没问题(targetsdk 34)

问题原因 Unity应用(target SDK 34)上线到GooglePlay&#xff0c;有用户反馈fold5设备上&#xff08;Android14系统&#xff09;疯狂闪退&#xff0c;经测试&#xff0c;在小米手机Android14系统的版本复现成功了&#xff0c;奇怪的是apk直接安装没问题&#xff0c;而打包成aa…

MacOS环境下Kali Linux安装及使用指导

Kali Linux是一个开源的、基于Debian的Linux发行版&#xff0c;面向各种信息安全任务&#xff0c;如渗透测试、安全研究、计算机取证和逆向工程&#xff0c;是最先进的渗透测试发行版&#xff0c;它的前身是BackTrack。 1. 我们为什么要用Kali Linux 由于Kali Linux具有以下特…

Typora上传图片失败PicGo

起初我是在Typora中点击一键上传图片&#xff0c;结果如下&#xff0c;报错。可是我找了半天也没错啊。 最后发现原来是一个图片的命名问题&#xff0c;名字太过于复杂&#xff0c;PicGo识别不出&#xff0c;一个图片报错导致其它也上传不了。 我把它复制到其它文件夹之后&…

JavaScript基础03

1 - 循环 1.1 for循环 语法结构 for(初始化变量; 条件表达式; 操作表达式 ){//循环体 } 名称作用初始化变量通常被用于初始化一个计数器&#xff0c;该表达式可以使用 var 关键字声明新的变量&#xff0c;这个变量帮我们来记录次数。条件表达式用于确定每一次循环是否能被执行…

集简云动作管理平台上线:创建强大且可分享的AI助手(GPTs)

OpenAI的GPT Store于昨天上线&#xff0c;用户可以找到好用的GPTs&#xff0c;也可以将自己的GPTs分享到GPT Store中。未来&#xff08;预计今年1季度&#xff09;甚至可以从GPTs Store中获取利润分成。 要创建强大的GPTs离不开调用外部的软件工具&#xff0c;比如查询CRM/ERP软…

03.阿里Java开发手册——OOP规约

【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法&#xff0c;无谓增加编译器解析成本&#xff0c;直接用类名来访问即可。 【强制】所有的覆写方法&#xff0c;必须加Override 注解。 说明&#xff1a;getObject()与 get0bject()的问题。一个是字母的 O&#x…

小程序中滚动字幕

需求&#xff1a;在录像时需要在屏幕上提示字幕&#xff0c;整体匀速向上滚动 html部分&#xff1a; <view class"subtitles_main"><view style"font-size:34rpx;color: #fff;line-height: 60rpx;" animation"{{animation}}">人生的…

Unity2022.3打包Android后从AB包加载场景发现丢失大量脚本问题

问题 这两天遇到一个问题&#xff0c;在VR项目打包Android的时候&#xff0c;加载场景后&#xff0c;Timeline工作不正常&#xff0c;找不到原因。 现象 看到有很多警告&#xff0c;丢失脚本的Log。 因为场景本身也有一些丢失的脚本所以没在意&#xff0c;但是又不是所有脚本…

QEMU源码全解析 —— PCI设备模拟(7)

接前一篇文章&#xff1a; 上一回讲解了pci_edu_realize函数中的pci_register_bar函数&#xff0c;本回开始对于edu设备的MMIO读写函数进行解析。 操作系统与PCI设备交互的主要方式是PIO和MMIO。MMIO虽然是一段内存&#xff0c;但是其没有EPT映射&#xff0c;在虚拟机访问设备…