昨天有群友,在交流群【群号:392784757】里提到了这个需求,进行实现一下

V10 官方代码结构相较于 V8 稍微复杂一些

yolov10 是基于 v8 的代码完成开发,yolov10 进行了继承来简化代码开发

因此 V10 的代码修改 基本和 V8 这篇一致

https://blog.csdn.net/csy1021/article/details/134406419

但存在一些不同,会在下面提到

版本环境

YOLOv10 2024.07.01 版本

修改

trainer.py

1 添加 save_metrics_per_class()

在 save_metrics 函数后面,添加下面的 save_metrics_per_class 函数

def save_metrics_per_class(self, box):

    """Saves training metrics per class to a CSV file."""

    # ap ap50 p r 提示作用
keys = ['ap', 'ap50', 'p', 'r']
n = 4 + 1 # number of cols for i in box.ap_class_index:
cur_class = self.model.names[box.ap_class_index[i]]
save_path = self.save_dir.joinpath("result_" + cur_class + ".csv")
vals = [box.ap[i], box.ap50[i], box.p[i], box.r[i]]
s = '' if save_path.exists() else (('%23s,' * n % tuple(['epoch'] + keys)).rstrip(',') + '\n') # header with open(save_path, 'a') as f:
f.write(s + ('%23.5g,' * n % tuple([self.epoch] + vals)).rstrip(',') + '\n')

2 validate() 修改

def validate(self):
"""
Runs validation on test set using self.validator. The returned dict is expected to contain "fitness" key.
"""
# metrics = self.validator(self)
metrics,box = self.validator(self)
fitness = metrics.pop("fitness", -self.loss.detach().cpu().numpy()) # use loss as fitness measure if not found
if not self.best_fitness or self.best_fitness < fitness:
self.best_fitness = fitness
# return metrics, fitness
return metrics, fitness,box

找到【这里比 v8 的判断要多】

if (self.args.val and (((epoch+1) % self.args.val_period == 0) or (self.epochs - epoch) <= 10)) \
or final_epoch or self.stopper.possible_stop or self.stop:
self.metrics, self.fitness = self.validate()

修改为

if (self.args.val and (((epoch+1) % self.args.val_period == 0) or (self.epochs - epoch) <= 10)) \
or final_epoch or self.stopper.possible_stop or self.stop:
# self.metrics, self.fitness = self.validate()
self.metrics, self.fitness,box = self.validate()

3 找到 self.save_metrics



self.save_metrics(metrics={**self.label_loss_items(self.tloss), **self.metrics, **self.lr})

后面添加调用

self.save_metrics_per_class(box)

validator.py

找到 stats = self.get_stats()

改为 stats,box = self.get_stats()

找到 return {k: round(float(v), 5) for k, v in results.items()}

改为 return {k: round(float(v), 5) for k, v in results.items()}, box

val.py

get_stats() 【注意与 v8 不同】

def get_stats(self):
"""Returns metrics statistics and results dictionary."""
stats = {k: torch.cat(v, 0).cpu().numpy() for k, v in self.stats.items()} # to numpy
# if len(stats) and stats["tp"].any():
# if len(stats) and stats[0].any():
if len(stats) :
self.metrics.process(**stats)
self.nt_per_class = np.bincount(
stats["target_cls"].astype(int), minlength=self.nc
) # number of targets per class
# return self.metrics.results_dict
return self.metrics.results_dict,self.metrics.box

save_metrics_per_class() 函数 【注意与 v8 不同】


可以看到支持的指标有 all_ap (可用来计算其他ap指标),map,map50,f1,p ap,r mr ...
我在函数中使用的是 ap,ap50,p,r,需要其他的可以再添加
==注意:添加指标,使用的是 . 而不是 ["xxxx"] 如 box.ap[i] 而不是 box['ap'][i]==

def save_metrics_per_class(self, box):

    """Saves training metrics per class to a CSV file."""

    # ap ap50 p r 提示作用
