【yolo系列】yolov10的结构解析、一致性双重分配

前言

论文阅读解析:【论文阅读】【yolo系列】YOLOv10: Real-Time End-to-End Object Detection
YOLOV8的解析:【yolov8系列】yolov8的目标检测、实例分割、关节点估计的原理解析

工程方面,没有阅读yolov10官方的github工程,而是yolov5/8的官方工程 ultralytics。
ultralytics 工程支持yolo主系列的版本的训练,当然也包括yolov10。于是相较于原论文中的设计,部分操作和结构并没有保持完全一致。本篇博客以ultralytics工程的实现细节为主,记录yolov10在实现上的细节。

1 模型结构简介

YOLOV10的结构如下图

工程中的yolov10和yolov8的网络结构的配置文件的对比


YOLOv10 论文中改进
详细内容可参考 YOLOV10论文解析第三章节 Methodology。在工程 ultralytics 中,论文中的内容并没有完全使用。

  1. 无 NMS 训练的一致双重分配、一致性匹配度量标准
  2. 【精度驱动】C2fCIB 中大核心卷积:C2fCIB 替代 C2f。ultralytics 定义了该模块 但实际没有使用
  3. 【精度驱动】部分自注意力(PSA)
  4. 【效率驱动】C2fCIB 中的结构重参数化。ultralytics 定义了该模块 但实际没有使用
  5. 【效率驱动】空间通道解耦式降采样:SCDown 代替了 Conv下采样
  6. 【效率驱动】分类任务头的轻量化:DWConv中 代替了 Conv 前向计算
  7. 【效率驱动】基于秩的模块化设计。 ultralytics 实际没有使用

工程中实际实现内容如下

  1. C2fCIB 模块
  2. PSA(部分自注意力)模块
  3. SCDown 模块
  4. DWconv 模块
  5. 任务头模块 &(无 NMS 训练的一致双重分配、一致性匹配度量标准)

2 C2fCIB 模块

在介绍 C2fCIB 模块前,需要重提下

  • DWConv。在yolov10中多处使用 深度可分离卷积,该卷积较早之前就提出,是较为基础的卷积,这里不展开讲述。
  • C2f。C2f 的介绍在 yolov8 的详解中的3.1.2章节记录
  • C2fCIB。在YOLOV10中使用。该模块在C2f 模块的基础上,使用 CIB 模块替换了 Bottleneck 模块,那只需要对比 CIB 与 Bottleneck 的实现。工程中在【ultralytics/nn/modules/block.py】中实现了 C2fCIB。

2.1 CIB 与 Bottleneck 结构对比


上图左1为 Bottleneck 模块结构;中间的为 CIB 模块结构;右侧为 RepVGGDW,可将 CIB 最中间层替换。

  • Bottlenet

    输出 shape 参数量 计算量 (FLOP)
    Conv3×3, C→C N×C×H×W 3×3×C×C = 9 C² 3×3×C×C×H×W×N = 9 C² H W N
    Conv3×3, C→C N×C×H×W 3×3×C×C = 9 C² 3×3×C×C×H×W×N = 9 C² H W N
    总计 --- 18 C² 18 C² H W N
  • CIB

    输出 shape 参数量 计算量 (FLOP)
    DWConv3×3, C groups N×C×H×W 3×3×1×C = 9 C 3×3×1×C×H×W×N = 9 C H W N
    PWConv1×1, C→2C N×2C×H×W 1×1×C×2C = 2 C² 1×1×C×2C×H×W×N = 2 C² H W N
    DWConv3×3, 2C groups N×2C×H×W 3×3×1×2C = 18 C 3×3×1×2C×H×W×N = 18 C H W N
    PWConv1×1, 2C→C N×C×H×W 1×1×2C×C = 2 C² 1×1×2C×C×H×W×N = 2 C² H W N
    DWConv3×3, C groups N×C×H×W 3×3×1×C = 9 C 3×3×1×C×H×W×N = 9 C H W N
    总计 --- 4 C² + 36 C (4 C² + 36 C) H W N
  • RepVGGDW

    • 将CIB最中间增加一个分支 使用DWConv7*7,和原有的DWConv3*3,就组成了 RepVGGDW。这样的话,参数增加了 98C,计算量增加了 98 CHWN。
    • 该模块为论文中描述的 C2fCIB 中的大核卷积,使用了7*7的深度可分离卷积。在推理时,该模块会进行 结构重参数化
    • 在工程中,没有使用 DWConv7*7 分支。

2.2 CIB 与 Bottleneck 能力对比

