YOLOv8训练流程-原理解析[目标检测理论篇]

news2024/12/23 12:32:27

          关于YOLOv8的主干网络在YOLOv8网络结构介绍-CSDN博客介绍了,为了更好地学习本章内容,建议先去看预测流程的原理分析YOLOv8原理解析[目标检测理论篇]-CSDN博客,再次把YOLOv8网络结构图放在这里,方便随时查看。

1.前言

          YOLOv8训练流程这一块内容还是比较复杂的,所以先来谈一下训练流程的思路,一共就两步:第一步就是从网络预测的结果中找到正样本,并且确定正样本要预测的对象;第二步就是计算预测结果和标签之间的损失,分别计算预测框的损失以及预测类别的损失。

         如下图所示,假设一张图片中只有3个标签,那么需要从8400个Grid cell中找到这3个标签对应的正样本,然后通过计算正样本的预测值和标签值之间的损失,最后通过损失的反向传播更新模型的权值和偏差。

 

        为了更好地理解YOLOv8或者说是YOLO系列网络,需要对Grid cell建立概念,如下所示:

        首先可以看到通过网络输出的三个特征图的分辨率分别为:80*80,40*40,20*20,本文所说的Grid cell即为图中的红点、蓝点以及黄点,从图中可以得到以下信息:第一,红点代表的Grid cell是80*80分辨率中每个像素的中心点,因为红色Grid cell比较密集并且可以x8将红点映射回原图,所以80*80分辨率的特征图Grid cell是用来训练小目标的,蓝色和黄色Grid cell同理;第二,如果8400个Grid cell全部当成正样本的话是不实际的,所以必须从这8400个Grid cell中选出一些正样本;第三,由于YOLOv8是Anchor Free的模型,所以会将这三个尺度的特征图展开变成长度为8400的一维向量。

2. Task Aligned Assigner

        Task Aligned Assigner中文翻译为任务对齐分配器,是一种正负样本分配策略,也就是找正样本的方法,也就是训练流程中的第一步。

         在正式开始找正样本之前,需要先把网络预测值Box和Cls解码,同时也需要把标签的Box和Cls解码,过程如下图所示:首先是网络预测结果Pred的Box需要解码成4维,用来预测LTRB的(解码过程在预测原理第三章有提到YOLOv8预测流程-原理解析[目标检测理论篇]-CSDN博客),另外还需要转换为XYXY格式且预测的坐标值是相对于网络输入尺寸的(即640*640);Cls只需要使用Sigmoid()解码就行。其次是标签Target的解码,其实只有Box需要解码,为了和Pred的解码格式保持一致,需要将XYWH格式转换为XYXY,并且标签值对应的坐标是相对于网络输入尺寸(即640*640)。

        然后正式开始找正样本了,假设一张图片上只有一个GT Box,使用红色框作为标记。由于已经将三个特征图下的grid cell都转换到640*640坐标系了,结合GT框的位置和大小,找到合适的中心点作为训练的正样本,这就是TaskAlignedAssigner的任务,一共分成三步,即初步筛选,精细筛选,剔除多余三个步骤。

        (1)初步筛选:即select_candidates_in_gts,转换之后的Grid Cell落在GT Box内部,作为初步筛选的正样本,如图中所示红色点为初步筛选的Grid Cell,而落在GT Box外部的点或者落在GT Box角上或者边上的都需要过滤掉,如蓝色点所示;经过初步筛选,图2中9个红色的点作为初筛后留下的正样本点。

 (2)精细筛选:即get_box_metrics,select_topk_candidates,通过公式align_metric=s^α∗u^β(s和u分别表示分类得分和CIoU得分, a和b是权重系数,默认值分别0.5和6.0),计算出每个预测框的得分,然后把得分低的预测框给过滤掉,一般会取得分最高的top10个gird cell。

        其中分类得分,取的在是GT Box内对应的类别的预测值,比如该GT的类别下标为1,那么落在GT box内的点所预测的类别下标为1时的置信度。另外计算IoU使用的是CIoU,计算公式和计算过程如下所示,如何理解CIoU呢,IoU并无法充分表示预测框和标注框之间的关系,需要引入中心点距离,以及最小矩形框斜边距离,通过这两者的比值来表示预测框和标注框的相似度。所以会在IoU的基础上减去该比值,再减去由预测框宽高和标注框宽高组成的式子。

        (3)剔除多余:保证一个Grid Cell只预测一个GT框,如果一个Grid Cell同时匹配到两个GT Box,那么将从这两个GT中,选出与他CIoU值最大的一个作为他要预测的GT Box。如图所示,Grid Cell A、B、C负责预测GT1,包括预测GT1的类别和Box,而Grid Cell D负责预测GT2,也是预测类别和Box。 

