YOLOv5-4.0-metrics.py 源代码导读

本文介绍了YOLOv5目标检测算法的4.0版本,并详细解读了metrics.py文件,该文件负责计算P、R、F1-score、AP和mAP等指标,并进行可视化,包括混淆矩阵和P-R曲线的绘制。重点讲解了fitness函数、ap_per_class函数、ConfusionMatrix类以及plot_pr_curve函数的用途。
摘要由CSDN通过智能技术生成

YOLOv5介绍

YOLOv5为兼顾速度与性能的目标检测算法。笔者将在近期更新一系列YOLOv5的代码导读博客。YOLOv5为2021.1.5日发布的4.0版本。
YOLOv5开源项目github网址
源代码导读汇总网址
本博客导读的代码为utils文件夹下的metrics.py

metrics.py

该文件通过获得到的预测结果与ground truth表现计算指标P、R、F1-score、AP、不同阈值下的mAP等。同时,该文件将上述指标进行了可视化,绘制了混淆矩阵以及P-R曲线。
相关导入模块及说明如下所示。

from pathlib import Path        #调用路径操作模块
import matplotlib.pyplot as plt #matplotlib画图软件
import numpy as np              #numpy矩阵处理模块
import torch                    #pytorch
from . import general           #从当前文件所处的相对路径调用general.py

fitness函数 通过指标加权的形式返回适应度

def fitness(x):
    # 以矩阵的加权组合作为模型的适应度
    w = [0.0, 0.0, 0.1, 0.9]  # 每个变量对应的权重 [P, R, mAP@0.5, mAP@0.5:0.95]
    # (torch.tensor).sum(1) 每一行求和tensor为二维时返回一个以每一行求和为结果的行向量 
    return (x[:, :4] * w).sum(1)

ap_per_class 函数计算每一个类的AP指标

def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision-recall_curve.png', names=[]):
    """ 计算平均精度(AP),并绘制P-R曲线
    源代码来源: https://github.com/rafaelpadilla/Object-Detection-Metrics.
    # Arguments(变量)
        tp:  True positives (nparray, nx1 or nx10).   真阳
        conf:  Objectness value from 0-1 (nparray).   目标的置信度取值0-1
        pred_cls:  Predicted object classes (nparray).预测目标类别
        target_cls:  True object classes (nparray).   真实目标类别
        plot:  Plot precision-recall curve at mAP@0.5 是否绘制P-R曲线 在mAP@0.5的情况下
        save_dir:  P-R曲线图的保存路径
    # Returns(返回)
        像faster-rcnn那种方式计算AP (这里涉及计算AP的两种不同方式 建议查询)
        The average precision as computed in py-faster-rcnn.
    """

    # 将目标进行排序
    # np.argsort(-conf)函数返回一个索引数组 其中每一个数按照conf中元素从大到小 置为 0,1...n
    i = np.argsort(-conf)
    # tp conf pred_cls 三个矩阵均按照置信度从大到小进行排列
    tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]

    # 找到各个独立的类别
    # np.unique()会返回输入array中出现至少一次的变量 这里返回所有独立的类别
    unique_classes = np.unique(target_cls)

    # 创建P-R曲线 并 计算每一个类别的AP
    px, py = np.linspace(0, 1, 1000), []  # for plotting
    pr_score = 0.1  # 评估P和R的分数 参考论坛https://github.com/ultralytics/yolov3/issues/898
    
    # 第一个为类别数目, 第二为IOU loss阈值的类别的 (i.e. 10 for mAP0.5...0.95)
    s = [unique_classes.shape[0], tp.shape[1]]  
    #初始化 对每一个类别在每一个IOU阈值下面 计算P R AP参数
    ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s) 
    for ci, c in enumerate(unique_classes): # ci为类别对应索引 c为具体的类别
        # i为一个包含True/False 的列表 代表 pred_cls array 各元素是否与 类别c 相同
        i = pred_cls == c 
        n_l = (target_cls == c).sum()  # ground truth中 类别c 的个数 all_results
        n_p = i.sum()  # 预测类别中为 类别c 的个数

        if n_p == 0 or n_l == 0: #如果没有预测到 或者 ground truth没有标注 则略过类别c
            continue
        else:
            """ 
            计算 FP(False Positive) 和 TP(Ture Positive)
            tp[i] 会根据i中对应位置是否为False来决定是否删除这一位的内容,如下所示:
            a = np.array([0,1,0,1]) i = np.array([True,False,False,True]) b = a[i]
            则b为:[0 1]
            而.cumsum(0)函数会 按照对象进行累加操作,如下所示:
            a = np.array([0,1,0,1]) b = a.cumsum(0)
            则b为:[0,1,1,2]
            (FP + TP = all_detections 所以有 fp[i] = 1 - tp[i])
            所以fpc为 类别c 按照置信度从大到小排列 截止到每一位的FP数目
                tpc为 类别c 按照置信度从大到小排列 截止到每一位的TP数目
            recall 和 precision 均按照元素从小到大排列
            """
            fpc = (1 - tp[i]).cumsum(0)
            tpc = tp[i].cumsum(0) 

            # 计算Recall
            # Recall = TP / (TP + FN) = TP / all_results = TP / n_l
            recall = tpc / (n_l + 1e-16)  # 加一个1e-16的目的是防止n_l为0 时除不开
            """
            np.interp() 函数第一个输入值为数值 第二第三个变量为一组x y坐标 返回结果为一个数值
            这个数值为 找寻该数值左右两边的x值 并将两者对应的y值取平均 如果在左侧或右侧 则取 边界值
            如果第一个输入为数组 则返回一个数组 其中每一个元素按照上述计算规则产生
            """
            r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0])     # pr_score 处的y值

            # 计算Precision
            # Precision = TP / TP + FP = TP / all_detections 
            precision = tpc / (tpc + fpc)  
            p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0])  # pr_score 处的y值

            # 从P-R曲线中计算AP
            for j in range(tp.shape[1]): #这里对每一个IOU阈值 下的参数进行计算 
                ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) #取每一个阈值计算AP
                if plot and (j == 0):
                    py.append(np.interp(px, mrec, mpre))  # mAP@0.5处的P

    # 计算F1分数 P和R的调和平均值
    f1 = 2 * p * r / (p + r + 1e-16)

    if plot:
        plot_pr_curve(px, py, ap, save_dir, names
  • 7
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 27
    评论
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值