💡💡💡本文主要内容:真正实时端到端目标检测(原理介绍+代码详见+结构框图)| yolov10如何训练自己的数据集(neu-det为案列)
博主简介
ai小怪兽,yolo骨灰级玩家,1)yolov5、v7、v8优化创新,轻松涨点和模型轻量化;2)目标检测、语义分割、ocr、分类等技术孵化,赋能智能制造,工业项目落地经验丰富;
原创自研系列, 2024年计算机视觉顶会创新点
23年最火系列,内涵80+优化改进篇,涨点小能手,助力科研,好评率极高
应用系列篇:
1.yolov10介绍
论文: https://arxiv.org/pdf/2405.14458
代码: github - thu-mig/yolov10: yolov10: real-time end-to-end object detection
摘要:在过去的几年里,由于其在计算成本和检测性能之间的有效平衡,yolos已经成为实时目标检测领域的主导范例。研究人员已经探索了yolos的架构设计、优化目标、数据增强策略等,并取得了显著进展。然而,对用于后处理的非最大抑制(nms)的依赖妨碍了yolos的端到端部署,并且影响了推理延迟。此外,yolos中各部件的设计缺乏全面和彻底的检查,导致明显的计算冗余,限制了模型的性能。这导致次优的效率,以及相当大的性能改进潜力。在这项工作中,我们的目标是从后处理和模型架构两个方面进一步推进yolos的性能-效率边界。为此,我们首先提出了用于yolos无nms训练的持续双重分配,该方法带来了有竞争力的性能和低推理延迟。此外,我们还介绍了yolos的整体效率-精度驱动模型设计策略。我们从效率和精度两个角度对yolos的各个组件进行了全面优化,大大降低了计算开销,增强了性能。我们努力的成果是用于实时端到端对象检测的新一代yolo系列,称为yolov10。广泛的实验表明,yolov10在各种模型规模上实现了最先进的性能和效率。例如,在coco上的类似ap下,我们的yolov10-s比rt-detr-r18快1.8倍,同时具有2.8倍更少的参数和flops。与yolov9-c相比,yolov10-b在性能相同的情况下,延迟减少了46%,参数减少了25%。
yolov10有哪些改进?
1.1 双标签分配
在训练过程中,yolos[20,59,27,64]通常利用tal[14](任务分配学习) 为每个实例分配多个正样本。采用一对多分配,可以产生丰富的监控信号,便于优化,实现更优的性能。然而,它需要yolo
依赖nms后处理,导致部署推理效率不理想。虽然以前的研究[49,60,73,5]探索一对一匹配来抑制冗余预测,但它们通常会引入额外的推理开销或产生次优性能。在这项工作中,我们提出了一种具有双标签分配和一致匹配度量的无nms的yolo训练策略,实现了高效率和竞争性的性能。
1.2 效率驱动的模型设计
yolo中的组件包括初始层、下采样层、带有基本构建块的阶段和头部。初始层的计算成本很低,因此我们对另外三个部分进行效率驱动的模型设计。
(1)轻量级的分类头:在yolos中,分类头和回归头通常共享相同的架构。然而,它们在计算开销上表现出显著的差异。例如,在yolov8-s中,分类头的flops(5.95g)和参数数(1.51m)分别是回归头(2.34g/0.64m)的2.5倍和2.4倍。然而,在分析了分类错误和回归错误的影响后(见表6),我们发现回归头对yolos的性能更为重要。因此,我们可以在不过分损害性能的情况下减少分类头的开销。因此,我们简单地采用了一种轻量级的架构用于分类头,它由两个深度可分离卷积[24, 8]组成,卷积核大小为3×3,后面跟着一个1×1的卷积。
(2)空间-通道解耦下采样:yolos通常利用常规的3×3标准卷积,步长为2,同时实现空间下采样(从h×w到h/2×w/2)和通道变换(从c到2c)。这引入了不可忽视的计算成本o(9hwc^2)和参数数量o(18c^2)。相反,我们提议将空间缩减和通道增加操作解耦,以实现更高效的下采样。具体来说,我们首先利用点对点卷积来调整通道维度,然后利用深度可分离卷积进行空间下采样。这将计算成本降低到o(2hwc^2 + 9hwc),并将参数数量减少到o(2c^2 + 18c)。同时,它最大限度地保留了下采样过程中的信息,从而在减少延迟的同时保持了有竞争力的性能。
(3)基于rank引导的模块设计:yolos通常在所有阶段使用相同的基本构建块,例如yolov8中的瓶颈块。为了彻底检查yolos的这种同质设计,我们利用内在秩来分析每个阶段的冗余。具体来说,我们计算每个阶段中最后一个基本块的最后一个卷积的数值秩,这计算了大于阈值的奇异值的数量。图3.(a)展示了yolov8的结果,表明深层阶段和大型模型更容易表现出更多的冗余。这一观察表明,简单地为所有阶段应用相同的块设计对于最佳的容量-效率权衡是次优的。为了解决这个问题,我们提出了一种基于秩的块设计方案,旨在通过紧凑的架构设计降低被证明是冗余的阶段复杂度。我们首先提出了一个紧凑的倒置块(cib)结构,它采用廉价的深度可分离卷积进行空间混合,以及成本效益高的点对点卷积进行通道混合,如图3.(b)所示。它可以作为高效的基本构建块,例如嵌入在elan结构中(图3.(b))。然后,我们提倡一种基于秩的块分配策略,以实现最佳效率,同时保持有竞争力的容量。具体来说,给定一个模型,我们根据其内在秩按升序对所有阶段进行排序。我们进一步检查用cib替换领先阶段的基本块的性能变化。如果与给定模型相比没有性能下降,我们就继续替换下一个阶段,否则就停止该过程。因此,我们可以在不同阶段和模型规模上实现自适应的紧凑块设计,实现更高的效率而不损害性能。
1.3 基于精度导向的模型设计
(1)大核卷积:使用大核深度可分离卷积是一种有效的方式来扩大感受野并增强模型的能力。然而,简单地在所有阶段利用它们可能会在用于检测小物体的浅层特征中引入污染,同时也会在高分辨率阶段引入显著的i/o开销和延迟。因此,我们提议在深层阶段的cib中利用大核深度可分离卷积。具体来说,我们将cib中第二个3×3深度可分离卷积的核大小增加到7×7,遵循[37]。此外,我们采用结构重参数化技术来引入另一个3×3深度可分离卷积分支,以缓解优化问题而不增加推理开销。此外,随着模型大小的增加,其感受野自然扩大,使用大核卷积的好处减少。因此,我们只对小模型规模采用大核卷积。
(2)部分自注意力(psa):自注意力机制因其卓越的全局建模能力而被广泛应用于各种视觉任务中。然而,它表现出高的计算复杂性和内存占用。为了解决这个问题,考虑到普遍存在的注意力头冗余,我们提出了一种高效的部分自注意力(psa)模块设计,如图3.(c)所示。具体来说,我们在1×1卷积后将特征均匀地分为两部分。我们只将一部分输入到由多头自注意力模块(mhsa)和前馈网络(ffn)组成的npsa块中。然后,两部分通过1×1卷积连接并融合。此外,我们遵循[21]将查询和键的维度分配为值的一半,并用batchnorm替换layernorm以实现快速推理。此外,psa仅放置在具有最低分辨率的第4阶段之后,避免了自注意力二次计算复杂性带来的过度开销。通过这种方式,可以在yolos中以低计算成本融入全局表示学习能力,这很好地增强了模型的能力并提高了性能。
2.yolov10代码讲解
2.1 c2fuib介绍
c2fuib只是用cib结构替换了yolov8中 c2f的bottleneck结构
实现代码ultralytics/nn/modules/block.py
class cib(nn.module):
"""standard bottleneck."""
def __init__(self, c1, c2, shortcut=true, e=0.5, lk=false):
"""initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
expansion.
"""
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = nn.sequential(
conv(c1, c1, 3, g=c1),
conv(c1, 2 * c_, 1),
conv(2 * c_, 2 * c_, 3, g=2 * c_) if not lk else repvggdw(2 * c_),
conv(2 * c_, c2, 1),
conv(c2, c2, 3, g=c2),
)
self.add = shortcut and c1 == c2
def forward(self, x):
"""'forward()' applies the yolo fpn to input data."""
return x + self.cv1(x) if self.add else self.cv1(x)
class c2fcib(c2f):
"""faster implementation of csp bottleneck with 2 convolutions."""
def __init__(self, c1, c2, n=1, shortcut=false, lk=false, g=1, e=0.5):
"""initialize csp bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
expansion.
"""
super().__init__(c1, c2, n, shortcut, g, e)
self.m = nn.modulelist(cib(self.c, self.c, shortcut, e=1.0, lk=lk) for _ in range(n))
2.2 psa介绍
具体来说,我们在1×1卷积后将特征均匀地分为两部分。我们只将一部分输入到由多头自注意力模块(mhsa)和前馈网络(ffn)组成的npsa块中。然后,两部分通过1×1卷积连接并融合。此外,遵循将查询和键的维度分配为值的一半,并用batchnorm替换layernorm以实现快速推理。
实现代码ultralytics/nn/modules/block.py
class attention(nn.module):
def __init__(self, dim, num_heads=8,
attn_ratio=0.5):
super().__init__()
self.num_heads = num_heads
self.head_dim = dim // num_heads
self.key_dim = int(self.head_dim * attn_ratio)
self.scale = self.key_dim ** -0.5
nh_kd = nh_kd = self.key_dim * num_heads
h = dim + nh_kd * 2
self.qkv = conv(dim, h, 1, act=false)
self.proj = conv(dim, dim, 1, act=false)
self.pe = conv(dim, dim, 3, 1, g=dim, act=false)
def forward(self, x):
b, _, h, w = x.shape
n = h * w
qkv = self.qkv(x)
q, k, v = qkv.view(b, self.num_heads, -1, n).split([self.key_dim, self.key_dim, self.head_dim], dim=2)
attn = (
(q.transpose(-2, -1) @ k) * self.scale
)
attn = attn.softmax(dim=-1)
x = (v @ attn.transpose(-2, -1)).view(b, -1, h, w) + self.pe(v.reshape(b, -1, h, w))
x = self.proj(x)
return x
class psa(nn.module):
def __init__(self, c1, c2, e=0.5):
super().__init__()
assert(c1 == c2)
self.c = int(c1 * e)
self.cv1 = conv(c1, 2 * self.c, 1, 1)
self.cv2 = conv(2 * self.c, c1, 1)
self.attn = attention(self.c, attn_ratio=0.5, num_heads=self.c // 64)
self.ffn = nn.sequential(
conv(self.c, self.c*2, 1),
conv(self.c*2, self.c, 1, act=false)
)
def forward(self, x):
a, b = self.cv1(x).split((self.c, self.c), dim=1)
b = b + self.attn(b)
b = b + self.ffn(b)
return self.cv2(torch.cat((a, b), 1))
2.3 scdown
olos通常利用常规的3×3标准卷积,步长为2,同时实现空间下采样(从h×w到h/2×w/2)和通道变换(从c到2c)。这引入了不可忽视的计算成本o(9hwc^2)和参数数量o(18c^2)。相反,我们提议将空间缩减和通道增加操作解耦,以实现更高效的下采样。具体来说,我们首先利用点对点卷积来调整通道维度,然后利用深度可分离卷积进行空间下采样。这将计算成本降低到o(2hwc^2 + 9hwc),并将参数数量减少到o(2c^2 + 18c)。同时,它最大限度地保留了下采样过程中的信息,从而在减少延迟的同时保持了有竞争力的性能。
实现代码ultralytics/nn/modules/block.py
class scdown(nn.module):
def __init__(self, c1, c2, k, s):
super().__init__()
self.cv1 = conv(c1, c2, 1, 1)
self.cv2 = conv(c2, c2, k=k, s=s, g=c2, act=false)
def forward(self, x):
return self.cv2(self.cv1(x))
3.如何训练yolov10
3.1环境配置
源码下载:
github - thu-mig/yolov10: yolov10: real-time end-to-end object detection
环境安装:
conda create -n yolov10 python=3.9
conda activate yolov10
pip install -r requirements.txt
pip install -e .
3.2 neu-det训练自己的yolov10模型
3.2.1 数据集介绍
直接搬运v8的就能使用
3.2.2 超参数修改
位置如下default.yaml
3.2.3 如何训练
import warnings
warnings.filterwarnings('ignore')
from ultralytics import yolov10
if __name__ == '__main__':
model = yolov10('ultralytics/cfg/models/v10/yolov10n.yaml')
model.load('yolov10n.pt') # loading pretrain weights
model.train(data='data/neu-det.yaml',
cache=false,
imgsz=640,
epochs=200,
batch=16,
close_mosaic=10,
device='0',
optimizer='sgd', # using sgd
project='runs/train',
name='exp',
)
发表评论