3.Loss

         YOLOv8的Loss由三部分组成:Loss_box,Loss_cls,Loss_DFL分别表示回归框损失,类比损失和DFL损失(其实也是回归框的损失),下面会详细介绍这三种损失。

        还是先来简单了解下Loss计算的思路,如下图所示:左边Target表示标签值,右边Pred表示预测值,均需要借助上一章找到的正样本,然后通过对比同一个Grid cell正样本的预测值和标签值,计算对应的Loss。 

        先来看一下get_targets函数做了哪些处理,GT_Box是经过预处理的,(1,3,4)表示XYXY且相对于640*640尺度的坐标。GT_Cls没有经过处理,表示GT_Box1、 GT_Box2、 GT_Box3的类别。

    假设GT1的box是(x0,y0,X0,Y0),cls是0; GT2的box是(x1,y1,X1,Y1),cls是1;根据找到的正样本和负样本来举个例子,其中负样本为E,正样本为A/B/C/D.由图可以看到Target_Score在这一步已经区分了正负样本了,其中负样本使用[0,0]来表示。而Target_Bbox并没有区分正负样本,负样本统统会选择第1个GT的Box作为其Target_Bbox,换句话说,Target_Bbox值为[x0,y0,X0,Y0]的Grid cell可能为正样本也可能为负样本。

        

3.1Loss_cls 

         下面是YOLOv8中计算Loss_cls的代码:

target_scores_sum = max(target_scores.sum(), 1)

loss[1] = self.bce(pred_scores, target_scores.to(dtype)).sum() / target_scores_sum   # BCE

        而主要的部分是Loss_cls采用了BCELoss损失函数,损失计算公式如下(注意:YOLOv8中的Cls使用的是BCEWithLogitsLoss,传入的预测值是不需要自己进行Sigmoid,损失内部会自动进行sigmoid,但我这里演示使用的是BCELoss):

        假设当前只有两个类别,取出其中三个Grid cell的值,其中(0,0)表示负样本,(0,1)和(1,0)表示正样本,经过Normalize后得到带有权重的真实标签,这里正负样本均计算Loss.

3.2Loss_box

        下面是YOLOv8中计算Loss_box的代码:

iou = bbox_iou(pred_bboxes[fg_mask], target_bboxes[fg_mask], xywh=False, CIoU=True)

loss_iou = ((1.0 - iou) * weight).sum() / target_scores_sum

         而主要的部分是Loss_box采用了CIoULoss损失函数,损失计算公式如下:

        由前面可知,经过get_targets后的Target_Bbox并没有区分正负样本,因此下一步将利用fg_mask来区分正负样本,从而得到30个正样本。对Box会求两个损失,所以有Target_Bbox1和Target_Bbox2,都需要还原到各自的特征图的比例进行计算(可能这样数字比较小计算比较方便),并且分别采用XYXY格式和LTRB格式表示。

        另一方面,Pred_Box1需要通过网络预测的结果(1,64,8400)解码成(1,4,8400)并采用XYXY坐标的格式表示,并且找到对应的30个正样本和Target_Bbox1计算CIoU损失;Pred_Box2则是直接把网络预测的结果(1,64,8400)取出来,然后找到对应的30个正样本,和Target_Bbox1计算DFL损失。

         这里再说一下为什么会是30个正样本,因为有3个GT,每个GT取top10个得分最高的grid cell,并且这30个中没有因重复而被过滤掉的Grid cell。

3.3Loss_DFL 

         下面是YOLOv8中计算Loss_DFL的代码:

loss_dfl = self._df_loss(pred_dist[fg_mask].view(-1, self.reg_max + 1), target_ltrb[fg_mask]) * weight

