yolov8添加FPPI评价指标

这里写自定义目录标题

    • yolov8 中FPPI实现
    • 测试中调用
  • 效果
  • 结语

续yolov7添加FPPI评价指标 。之前在yolov7中增加了fppi指标,有不少网友问有没有yolov8中增加,最近没有做算法训练,也一直没时间弄。这几天晚上抽了点时间,弄了一下。不过我本地的yolov8挺久没更新了,所以不一定能直接用,权当参考吧。

yolov8 中FPPI实现

yolo8中的评价指标实现位于ultralytics/utils/metrics.py中,我们只需要参照mAP指标在其中增加FPPI的内容即可:

def fppi_per_class(tp, conf, pred_cls, target_cls, image_num, plot=False, on_plot=None, save_dir=Path(), names=(), eps=1e-16, prefix=""):
    """Compute the false positives per image (FPPW) metric, given the recall and precision curves.
    Source:
    # Arguments
        tp:  True positives (nparray, nx1 or nx10).
        conf:  Objectness value from 0-1 (nparray).
        pred_cls:  Predicted object classes (nparray).
        target_cls:  True object classes (nparray).
        plot:  Plot precision-recall curve at mAP@0.5
        save_dir:  Plot save directory
    # Returns
        The fppi curve
    """
    # Sort by objectness
    i = np.argsort(-conf)
    tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]

    # Find unique classes
    unique_classes = np.unique(target_cls)
    nc = unique_classes.shape[0]  # number of classes, number of detections

    # Create Precision-Recall curve and compute AP for each class
    px, py = np.linspace(0, 1, 1000), np.linspace(0, 100, 1000)  # for plotting
    r = np.zeros((nc, 1000))
    miss_rate = np.zeros((nc, 1000))
    fppi = np.zeros((nc, 1000))
    miss_rate_at_fppi = np.zeros((nc, 3))  # missrate at fppi 1, 0.1, 0.01
    p_miss_rate = np.array([1, 0.1, 0.01])
    for ci, c in enumerate(unique_classes):
        i = pred_cls == c
        n_l = (target_cls == c).sum()  # number of labels
        n_p = i.sum()  # number of predictions

        if n_p == 0 or n_l == 0:
            continue
        else:
            # Accumulate FPs and TPs
            fpc = (1 - tp[i]).cumsum(0)
            tpc = tp[i].cumsum(0)

            # Recall
            recall = tpc / (n_l + eps)  # recall curve
            r[ci] = np.interp(-px, -conf[i], recall[:, 0], left=0)  # negative x, xp because xp decreases
            miss_rate[ci] = 1 - r[ci]

            fp_per_image = fpc / image_num
            fppi[ci] = np.interp(-px, -conf[i], fp_per_image[:, 0], left=0)

            miss_rate_at_fppi[ci] = np.interp(-p_miss_rate, -fppi[ci], miss_rate[ci])

    if plot:
        names = [v for k, v in names.items() if k in unique_classes]  # list: only classes that have data
        names = dict(enumerate(names)) 
        plot_fppi_curve(fppi, miss_rate, miss_rate_at_fppi, save_dir / f"{prefix}fppi_curve.png", names, on_plot=on_plot)


    return miss_rate, fppi, miss_rate_at_fppi

将fppi以对数坐标画图:

@plt_settings()
def plot_fppi_curve(px, py, fppi, save_dir=Path("pr_curve.png"), names=(), on_plot=None):
    """Plots a missrate-fppi curve."""
    fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True)
    py = np.stack(py, axis=1)
    # semi log
    for i, y in enumerate(py.T):
        ax.semilogx(px[i],y, linewidth=1, label=f'{names[i]} {fppi[i].mean():.3f}')  # plot(recall, precision)
    
    ax.semilogx(px.mean(0), py.mean(1), linewidth=3, color='blue', label='all classes %.3f' % fppi.mean())

    ax.set_xlabel('False Positives Per Image')
    ax.set_ylabel('Miss Rate')
    ax.set_xlim(0, 100)
    ax.set_ylim(0, 1)
    ax.grid(True)
    plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
    fig.savefig(Path(save_dir), dpi=250)
    plt.close(fig)
    if on_plot:
        on_plot(save_dir)