keys = ['ap', 'ap50', 'p', 'r']
n = 4 + 1 # number of cols for i in box.ap_class_index:
cur_class = self.model.names[box.ap_class_index[i]]
save_path = self.save_dir.joinpath("result_" + cur_class + ".csv")
vals = [box.ap[i], box.ap50[i], box.p[i], box.r[i]]
s = '' if save_path.exists() else (('%23s,' * n % tuple(['epoch'] + keys)).rstrip(',') + '\n') # header with open(save_path, 'a') as f:
f.write(s + ('%23.5g,' * n % tuple([self.epoch] + vals)).rstrip(',') + '\n')

注意!不同点

def get_stats(self):
"""Returns metrics statistics and results dictionary."""
stats = {k: torch.cat(v, 0).cpu().numpy() for k, v in self.stats.items()} # to numpy
# if len(stats) and stats["tp"].any(): # v10
# if len(stats) and stats[0].any(): # v8
if len(stats) : # 修改后
self.metrics.process(**stats)
self.nt_per_class = np.bincount(
stats["target_cls"].astype(int), minlength=self.nc
) # number of targets per class
# return self.metrics.results_dict
return self.metrics.results_dict,self.metrics.box

v10



v8

如果不修改 这个判断条件

if len(stats) and stats["tp"].any(): # v10
# if len(stats) and stats[0].any(): # v8 仅作对比
if len(stats) : # 修改后

可能会出现 前几次 epoch 数据不记录的问题 【这里也可能是和我的数据集有关,我测试了几次,增加 batch-size 发现仍然 stats["tp"] 仍然全为 false 过不了,后面 epoch 会正常 】这里大家可以自行测试后决定,如果正常,就不需要改

其他

增加训练过程各类指标打印(可选,默认开启是有条件的)

val.py 找到 print_results() 函数 在

LOGGER.info(pf % ('all', self.seen, self.nt_per_class.sum(), *self.metrics.mean_results())) 后面

添加

for i, c in enumerate(self.metrics.ap_class_index):
LOGGER.info(pf % (self.names[c], self.seen, self.nt_per_class[c], *self.metrics.class_result(i)))

有问题,欢迎留言、进群讨论或私聊:【群号:392784757】