loss_dfl = loss_dfl.sum() / target_scores_sum

        而主要的部分是Loss_DFL,损失计算公式如下:

        下面演示一个Grid cell正样本LTRB的计算过程:

        首先,Pred_Box2即Pred_dist,是一个(120,16)的矩阵,可以理解为(30*4,16),即共有30个正样本,每个正样本需要预测LTRB四个数值,并且这四个数又分别通过0~15来表示。其次,Target_Bbox2即Target,是一个(120,1)的向量,分别对应着30个样本中每个样本的LTRB真实值。最后,由于Target一般不会是整数值,所以需要计算相邻的两个真实值对应的损失。损失函数使用Cross_entropy损失.

        前面提到了由于Target一般不会是整数值,所以需要计算相邻的两个真实值对应的损失,那么如何选择呢?这两个损失之间的权重又是怎么样的呢?为了加深理解,又单独举例演示该Grid cell中的Top_loss是怎么计算的:

        该正样本需要对GT对应的LTRB中的T为例,该正样本的中心点距离上边框是7.29像素,因为网络预测只能是0~15的整数,那么只能选择7和8这两个相邻的值作为标签值,即yi=7和yi+1=8。接下来是选择这两个损失的权重,遵循一个原则:离得越近权重越大,所以当计算标签为7的时候,选择权重0.71,即yi+1-y;而计算标签为8的时候,选择权重0.21,即y-yi+1。

    前面也提到了损失函数使用Cross_entropy损失,和BCE损失有两点区别,第一是把网络预测的每个正样本的LTRB值都需要进行SoftMax(),使得∑value=1,这和预测的时候是一样的;第二是只选取标签值对应的值作为损失,比如在该正样本预测Top的损失计算中,有7和8两个标签值,那么7对应的损失值为1.4676,即-Log(Si),8对应的损失值为1.6825,即-log(Si+1)。最后该正样本的Loss_Top为1.53,该正样本的总损失为(Loss_Left+ Loss_Top+ Loss_Right+ Loss_Bottom)/4.

        训练过程的原理会稍微复杂,先整理成这样子,后面我再优化下表达,争取每个人都可以看得懂。

         

       

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

geoserver SQL注入、Think PHP5 SQL注入、spring命令注入