两层的 3×3 直筒只给出"最原始"的局部线性+非线性叠加;
五层深度可分离瓶颈在几乎 1/3 的计算成本 下,提供了更深非线性、更大感受野、通道扩缩容量、内置正则四重优势,因而成为轻量高性能模型的首选单元。

  1. 参数 / 计算效率

    指标 A 结构 B 结构 B/A 比值(C=32 为例)
    参数量 18 C² 4 C² + 36 C ≈ 0.30
    计算量 18 C² HWN (4 C² + 36 C) HWN ≈ 0.30

    B 用约 30 % 的参数 & 计算量 就完成了更长的非线性变换链路。

  2. 表征能力

    • 非线性层数 :A 只有 2 层激活,B 有 5 层激活(每层卷积后都接非线性)。
      更深的光滑非线性曲面带来更强的函数逼近能力。
    • 通道扩展:B 在中间把通道升到 2 C,给了 3×3 DW 更丰富的"独立滤波器bank",而 A 全程通道数不变,没有这种"扩张-压缩"的容量缓冲。
    • 感受野:A 固定 5×5;B 更大的感受野,却没用更大 kernel,仅靠深度可分离堆叠就拿到更大视野,利于捕获远距离空间依赖。
  3. 正则与泛化

    • DW 卷积本身每组只处理 1 个通道,天然地把参数量拆成"空间-通道"两段,相当于在通道维度引入分组正则,降低过拟合风险。
    • 1×1 PW 负责跨通道信息融合,可视为低秩投影(bottleneck),进一步起到参数压缩 + 正则作用。
  4. 实际部署友好

    • 计算密度低:DW 卷积的乘法密度(每像素乘加数)远低于普通卷积,对移动端/缓存更友好。
    • 可插入残差:B 结构输入输出通道一致,天然适合做成残差边,训练更深网络时梯度更稳。

3 PSA 模块

全名Partial self-attention (PSA),在脚本【ultralytics/nn/modules/block.py】中定义。

该模块核心的为 位置敏感的多头自注意力子模块 Attention层,然后正常的跟个前馈神经网络,做特征再提取。


3.1 Attention层


理解Attention模块中具体的结构,以及多头、qkv操作,图中为yolov10实际的参数数值,详细分析维度变化过程如下:

  1. 初始化参数计算(num_heads=4)
    假设输入通道数dim=256,注意力头数num_heads=4,注意力比例attn_ratio=0.5
    • 每个 V注意头的维度: head_dim = dim/num = 256 / / 4 = 64 \text{head\_dim = dim/num} = 256//4=64 head_dim = dim/num=256//4=64
    • Q/K的维度: key_dim = int(head_dim*attn_ratio) = i n t ( 64 ∗ 0.5 ) = 32 \text{key\_dim = int(head\_dim*attn\_ratio)}=int(64*0.5) = 32 key_dim = int(head_dim*attn_ratio)=int(64∗0.5)=32
    • 所有头的Q/K总维度: nh_kd = key_dim * num_heads = 32 ∗ 4 = 128 \text{nh\_kd = key\_dim * num\_heads} = 32*4 =128 nh_kd = key_dim * num_heads=32∗4=128
    • qkv卷积的输出通道数: h=dim + nh_kd * 2 = 256 + 128 ∗ 2 = 512 \text{h=dim + nh\_kd * 2} = 256 + 128 * 2 = 512 h=dim + nh_kd * 2=256+128∗2=512
  2. qkv卷积与维度变化
    • 输入x的维度:[B, C, H, W] = [B, 256, H, W]
    • qkv卷积输出:[B, 256, H, W] → [B, 512, H, W]
  3. 分割 q、k、v(关键步骤)
    具体操作为 reshape 和 切片:
    • reshape维度变化:[B, 512, H, W] → [B, 4, 32*2+64, N] = [B, 4, 128, N] (N = H×W)
    • 分割后维度:
      • q : [ B , 4 , 32 , N ] q: [B, 4, 32, N] q:[B,4,32,N] (4个注意力头,每个头的Q为32维)
        k : [ B , 4 , 32 , N ] k: [B, 4, 32, N] k:[B,4,32,N] (4个注意力头,每个头的K为32维)
        v : [ B , 4 , 64 , N ] v: [B, 4, 64, N] v:[B,4,64,N] (4个注意力头,每个头的V为64维)
    • 这里清晰地体现了注意力头数的作用:
      • self.num_heads=4决定了第2维的大小为4
      • 每个注意力头独立拥有自己的Q、K、V空间
      • 所有注意力头并行处理不同的特征子空间
  4. 注意力计算过程
    • Q转置:[B, 4, 32, N] → [B, 4, N, 32]
    • 注意力分数计算:Q^T @ K → [B, 4, N, 32] @ [B, 4, 32, N] = [B, 4, N, N]
    • Softmax归一化:保持维度不变 [B, 4, N, N]
    • 加权求和:V @ attn^T → [B, 4, 64, N] @ [B, 4, N, N] = [B, 4, 64, N]
    • reshape回原始通道数:[B, 4, 64, N] → [B, 256, H, W]
  5. 位置编码与输出
    • 位置编码:对 V 进行3×3深度卷积 [B, 256, H, W] → [B, 256, H, W]
    • 残差连接:注意力输出 + 位置编码
    • 投影层:保持通道数不变 [B, 256, H, W] → [B, 256, H, W]