YOLOv10添加输出各类别训练过程指标的更多相关文章

  1. (转)理解YOLOv2训练过程中输出参数含义

    最近有人问起在YOLOv2训练过程中输出在终端的不同的参数分别代表什么含义,如何去理解这些参数?本篇文章中我将尝试着去回答这个有趣的问题. 刚好现在我正在训练一个YOLOv2模型,拿这个真实的例子来讨 ...

  2. 理解YOLOv2训练过程中输出参数含义

    原英文地址: https://timebutt.github.io/static/understanding-yolov2-training-output/ 最近有人问起在YOLOv2训练过程中输出在 ...

  3. TensorFlow从1到2(七)线性回归模型预测汽车油耗以及训练过程优化

    线性回归模型 "回归"这个词,既是Regression算法的名称,也代表了不同的计算结果.当然结果也是由算法决定的. 不同于前面讲过的多个分类算法或者逻辑回归,线性回归模型的结果是 ...

  4. 深度学习笔记之关于基本思想、浅层学习、Neural Network和训练过程(三)

    不多说,直接上干货! 五.Deep Learning的基本思想 假设我们有一个系统S,它有n层(S1,…Sn),它的输入是I,输出是O,形象地表示为: I =>S1=>S2=>….. ...

  5. 交叉熵代价函数——当我们用sigmoid函数作为神经元的激活函数时,最好使用交叉熵代价函数来替代方差代价函数,以避免训练过程太慢

    交叉熵代价函数 machine learning算法中用得很多的交叉熵代价函数. 1.从方差代价函数说起 代价函数经常用方差代价函数(即采用均方误差MSE),比如对于一个神经元(单输入单输出,sigm ...

  6. 吴裕雄 python 神经网络——TensorFlow 训练过程的可视化 TensorBoard的应用

    #训练过程的可视化 ,TensorBoard的应用 #导入模块并下载数据集 import tensorflow as tf from tensorflow.examples.tutorials.mni ...

  7. DL4J实战之六:图形化展示训练过程

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<DL4J实战>系列的第六 ...

  8. 深度学习训练过程中的学习率衰减策略及pytorch实现

    学习率是深度学习中的一个重要超参数,选择合适的学习率能够帮助模型更好地收敛. 本文主要介绍深度学习训练过程中的6种学习率衰减策略以及相应的Pytorch实现. 1. StepLR 按固定的训练epoc ...

  9. 从零搭建Pytorch模型教程(四)编写训练过程--参数解析

    ​  前言 训练过程主要是指编写train.py文件,其中包括参数的解析.训练日志的配置.设置随机数种子.classdataset的初始化.网络的初始化.学习率的设置.损失函数的设置.优化方式的设置. ...

  10. (原)torch的训练过程

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/6221622.html 参考网址: http://ju.outofmemory.cn/entry/284 ...

随机推荐

  1. spring与设计模式之五委派模式

    一.定义 主要突出一个安排,派遣. 这个设计模式非常常见,不需要学习也能自然而然地用上. 从广义的角度出发,一个对象用另外一个对象就是委派. 二.经典实现 略. 三.spring实例代码 https: ...

  2. 【排行榜】Carla leaderboard 排行榜 运行与参与手把手教学

    此分支主要供参与leaderboard排名使用,介绍如何构建队伍,提交自己代码,此部分较为简单,主要是基本教学与演示:后续可以参考更多的开源代码进行学习等. 基本参与此榜单的大多都是学校和实验室,还是 ...

  3. 都是全志T113处理器,“-i”和“-S3”有什么区别?

    自9个月前,创龙科技"1片含税就79元"的全志T113-i双核ARM Cortex-A7@1.2GHz的工业核心板(SOM-TLT113)推出之后,不少嵌入式软硬件工程师.用户都咨 ...

  4. Java在创建同名目录/同名文件时名称拼接(数字)

    /** * 创建同名文件名称拼接(数字) * * @param path 需要创建的目录 * @return */ public static String recursionMkdirsFile(S ...

  5. LVGL一键打包图片工具,全部图片打包成一个bin文件,支持nor flash XIP模式下直接访问数据显示

    最近做工程项目,需要用到LVGL,但是搜了很长时间没有看到合适的图片打包工具,大多都是生成数组或者单个的bin文件,这样烧录到nor flash很麻烦 后来看到一篇博客,博主的想法与我类似,不过他后面 ...

  6. yb课堂之分布式应用下登陆校验解决方案 JWT讲解 json wen token 《八》

    什么是JWT? JWT是一个开放标准,它定义了一种用户简介,自包涵的用于通信双方之间以JSON对象的形式安全传递信息的方法.可以使用HMAC算法或者是RSA的公钥密钥进行签名 简单来说:就是通过一定规 ...

  7. Java异步判断线程池所有任务是否执行完成的方法

    1.使用ExecutorService和CountDownLatch的方法示例 在Java中,当我们使用线程池(如ExecutorService)来执行异步任务时,常常需要知道所有任务是否都已经完成. ...

  8. 解决方案 | pywintypes.com_error: (-2147221005, '无效的类字符串', None, None) --Python连接CAD报错真正解决思路!

    1 背景 import pythoncom import win32com.client import math wincad = win32com.client.Dispatch("Aut ...

  9. TIER 1: Sequel

    TIER 1: Sequel MySQL MySQL 是一种流行的开源关系型数据库管理系统(RDBMS),它被广泛用于存储和管理大量的结构化数据.MySQL 是由瑞典公司 MySQL AB 开发的,后 ...

  10. 树莓派配置固定IP地址

    树莓派配置固定IP地址 1.编辑文件/etc/dhcpcd.confroot@raspberrypi:~# vi /etc/dhcpcd.conf 2.修改以下参数配置,如果没有就在文件底部添加有线配 ...