至此,fppi相关实现就完成了,接下来就是在代码中调用了。

测试中调用

通过调试,metrics的调用是在ultralytics/models/yolo/detect/val.py中的DetectionValidator中的get_stats函数中,在调用get_stats之前,会调用update_metrics计算tp, fp等。首先我们需要解决的时fppi计算需要图片的张数这个参数。在update_metrics我们可以获取这个值,在init_metrics增加参数self.image_num=0,在update_metrics中更新:

def update_metrics(self, preds, batch):
        """Metrics."""
        self.image_num+=len(batch['im_file'])
        for si, pred in enumerate(preds):
            idx = batch['batch_idx'] == si
            cls = batch['cls'][idx]
            bbox = batch['bboxes'][idx]
            ...

ap的计算在ultralytics/utils/metrics.py的DetMetrics中,我们给它也增加一个self.image_num=0参数, 并且在get_stats函数中设置它:

def get_stats(self):
        """Returns metrics statistics and results dictionary."""
        # set image_num for fppi calculation
        self.metrics.image_num = self.image_num
        stats = [torch.cat(x, 0).cpu().numpy() for x in zip(*self.stats)]  # to numpy
        if len(stats) and stats[0].any():
            self.metrics.process(*stats)
        self.nt_per_class = np.bincount(stats[-1].astype(int), minlength=self.nc)  # number of targets per class
        return self.metrics.results_dict

然后修改其process函数,在这个函数中调用乐ap_per_class来计算map, 我们在后面增加计算fppi的函数即可( def keys(self)中要加一个fppi的key):

def process(self, tp, conf, pred_cls, target_cls):
        """Process predicted results for object detection and update metrics."""
        results = ap_per_class(
            tp,
            conf,
            pred_cls,
            target_cls,
            plot=self.plot,
            save_dir=self.save_dir,
            names=self.names,
            on_plot=self.on_plot,
        )[2:]
        self.box.nc = len(self.names)
        self.box.update(results)
        results_fppi = fppi_per_class(
            tp,
            conf,
            pred_cls,
            target_cls,
            self.image_num,
            plot=self.plot,
            save_dir=self.save_dir,
            names=self.names,
            on_plot=self.on_plot,
        )
        self.box.update_fppi(results_fppi)
        
 @property
    def keys(self):
        """Returns a list of keys for accessing specific metrics."""
        return ["metrics/precision(B)", "metrics/recall(B)", "metrics/mAP50(B)", "metrics/mAP50-95(B)",  "metrics/missrate_fppi_1"]

指标的计算结果是保存在ultralytics/utils/metrics.py的Metric结构中,所以还需要增加存储fppi相关指标(fitness也修改):