维度变化总结表】(num_heads=4)

操作 张量 维度变化
输入 x [B, 256, H, W]
qkv卷积 qkv [B, 256, H, W] → [B, 512, H, W]
重塑 qkv_reshaped [B, 512, H, W] → [B, 4, 128, N]
分割Q q [B, 4, 32, N]
分割K k [B, 4, 32, N]
分割V v [B, 4, 64, N]
Q转置 q.transpose [B, 4, 32, N] → [B, 4, N, 32]
注意力分数 q@k [B, 4, N, 32] @ [B, 4, 32, N] → [B, 4, N, N]
加权求和 v@attn [B, 4, 64, N] @ [B, 4, N, N] → [B, 4, 64, N]
重塑 - [B, 4, 64, N] → [B, 256, H, W]
位置编码 pos_encoding [B, 256, H, W] → [B, 256, H, W]
输出 x [B, 256, H, W]

注意力头的核心作用

  1. 特征空间分解 &多角度关注:将256维的特征空间分解为4个64维的子空间,每个头专注于不同的特征模式(不同的注意力模式),增强模型的表达能力
  2. 并行处理:4个注意力头并行计算,提高模型的并行能力
  3. 维度效率 :通过降维注意力(Q/K使用32维而非64维)提高计算效率

    通过这种多注意力头的设计,YOLOv10的Attention模块能够在保持计算效率的同时,有效捕捉不同尺度和角度的特征依赖关系。

3.2 FFN 层

self.ffn 前馈神经网络确实采用了先升维再降维的设计模式,在Transformer、Vision Transformer以及现代卷积神经网络中被广泛应用,是一种兼顾性能与效率的设计选择。

python 复制代码
self.ffn = nn.Sequential(
    Conv(self.c,     self.c*2, 1),            # 升维:c → 2c
    Conv(self.c*2,   self.c,     1, act=False)  # 降维:2c → c
)

结构细节】:

  1. 输入x 的维度 [1,256,20,20]
  2. 升维阶段 conv 1×1:
    • 输出维度 [1,512,20,20]
    • 作用:
      增加特征空间维度,提升模型的表达能力
      引入更多非线性变换(通过Conv模块中的激活函数)
  3. 降维阶段 conv 1*1:
    • 输出维度 [1,256,20,20]
    • 作用:
      保持输出维度与输入一致,便于外部的残差连接
      最后一层没有激活函数(act=False),让后续操作决定输出特性

技术优势】:

  • 高效计算:使用1×1卷积进行维度变换,计算量远小于3×3等大卷积
  • 特征增强 :中间升维过程能够捕捉更丰富的特征交互
  • 残差友好:输入输出维度一致,便于添加残差连接
  • 参数高效:相比直接使用大通道数,这种结构在参数总量增加不多的情况下提升性能

4 SCDown 下采样

  • yolov8中的下采样:conv(3*3, stride=2*2)。
  • yolov10中下采样:conv(1*1)、DWconv(3*3,stride=2*2,act=False)。更少的参数、更少的计算量。yolov10中将下采样拆解,
    1. 先使用 point-wise conv 进行通道信息交错融合
    2. 再使用DWconv 降低尺寸。不加激活,保留线性传递,防止小目标/边缘信息被激活截断。

与其它下采样对比

模块 参数量 计算量 激活次数 感受野 信息保留
conv(3×3/s2) 9 C C′ 9/2 C C′ HWN 1 3×3
SCDown C C′ + 9 C′ (C C′ + 9/4 C′) HWN 1(仅 PW 后) 3×3
MaxPool+Conv C C′ C C′ HWN 1 2×2 低(不可学习)

5 一致性双重分配(Consistent Dual Assignments)