文章目录 一、geoserver SQL注入CVE-2023-25157二、Think PHP5 SQL注入三、Spring Cloud Function SpEL表达式命令注入(CVE-2022-22963) 一、geoserver SQL注入CVE-2023-25157 介绍:GeoServer是一个开源的地理信息系统(GIS&#…

[C/C++] -- 大数的加减法

大数加减法的问题主要产生于计算机基本数据类型的表示范围限制。通常情况下,计算机采用有限位数的数据类型(如int、long)来表示整数,这些数据类型的表示范围有限,无法表示超出范围的大整数。 例如超过了long类型的表示…

支持播放h265的插件

插件源码地址:GitCode - 开发者的代码家园https://gitcode.com/mirrors/nanguantong/flv-h265.js/overview 1. 下载代码 运行以下命令 npm i npm run build npm run build 后生成 flv.min.js 文件,引入使用 2. 调用 js 文件: let flvj…

【数据结构】链式栈

链式栈 一、链式栈的栈顶在哪里? 二、链式栈的结构: typedef struct LSNode {int data;struct LSNode* next; }LSNode, *PLStack; // 链栈的节点,由于栈顶在第一个数据节点,所以不需要top指针三、链式栈的实现 //初始化 void …

价格中间加横杠

<span></span>59 <span class"price">177</span>.price{ text-decoration:line-through; }

vue2和vue3区别: 探索关键差异

vue2和vue3区别&#xff1a; 探索关键差异 Vue.js 作为流行的前端框架&#xff0c;其版本 3 带来了许多令人兴奋的改进和新功能。虽然 Vue 3 保持了与 Vue 2 的相似性&#xff0c;但也存在一些关键差异需要开发者注意。本文将通过表格形式&#xff0c;清晰地展现 Vue 2 和 Vue …

清理缓存简单功能实现

在程序开发中&#xff0c;经常会用到缓存&#xff0c;最常用的后端缓存技术有Redis、MongoDB、Memcache等。 而有时候我们希望能够手动清理缓存&#xff0c;点一下按钮就把当前Redis的缓存和前端缓存都清空。 功能非常简单&#xff0c;创建一个控制器类CacheController&#xf…

Android Studio连接MySQL8.0

【序言】 移动平台这个课程要做一个app的课设&#xff0c;我打算后期增加功能改成毕设&#xff0c;就想要使用MySQL来作为数据库&#xff0c;相对于SQLlite来说&#xff0c;我更熟悉MySQL一点。 【遇到的问题】 一直无法连接上数据库&#xff0c;开始的时候查了很多资料&#…

Jmeter中线程组介绍

1.线程数的意义 Jmeter采用了线程来模拟用户&#xff0c;即1个线程代表1个用户&#xff0c;线程可以简单理解为计算机处理任务时的一个具体执行人。 一个任务可以由多个人&#xff08;线程&#xff09;共同完成&#xff0c;也可以由一个人&#xff08;线程&#xff09;来完成&a…

基于LLM的自行车道CAD

LLM&#xff08;大型语言模型&#xff09;是强大的工具。对于许多人来说&#xff0c;用语言表达愿望通常比浏览复杂的 GUI 更简单。 1、系统简介和环境搭建 urb-x.ch&#xff0c;这是一家专门从事自行车道建设的公司。轨道采用模块化构建块进行独特设计&#xff0c;可以通过多…

AI工具的热门与卓越:揭示AI技术的实际应用和影响

文章目录 每日一句正能量前言常用AI工具创新AI应用个人体验分享后记 每日一句正能量 我们在我们的劳动过程中学习思考&#xff0c;劳动的结果&#xff0c;我们认识了世界的奥妙&#xff0c;于是我们就真正来改变生活了。 前言 随着人工智能&#xff08;AI&#xff09;技术的快…

prometheus、mysqld_exporter、node_export、Grafana安装配置

工具简介 Prometheus&#xff08;普罗米修斯&#xff09;&#xff1a;是一个开源的服务监控系统和时间序列数据库 mysqld_exporter&#xff1a; 用于监控 mysql 服务器的开源工具&#xff0c;它是由 Prometheus 社区维护的一个官方 Exporter。该工具通过连接到mysql 服务器并执…

每日一题9:Pandas-填充缺失值

一、每日一题 DataFrame products --------------------- | Column Name | Type | --------------------- | name | object | | quantity | int | | price | int | ---------------------编写一个解决方案&#xff0c;在 quantity 列中将缺失的值 编…

flutter开发实战-人脸识别相机使用

flutter开发实战-人脸识别相机使用 当需要拍摄的时候&#xff0c;需要检测到人脸再进行后续的操作&#xff0c;这里使用的是face_camera 一、引入face_camera 在工程的pubspec.yaml中引入插件 # 检测人脸face_camera: ^0.0.8iOS端需要设置相关权限 在info.plist文件中&…

编程代码的舞者--Python循环语句

循环语句是编程中不可或缺的要素之一&#xff0c;它们能够让程序反复执行特定的任务&#xff0c;提高代码的重复利用性和效率。在本篇博客中&#xff0c;我们将深入探讨Python中常用的循环语句&#xff0c;包括for循环和while循环&#xff0c;以及控制循环流程的关键字break和c…

【Win10设备管理器中无端口选项】

计算机疑难杂症分享002 Win10设备管理器中无端口选项1、问题现象2、问题原因3、问题解决3.1、驱动精灵(亲测的此方法)3.2、添加过时硬件3.3、官方的方法 Win10设备管理器中无端口选项 1、问题现象 当我调试串口通信时&#xff0c;发现打开设备管理器没有端口&#xff0c;打开…

系统需求开发和管理指南(软件标准文件Word)

1.需求获取的方式 2.需求分析的准则 3.需求分析的方法 4.需求开发考虑的方面 5.需求确认的方法 6.需求优先级的设定 7.需求文档编制规范要求 软件全文档获取方式一&#xff1a;本文末个人名片直接获取。 软件全文档获取二&#xff1a;软件项目开发全套文档下载_软件项目文档-C…

Unity开发中导弹路径散射的原理与实现

Unity开发中导弹路径散射的原理与实现 前言逻辑原理代码实现导弹自身脚本外部控制脚本 应用效果结语 前言 前面我们学习了导弹的追踪的效果&#xff0c;但是在动画或游戏中&#xff0c;我们经常可以看到导弹发射后的弹道是不规则的&#xff0c;扭扭曲曲的飞行&#xff0c;然后击…

Leetcode39.组合总和

文章目录 题目描述解题思路重复子集剪枝 代码 题目 参考题解 题目描述 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返…

Python | Leetcode Python题解之第78题子集

题目&#xff1a; 题解&#xff1a; class Solution:def subsets(self, nums: List[int]) -> List[List[int]]:self.res []self.backtrack([], 0, nums)return self.resdef backtrack(self, sol, index, nums):self.res.append(sol)for i in range(index, len(nums)):self…