class Metric(SimpleClass):
    """
    Class for computing evaluation metrics for YOLOv8 model.

    Attributes:
        p (list): Precision for each class. Shape: (nc,).
        r (list): Recall for each class. Shape: (nc,).
        f1 (list): F1 score for each class. Shape: (nc,).
        all_ap (list): AP scores for all classes and all IoU thresholds. Shape: (nc, 10).
        ap_class_index (list): Index of class for each AP score. Shape: (nc,).
        nc (int): Number of classes.

    Methods:
        ap50(): AP at IoU threshold of 0.5 for all classes. Returns: List of AP scores. Shape: (nc,) or [].
        ap(): AP at IoU thresholds from 0.5 to 0.95 for all classes. Returns: List of AP scores. Shape: (nc,) or [].
        mp(): Mean precision of all classes. Returns: Float.
        mr(): Mean recall of all classes. Returns: Float.
        map50(): Mean AP at IoU threshold of 0.5 for all classes. Returns: Float.
        map75(): Mean AP at IoU threshold of 0.75 for all classes. Returns: Float.
        map(): Mean AP at IoU thresholds from 0.5 to 0.95 for all classes. Returns: Float.
        mean_results(): Mean of results, returns mp, mr, map50, map.
        class_result(i): Class-aware result, returns p[i], r[i], ap50[i], ap[i].
        maps(): mAP of each class. Returns: Array of mAP scores, shape: (nc,).
        fitness(): Model fitness as a weighted combination of metrics. Returns: Float.
        update(results): Update metric attributes with new evaluation results.

    """

    def __init__(self) -> None:
        self.p = []  # (nc, )
        self.r = []  # (nc, )
        self.f1 = []  # (nc, )
        self.all_ap = []  # (nc, 10)
        self.ap_class_index = []  # (nc, )
        self.nc = 0
        self.missrate = [] #miss rate, (nc, )
        self.fppi = [] #false positives per image, (nc, )
        self.missrate_fppi = [] #miss rate at fppi 1, 0.1, 0.01, (nc, 3)

    @property
    def missrate_fppi_1(self):
        return self.missrate_fppi[:, 0].mean() if len(self.missrate_fppi) else []

    @property
    def ap50(self):
        """
        Returns the Average Precision (AP) at an IoU threshold of 0.5 for all classes.

        Returns:
            (np.ndarray, list): Array of shape (nc,) with AP50 values per class, or an empty list if not available.
        """
        return self.all_ap[:, 0] if len(self.all_ap) else []

    @property
    def ap(self):
        """
        Returns the Average Precision (AP) at an IoU threshold of 0.5-0.95 for all classes.

        Returns:
            (np.ndarray, list): Array of shape (nc,) with AP50-95 values per class, or an empty list if not available.
        """
        return self.all_ap.mean(1) if len(self.all_ap) else []

    @property
    def mp(self):
        """
        Returns the Mean Precision of all classes.

        Returns:
            (float): The mean precision of all classes.
        """
        return self.p.mean() if len(self.p) else 0.0

    @property
    def mr(self):
        """
        Returns the Mean Recall of all classes.

        Returns:
            (float): The mean recall of all classes.
        """
        return self.r.mean() if len(self.r) else 0.0

    @property
    def map50(self):
        """
        Returns the mean Average Precision (mAP) at an IoU threshold of 0.5.

        Returns:
            (float): The mAP50 at an IoU threshold of 0.5.
        """
        return self.all_ap[:, 0].mean() if len(self.all_ap) else 0.0

    @property
    def map75(self):
        """
        Returns the mean Average Precision (mAP) at an IoU threshold of 0.75.

        Returns:
            (float): The mAP50 at an IoU threshold of 0.75.
        """
        return self.all_ap[:, 5].mean() if len(self.all_ap) else 0.0

    @property
    def map(self):
        """
        Returns the mean Average Precision (mAP) over IoU thresholds of 0.5 - 0.95 in steps of 0.05.

        Returns:
            (float): The mAP over IoU thresholds of 0.5 - 0.95 in steps of 0.05.
        """
        return self.all_ap.mean() if len(self.all_ap) else 0.0

    def mean_results(self):
        """Mean of results, return mp, mr, map50, map."""
        return [self.mp, self.mr, self.map50, self.map, self.missrate_fppi_1]

    def class_result(self, i):
        """class-aware result, return p[i], r[i], ap50[i], ap[i]."""
        return self.p[i], self.r[i], self.ap50[i], self.ap[i]

    @property
    def maps(self):
        """mAP of each class."""
        maps = np.zeros(self.nc) + self.map
        for i, c in enumerate(self.ap_class_index):
            maps[c] = self.ap[i]
        return maps

    def fitness(self):
        """Model fitness as a weighted combination of metrics."""
        w = [0.0, 0.0, 0.1, 0.9]  # weights for [P, R, mAP@0.5, mAP@0.5:0.95]
        return (np.array(self.mean_results()[:4]) * w).sum()

    def update(self, results):
        """
        Args:
            results (tuple): A tuple of (p, r, ap, f1, ap_class)
        """
        self.p, self.r, self.f1, self.all_ap, self.ap_class_index = results
    
    def update_fppi(self, results):
        """
        Args:
            results (tuple): A tuple of (missrate, fppi, missrate_fppi)
        """
        self.missrate, self.fppi, self.missrate_fppi = results

