YOLOv5-4.0-metrics.py 源代码导读
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-1pred_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...ni = 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曲线 并 计算每一个类别的APpx, py = np.linspace(0, 1, 1000), [] # for plottingpr_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_resultsn_p = i.sum() # 预测类别中为 类别c 的个数if n_p == 0 or n_l == 0: #如果没有预测到 或者 ground truth没有标注 则略过类别ccontinueelse:""" 计算 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_lrecall = 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曲线中计算APfor j in range(tp.shape[1]): #这里对每一个IOU阈值 下的参数进行计算 ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j]) #取每一个阈值计算APif 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)
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
