最近在学习和尝试改进yolov结记录一下原始代码的理解,希望大佬指正.10,在这里总
[1] 论文:https://arxiv.org/abs/2405.14458
[2] 代码:GitHub - THU-MIG/yolov10: YOLOv10: Real-Time End-to-End Object Detection [NeurIPS 2024]
YOLOv10的新特性
1. 无NMS训练
YOLOv10的一大亮点是其无NMS训练。传统的YOLO模型使用NMS来过滤重叠的预测,这增加了推理延迟。YOLOv10引入了一种双重分配策略,消除了NMS的需求,从而实现了更快、更高效的目标检测。
双重分配策略解释:
一对多分配:在训练过程中使用,以提供丰富的监督信号。
一对一分配:在推理过程中使用,以避免冗余预测。
通过使用一致的匹配度量协调这两种策略,YOLOv10在不牺牲性能的情况下实现了高效率。
2. 整体效率-准确性驱动设计
YOLOv10采用了一种全面的模型设计方法,优化了各种组件以提高效率和准确性。以下是一些关键创新:
轻量化分类头:通过使用深度可分离卷积,减少分类头的计算开销,而不显著影响性能。
空间-通道解耦下采样:通过分离空间缩减和通道增加操作,增强下采样效率,减少信息损失。
秩引导块设计:根据模型不同阶段的内在冗余,调整构建块的复杂度,确保参数的最佳利用。
3. 大核卷积和部分自注意力
为了进一步提高准确性,YOLOv10集成了大核卷积和部分自注意力(PSA)模块。这些组件提高了模型捕捉全局信息的能力,同时保持计算效率。
大核卷积:在较深阶段有选择地使用,以扩大感受野而不显著增加I/O开销。
PSA模块:以成本效益的方式引入自注意力,提升模型学习全局表示的能力
yaml文件理解
yolov10n.yaml文件源码如下.
# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
# [depth, width, max_channels]
n: [0.33, 0.25, 1024]
# YOLOv8.0n backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
- [-1, 1, PSA, [1024]] # 10
# YOLOv8.0n head
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 13
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 16 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 19 (P4/16-medium)
- [-1, 1, SCDown, [512, 3, 2]]
- [[-1, 10], 1, Concat, [1]] # cat head P5
- [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large)
- [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)
这里我将从上到下进行解释.
Parameters(参数)
nc:是类别数目,原文是80,若我的数据集的类别是10,则改为10
scales:是模型尺度,不同的尺度模型的参数和计算量不同,上文是n模型,但是其实yolov10的作者还提供了其他模型,如下图所示.
其中每个模型的三个参数分布是depth (深度因子),width(宽度因子),max_channels(最大通道数)
depth 网络模型深度因子 : 表示模型种重复模块的数量或层数的缩放比例(仅在repeats≠1时启用),后面举例表示其应用
width:宽度因子 表示模型中通道数(特征图的深度)的缩放比例 计算实际的通道数,主要作用于args中的ch_out(如第一个conv层,ch_out=64 ,那么在实际的运算过程中,会将其卷积核设为 64 * 0.25 = 16 ,故其会输出16通道的特征图)
amx_channels:每层的最大通道数 每层的通道数会与这个参数进行一个对比,如果特征图通道数大于这个数,那就取 max_channels的值。
backbone(主干)
backbone用于提取图像特征,为目标检测任务提供基础特征表示
[from,repeats,module,args]
from: -n 代表是从前n层获得的输入 代表从前一层获得输入
repeats 表示网络模块的数目
Module表示网络模块的名称
args :表示向不同模块内传递的参数[ch_out,kernel,stride,padding,groups] 没有ch_in,因为输入都是上层的输出
特征图公式:Feature_new = (Feature_old - kernel + 2 * padding) / stride + 1
例
首层input : 3*640*640
[ch_out,kernel,stride] = [64,3,2]
Feature_new = (640 - 3 + 2*1)/2 + 1 = 320
就是得到了P1/2的特征图,为 64 * 320 *320,通道数从3变成64,使得网络能够捕捉到更多的特征信息,提高网络的表达能力,同时减小特征图的空间维度,减少后续层的计算量,有助于网络的计算效率提升,同时卷积操作本身也增强了特征提取能力.
带注释的代码如下:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2 第0层:使用64个3x3的卷积核,步幅为2进行卷积,得到P1/2特征图
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4 第1层:使用128个3x3的卷积核,步幅为2进行卷积,得到P2/4特征图:
- [-1, 3, C2f, [128, True]] #第2层:进行3次C2f操作,每次操作使用128个通道,最后一次操作使用降维(True)
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8 #第3层:使用256个3x3的卷积核,步幅为2进行卷积,得到P3/8特征图,
- [-1, 6, C2f, [256, True]] #第4层:进行6次C2f操作,每次操作使用256个通道,最后一次操作使用降维(True)
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16第5层:使用512个3x3的卷积核,步幅为2进行卷积,得到P4/16特征图。
- [-1, 6, C2f, [512, True]] #第6层:进行6次C2f操作,每次操作使用512个通道,最后一次操作使用降维(True)
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32 第7层:使用1024个3x3的卷积核,步幅为2进行卷积,得到P5/32特征图
- [-1, 3, C2f, [1024, True]] #第8层:进行3次C2f操作,每次操作使用1024个通道,最后一次操作使用降维(True)
- [-1, 1, SPPF, [1024, 5]] # 9 第9层:使用1024个通道的SPPE(空间金字塔池化)层,使用5个不同大小的池化核进行池化操作。
- [-1, 1, PSA, [1024]] #第10层使用 PSA 机制对上一层的输出进行逐点空间注意力处理,生成具有更高关注度的特征图。这一层的作用在于提高模型对重要特征的关注度,从而增强模型的表现力
先举例说明上面的depth的作用,去[-1,3,C2f,[128,True]]进行说明,这里的repeats是3,depth = 0.33,3 * 0.33 = 1,表示这个cf模块在Bottelneck中只重复一次
head(头部)
head: 用于生成目标检测结.在目标检测任务中,“目标检测结” 实际上是指目标检测网络的输出部分,也称作 “检测头”(Detection Head)。检测头的作用是预测图像中各个目标的位置(通常是边界框)以及目标的类别.
它的具体运算和上面的backnone类似这里不再进行解释,含有部分注释的代码如下.
# YOLOv8.0n head
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] #上采样 #第0层:使用最近邻上采样(nn.WRsample)将特征图尺寸放大两倍
- [[-1, 6], 1, Concat, [1]] # cat backbone P4 ##第1层:将backbone提取的P4特征图与当前特征图进行拼接(Concat),生成新的特征图
- [-1, 3, C2f, [512]] # 12#第2层:进行3次C2f操作,使用512个通道,得到第12个特征图。
- [-1, 1, nn.Upsample, [None, 2, "nearest"]] #第3层:使用最近邻上采样将特征图尺寸放大两倍。
- [[-1, 4], 1, Concat, [1]] # cat backbone P3 #第4层:将backbone提取的P3特征图与当前特征图进行拼接,生成新的特征图。
- [-1, 3, C2f, [256]] # 15 (P3/8-small) 第5层:进行3次C2f操作,使用256个通道,得到第15个特征图(P3/8-small)。
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 19 (P4/16-medium)
- [-1, 1, SCDown, [512, 3, 2]]
- [[-1, 10], 1, Concat, [1]] # cat head P5
- [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large) #c2fcib是C2f模块的一个变种,结合了cIB(Channel-wise Information Bottleneck)模块,用于进一步压缩特征信息。
- [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5) #YOLOv10 检测头,从特征图中提取目标位置和类别信息,生成预测框。
#这部分主要多出3个操作nn.Upsample、Concat、Detect,解释如下:
#nn.Upsample:表示上采样,将特征图大小进行翻倍操作。比如将大小为20X20的特征图,变为40X40的特征图大小。
#Concat:代表拼接操作,将相同大小的特征图,通道进行拼接,要求是特征图大小一致,通道数可以不相同。例如[-1, 6]:-1代表上一层,6代表第六层(从第0层开始数),将上一层与第6层进行concat拼接操作。
#Detect的from有三个数,15,18,21,这三个就是最终网络的输出特征图,分别对应P3,P4,P5。
网络模型图
这里展示了网上看到的毕竟完整的模型图
1.backbone
2.head