效果

训练过程中会在mAP的后面打印fppi, 训练完成后以及调用test.py测试时,会画fppi图:
在这里插入图片描述

结语

本文简述了在yolov8中增加FPPI评价指标,可以用来直观的表现模型的效果,指导阈值的选取。
f77d79a3b79d6d9849231e64c8e1cdfa~tplv-dy-resize-origshort-autoq-75_330.jpeg

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

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

相关文章

Vue3 - 项目配置多环境配置文件

最常见的多环境配置,就是开发环境配置,和生产环境配置(也就是上线的配置),很多情况下我们开发环境下的域名,和一些配置项,和我们生产模式下的不同,这个时候就需要我们进行多环境配置,不然每次发版都要改一波数据多麻烦。 另一种情况就是你两个项目是用的一套代码,但是最…

一文全解聚碳酸酯PC材料在汽车灯罩制造中的诸多显著优势!汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

聚碳酸酯PC材料在汽车灯罩制造中具有诸多显著优势。除了优异的抗冲击性、透明性、耐热性和稳定性外,还有以下一些重要优势: 出色的光学性能:PC材料的光学性能优异,能够确保灯罩内的光源均匀分布,减少光斑和眩光&#…

新人学习笔记值(初始JavaScript)

一、Java Script是什么 1.Java Script是世界上最流行的语言之一,是一种运行在客户端的脚本语言(script是脚本的意思) 2.脚本语言:不需要编译,运行过程中由js解释器(js引擎)进行解释并运行 3.现在…

3dmax材质库导入方法?3dmax云渲染速度体验

3ds Max 材质库包含多种素材,如金属、木材、布料和石材等,但用户在导入材质时常遇到问题。本文将介绍如何在3ds Max中成功导入材质,并探讨使用云渲染服务来加速渲染过程,提高项目效率。 一、3dmax材质库导入教程 自建材质导入方法…

胖东来5月生鲜陈列欣赏

【免责声明】:凡未注明来源的图文内容,版权归原作者所有。本平台所发稿件、图片均用于学习交流,不代表赞同文章观点和对其真实性负责,不用作商业用途。若文章涉及版权,请将马上联系,安排删除。

Google Chrome 设备工具栏原理

1.不同预览模式 2.计算出缩放比 3.固定滚动偏移 关键代码&#xff1a; overview&#xff1a; ratioW getChildRect().width / getParentRect().width ratioH getChildRect().height / getParentRect().height maxRatio max(ratioW, ratioH) if(maxRatio < 1) return 1 …

商业银行总分支数据分发的核心问题是什么?如何解决?

银行业对一个国家至关重要&#xff0c;关乎国计民生。银行为我国经济建设分配资金&#xff0c;是社会再生产顺 利进行的纽带&#xff0c;它能掌握和反应社会经济活动的信息&#xff0c;为企业和政府作出正确的经济决策提供 必要的依据。通过银行&#xff0c;可以对国民经济各部…

白话机器学习4:小波分解的原理与Python代码实现

小波去噪可以想象成使用一把“筛子”来过滤信号。这个“筛子”能够根据信号的不同频率成分&#xff0c;将其分解成多个层次。在这个过程中&#xff0c;信号的重要信息通常包含在低频部分&#xff0c;而噪声则多分布在高频部分。 将信号通过这个“筛子”分解后&#xff0c;我们可…

OpenAI 重磅发布GPT 4o!可以视频聊天的AI?