NMS 曾长期稳坐检测后处理头把交椅,却避免不掉额外耗时;诸多替代方案轮番上阵,又常牵出新麻烦。YOLOv10 的一致性双重分配策略,轻巧化解了上述两难。

  1. 无 NMS 的核心:一致性双重分配

    1. 训练时同时放两份检测头
      • One-to-Many Head(OTM):负责学习,一个 gt 匹配多个 anchor,保证监督信号充足。 (与yolov8保持一致思想)
      • One-to-One Head(OTO):负责无冗余输出,一个 gt 只匹配分数最高的 1 个 anchor,模拟推理场景。
    2. 两个头共用同一套特征,用统一匹配度量
      m = s α ⋅ I o U β ( α = β = 0.5 ) m = s^α · IoU^β (α=β=0.5) m=sα⋅IoUβ(α=β=0.5)
      训练损失加权求和,让 OTM 学到的特征对 OTO 同样有效;论文里两头的匹配一致性可达 95% 以上 。
    3. 推理时只启用 OTO 头,天然没有重复框,于是把 NMS 彻底省掉 。
  2. Detect 模块结构
    (输入:3 层特征 P3/8, P4/16, P5/32)

    分支 组成 输出通道 激活 备注
    共享 Stem 2×DWConv3×3 + 1×PWConv1×1 256 SiLU 先统一通道数
    OTM 头 1×PWConv → 2×DWConv3×3 → Reg/Cls 1×1 4A+C A=anchor 数
    OTO 头 同 OTM 结构,独立权重 4A+C 仅训练时更新
    • 两个头各自输出 (reg, cls) 后,分别与 gt 做标签分配,各自算损失;反向传播只更新对应分支权重。
    • 因为 OTO 头在训练阶段就被迫"只挑最高分",所以推理直接拿它输出即可,无需再做 NMS 。
  3. 训练阶段样本分配

    1. OTM 头:沿用 YOLOv8 的 Task-Aligned 策略
      把 head 输出的所有预测框 decode 成原图坐标,然后通过规则选取 top-10 的框 → 正样本;其余负样本。
    2. OTO 头:同一度量,但强制 top-1
      每个 gt 只在所有 anchor 里选 t 最大的那一个作为正样本,其余一律负样本。
    3. 损失函数 单头的loss与yolov8保持一致
      L = L_OTM + λ·L_OTO ,λ 默认 1.0
      L_OTM 负责让网络"看得多、学得好";L_OTO 负责让网络"不打架、无冗余"
  4. 推理阶段使用流程(真正部署时)
     整个过程没有 NMS、没有 Top-K、没有排序,CPU 后处理耗时 < 0.1 ms 。

    1. 输入图片 → Letterbox resize → 640×640
    2. Backbone + Neck → 拿到 3 层特征
    3. 只启用 OTO 头 → 直接输出 1×(4+1+C)×H×W 的 tensor
    4. 置信度阈值 0.25 过滤 → 解码坐标 → 输出最终框
  5. 收益小结

    • 延迟:相比 YOLOv9-C 省掉 NMS,整体推理延迟 ↓ 46% 。
    • 精度:密集场景(人群、车流)召回率 ↑ 8%,不再因 NMS 阈值误删框 。
    • 部署:ONNX/TensorRT 导出时,模型图里连 NMS 节点都没有,端侧落地零额外算子。

一句话:YOLOv10 把"学的时候多给信号,用的时候只留一个最高分"做成双重头,用训练一致性代替后处理 NMS,从而真正端到端。

相关推荐
延凡科技2 小时前
延凡智慧水库系统:数字孪生+AI驱动水库安全与智能调度
人工智能·安全
Christo32 小时前
2024《Three-way clustering: Foundations, survey and challenges》
人工智能·算法·机器学习·数据挖掘
言之。2 小时前
Claude Code IDE 集成工作原理详解
ide·人工智能
肥猪猪爸2 小时前
计算机视觉中的Mask是干啥的
图像处理·人工智能·深度学习·神经网络·目标检测·计算机视觉·视觉检测
yiersansiwu123d2 小时前
工程化破局,2025年AI大模型的价值兑现之路
人工智能
_codemonster2 小时前
自然语言处理容易混淆知识点(六)SentenceTransformer的训练参数
人工智能·自然语言处理
2501_941329722 小时前
基于DETR的血细胞显微图像检测与分类方法研究【原创】_1
人工智能·数据挖掘
人工智能训练2 小时前
Docker Desktop WSL 集成配置宝典:选项拆解 + 精准设置指南
linux·运维·服务器·人工智能·docker·容器·ai编程
golang学习记2 小时前
VS Code使用 GitHub Copilot 高效重构代码:10 大实战技巧 + 自定义指令封装指南
人工智能