yolov7添加FPPI评价指标

学术上目标检测大多用mAP去评价一个模型的好坏,mAP用来作为比较模型的指标是挺好的,不过有个问题就是不够直观,比如mAP=0.9到底代表什么呢?平均一个图会误检几个呢?该取什么阈值呢?mAP说明不了,所以有时候我们还需要其他更直观的指标。

FPPI

fppi:false positive per image, 顾名思义就是平均每张图误检的个数。是目标检测中也比较常见的指标。FPPI与missrate(漏检率)可以构成如下的图像,曲线越低越好。
image.png
通过FPPI曲线图,我们可以知道在一个FPPI下面的漏检率,可以作为阈值选取的指导。

yolov7FPPI_5">yolov7中增加FPPI

FPPI实现

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

def fppi_per_class(tp, conf, pred_cls, target_cls, image_num, plot=False, save_dir='.', names=(), return_plt=False):
    """ 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 + 1e-16)  # 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:
        fig = plot_fppi_curve(fppi, miss_rate, miss_rate_at_fppi, Path(save_dir) / 'fppi_curve.png', names)

    if return_plt:
        return fppi, miss_rate, miss_rate_at_fppi, fig

    return miss_rate, fppi, miss_rate_at_fppi

和mAP比较类似
f p p i = f p / i m a g e _ n u m fppi=fp/{image\_num} fppi=fp/image_num
m i s s r a t e = 1 − r e c a l l missrate=1-recall missrate=1recall
将fppi以对数坐标画图:

def plot_fppi_curve(px,py, missrate_at_fppi, save_dir='fppi_curve.png', names=()):
    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]} {missrate_at_fppi[i].mean():.3f}')  # plot(recall, precision)
    
    ax.semilogx(px.mean(0), py.mean(1), linewidth=3, color='blue', label='all classes %.3f' % missrate_at_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)

    return fig

训练中调用

在test.py中在map计算的下方增加fppi的计算:

p, r, f1, mp, mr, map50, map, t0, t1, mfppi_1 = 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
........
........
stats = [np.concatenate(x, 0) for x in zip(*stats)]  # to numpy
if len(stats) and stats[0].any():
	p, r, ap, f1, ap_class = ap_per_class(*stats, plot=plots, save_dir=save_dir, names=names)
	miss_rate, fppi, miss_rate_at_fppi = fppi_per_class(*stats, plot=plots, image_num= image_num, save_dir=save_dir, names=names)
	mfppi_1 = miss_rate_at_fppi[:,0].mean()
	ap50, ap = ap[:, 0], ap.mean(1)  # AP@0.5, AP@0.5:0.95
	mp, mr, map50, map = p.mean(), r.mean(), ap50.mean(), ap.mean()
	nt = np.bincount(stats[3].astype(np.int64), minlength=nc)  # number of targets per class
else:
	nt = torch.zeros(1)# Print results
pf = "%20s" + "%12i" * 2 + "%12.3g" * 5  # print format
print(pf % ("all", seen, nt.sum(), mp, mr, map50, map, mfppi_1))
········
#返回fppi
return (mp, mr, map50, map, *(loss.cpu() / len(dataloader)).tolist(), mfppi_1), maps, t

wandb中增加,我习惯使用wandb, 所以加了这步,如果不使用wandb的话,上面的函数不返回fppi就不用修改train.py了:

train.py# Log
            tags = [
                "train/box_loss",
                "train/obj_loss",
                "train/cls_loss",  # train loss
                "metrics/precision",
                "metrics/recall",
                "metrics/mAP_0.5",
                "metrics/mAP_0.5:0.95",
                "val/box_loss",
                "val/obj_loss",
                "val/cls_loss",  # val loss,
                "val/missrate@fppi=1",
                "x/lr0",
                "x/lr1",
                "x/lr2",
            ]  # params

效果

训练过程中会在mAP的后面打印fppi, 训练完成后以及调用test.py测试时,会画fppi图:
image.png

结语

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


http://www.niftyadmin.cn/n/5288187.html

相关文章

【Qt-正则表达式】

Qt编程指南 ■ 正则表达式■ 演示代码■ 限定符■ ■■■■ ■ 正则表达式 ■ 演示代码 #include <QRegularExpressionValidator> QRegularExpressionValidator* m_validator1_10; m_validator1_10 new QRegularExpressionValidator(QRegularExpression("^(?:[1…

「GPT」G、P、T分别是啥意思?

G意为Generative &#xff1a;生成式 比如&#xff0c;生成式的分类器&#xff08;模型&#xff09;包括---- generative classifiers: naive Bayes classifier and linear discriminant analysis 与之对应的为判别式----- discriminative model: logistic regression P意为…

Autosar文档怎么食用

目录 一、文档下载 二、文档结构 三、文档内容 四、各部分介绍 1、Introdu

基于springboot+vue的教材管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

R语言绘图教程汇总 | 2023

2023年总结 2023年即将结束&#xff0c;我们即将迎来2024年。2023年&#xff0c;我们做了什么呢&#xff1f;&#xff1f;这个是个值得深思的问题…? 12月份是个快乐且痛苦时间节点。前一段时间&#xff0c;单位需要提交2023年工作总结&#xff0c;真的是憋了好久才可以下笔…

LazyForEach常见使用问题

目录 1、渲染结果非预期 2、重新渲染时图片闪烁 3、ObjectLink属性变化UI未更新 上篇文章中我们介绍了LazyForEach的基本使用&#xff0c;展示了如何使用LazyForEach构造一个列表&#xff0c;并演示数据的添加、删除、修改如何与LazyForEach配合并正确的更新UI。本篇将介绍使…

【WinForm.NET开发】设计具有更改通知的出色数据源

本文内容 简单绑定的更改通知基于列表的绑定的更改通知自定义控件的更改通知应用 PropertyNameChanged 模式实现 INotifyPropertyChanged 接口同步绑定 Windows 窗体数据绑定最重要的概念之一是更改通知。 为确保数据源和绑定控件始终具有最新数据&#xff0c;必须为数据绑定…

关于mysql8.0新特性的一些简单总结

在前面的文章中分享了一些mysql升级到8.0.x的一些实际做法&#xff0c;这里对mysql8.0.x的一些新特性或者是改良优化的地方做一些简单总结&#xff0c;可能涉及的方面不全或者个人理解不一样&#xff0c;见谅 參考参考官网&#xff1a;MySQL &#xff1a;&#xff1a; MySQL 8…