OpenAI 重磅发布GPT 4o&#xff01; 前言 就在今日&#xff0c;OpenAI发布了ChatGPT-4o版本&#xff0c;技术主管 Mira Murati 在直播中表示GPT-4o对比之前版本速度更快&#xff0c;在文本、视频和音频方面的能力也都有所提高。值得注意的是它还可以让用户与 ChatGPT 进行视频聊…

Vue3使用datav3报错的三个问题解决

我这里写的是按需引入 报错问题Cannot find module dataview/datav-vue3 修改datav源码中的package.json文件 修改为 "module": "./es/index.mjs", 然就就会遇见新的报错问题 报错问题TypeError: Cannot read properties of null (reading $el) 然后修改…

QT切换控件布局

1、切换前垂直布局 2、切换后水平布局 3、关键代码 qDebug() << "开始切换布局";QWidget *widget centralWidget();QLayout *layout widget->layout();if(layout){while(layout->count()){QLayoutItem *item layout->takeAt(0);if(item->layout…

后仿真中的关于延时问题(延迟类型选择和脉冲控制)

目录 通过前面的文章提到,从物理特性角度出发,仿真中存在两种延时:惯性延时和传输延时。那么,实际仿真电路过程中,我们究竟选择的哪种模式呢? 一 指定传输延迟类型 传输延迟类型不是默认的延迟类型。我们需要显示指定它。 1.1 module-path delay VCS 仿真中添加如下三…

物联网促进信息化——​青创智通工业物联网解决方案​

随着传感器网络&#xff08;WSN)、无线射频识别&#xff08;RFID&#xff09;以及微电子机械系统(MEIVIS&#xff09;等技术的不断成熟,扩展了人们对信息获取和使用的能力&#xff0c;并将提高制造效率、改善产品质量、降低产品成本和资源消耗、为用户提供更加透明和个性化的服…

DC-DC直流升压线性可调电源模块电压控制输出0-50V/0-80V/0-100V/0-200V/0-250V/0-300V/0-500V/0-1000V

特点 效率高达 75%以上1*2英寸标准封装单电压输出可直接焊在PCB 上工作温度: -40℃~75℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好电压控制输出,输出电压随控制电压线性变化 应用 GRB 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#xff1a;4.5~9V、…

【绝对有用】快速掌握GPT-4o:详细免费使用指南!

GPT-4o 简介 北京时间5月14日&#xff0c;OpenAI举行了春季发布会&#xff0c;并发布了其新旗舰模型“GPT-4o”。据OpenAI首席技术官穆里穆拉蒂&#xff08;Muri Murati&#xff09;介绍&#xff0c;GPT-4o在继承GPT-4强大智能的基础上&#xff0c;进一步提升了文本、图像及语音…

从0到1,百亿级任务调度平台的架构与实现

尼恩&#xff1a;百亿级海量任务调度平台起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试机会&#x…

走进Java接口测试之多数据源切换示例

文章目录 一、前言二、demo实现2.1、开发环境2.2、构建项目2.3、配置数据源2.4、编写配置文件2.5、编写Dao层的mapper2.6、编写实体成层2.7、编写测试类2.8、验证结果 三、多数据源 demo 实现3.1、配置数据源3.2、增加pom文件3.3、修改数据源读取方式&#xff1a;3.4、增加动态…

Windows本地部署直播录屏利器Bililive-go并实现远程添加直播间录屏

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 1. Bililive-go与套件下载1.1 获取ffmpeg1.2 获取Bililive-go1.3 配置套件 2. 本地运行测试3. 录屏…

ChatGPT 4o 使用案例之一

2024年GPT迎来重大更新&#xff0c;OpenAI发布GPT-4o GPT-4o&#xff08;“o”代表“全能”&#xff09; 它可以接受任意组合的文本、音频和图像作为输入&#xff0c;并生成任意组合的文本、音频和图像输出。它可以在 232 毫秒内响应音频输入&#xff0c;平均为 320 毫秒&…