YOLOv8 架构深度研究报告
重要说明:Ultralytics 未发布经过同行评审的 YOLOv8 官方论文,所有架构细节依赖源码(ultralytics GitHub)和官方文档。
术语命名对照表
网络结构模块
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| C3 | Cross Stage Partial Bottleneck with 3 Convolutions | 跨阶段部分瓶颈-3卷积 |
| C2f | Cross Stage Partial Bottleneck with 2 Convolutions and finer flow | 跨阶段部分瓶颈-2卷积-细粒度流 |
| CSP | Cross Stage Partial (Network) | 跨阶段部分(网络) |
| ELAN | Efficient Layer Aggregation Network | 高效层聚合网络 |
| E-ELAN | Expanded Efficient Layer Aggregation Network | 扩展高效层聚合网络 |
| SPPF | Spatial Pyramid Pooling - Fast | 空间金字塔池化-快速版 |
| Bottleneck | Bottleneck (Residual Block) | 瓶颈层(残差块) |
| RepConv | Reparameterized Convolution | 重参数化卷积 |
| Backbone | Backbone Network | 主干网络(特征提取) |
| Neck | Neck Network | 颈部网络(特征融合) |
| Head | Detection Head | 检测头(输出预测) |
检测头与标签分配
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| FCOS | Fully Convolutional One-Stage (Detector) | 全卷积单阶段检测器 |
| TAL | TaskAlignedAssigner | 任务对齐标签分配器 |
| OTA | Optimal Transport Assignment | 最优传输标签分配 |
| SimOTA | Simplified Optimal Transport Assignment | 简化最优传输标签分配 |
| Anchor-free | Anchor-free Detection | 无锚框检测(无需预定义候选框) |
| Anchor-based | Anchor-based Detection | 基于锚框检测(使用预定义候选框) |
| Decoupled Head | Decoupled Detection Head | 解耦检测头(分类与回归分支分离) |
损失函数
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| IoU | Intersection over Union | 交并比(预测框与真实框的重叠度量) |
| GIoU | Generalized IoU | 广义交并比(IoU + 包围框惩罚) |
| DIoU | Distance IoU | 距离交并比(IoU + 中心点距离惩罚) |
| CIoU | Complete IoU | 完整交并比(IoU + 中心距离 + 宽高比惩罚) |
| BCE | Binary Cross-Entropy | 二元交叉熵(分类损失) |
| DFL | Distribution Focal Loss | 分布焦点损失(边界框概率分布建模) |
| GFL | Generalized Focal Loss | 广义焦点损失(DFL 的理论基础) |
| QFL | Quality Focal Loss | 质量焦点损失(YOLOv8 未采用) |
| DGQP | Distribution-Guided Quality Predictor | 分布引导质量预测器 |
特征金字塔
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| FPN | Feature Pyramid Network | 特征金字塔网络(自顶向下特征融合) |
| PAN | Path Aggregation Network | 路径聚合网络(自底向上特征融合) |
| PAN-FPN | PAN + FPN (Bi-directional) | 双向特征金字塔(YOLOv8 Neck 结构) |
评估指标
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| AP | Average Precision | 平均精度(单一 IoU 阈值下的精度) |
| mAP | mean Average Precision | 各类别平均精度均值(先求单类 AP,再跨类别取均值) |
| mAP@50-95 | mAP at IoU 0.50 to 0.95 | IoU 从 0.50 到 0.95 的 mAP 平均值 |
| COCO | Common Objects in Context | 上下文中的常见物体(目标检测基准数据集) |
| FLOPs | Floating Point Operations | 浮点运算次数(衡量计算量) |
| FPS | Frames Per Second | 每秒帧数(衡量推理速度) |
模型缩放与部署
| 缩写 | 英文全称 | 中文译名 |
|---|---|---|
| reg_max | Regression Max Bins | 回归最大离散桶数(DFL 的离散化参数) |
| INT8 | 8-bit Integer Quantization | 8 位整数量化 |
| FP16 | 16-bit Floating Point (Half Precision) | 半精度浮点 |
| FP32 | 32-bit Floating Point (Single Precision) | 单精度浮点 |
| TOPS | Tera Operations Per Second | 每秒万亿次运算(NPU 算力单位) |
| NPU | Neural Processing Unit | 神经网络处理单元 |
| RKNN | Rockchip Neural Network | 瑞芯微神经网络格式 |
| ONNX | Open Neural Network Exchange | 开放神经网络交换格式 |
| TensorRT | TensorRT (NVIDIA Inference Optimizer) | NVIDIA 推理优化引擎 |
数据增强
| 术语 | 英文全称 | 中文译名 |
|---|---|---|
| Mosaic | Mosaic Augmentation | 马赛克增强(4 张图拼接为 1 张) |
| MixUp | MixUp Augmentation | 混合增强(2 张图按比例叠加混合) |
| Copy-Paste | Copy-Paste Augmentation | 复制粘贴增强(实例级复制粘贴) |
一、网络整体结构:Backbone + Neck + Head
YOLOv8 是 Ultralytics 于 2023 年发布的目标检测架构,在 YOLOv5 基础上进行了四项核心改进:C2f 模块替代 C3、保留 PAN-FPN 双向 Neck、引入 Anchor-free 解耦检测头、采用 Distribution Focal Loss + CIoU 损失。
1.1 Backbone:C2f 模块 + 5 级特征金字塔
YOLOv8 Backbone 采用 C2f(Cross Stage Partial Bottleneck with 2 Convolutions and finer flow,跨阶段部分瓶颈-2卷积-细粒度流)模块 (替代 YOLOv5 的 C3(Cross Stage Partial Bottleneck with 3 Convolutions,跨阶段部分瓶颈-3卷积) )构成 5 级特征金字塔 P1--P5 ,末端接 SPPF(Spatial Pyramid Pooling - Fast,空间金字塔池化-快速版,k=5, ch=1024)。
P1/2 → P2/4 → P3/8 → P4/16 → P5/32
(stem) C2f C2f C2f C2f + SPPF
C2f vs C3 的核心差异(基于源码分析):
「3」和「2」指的是什么? ------指模块外围主卷积层数量,不是 Bottleneck 内部的卷积数。
C3(Cross Stage Partial Bottleneck with 3 Convolutions,跨阶段部分瓶颈-3卷积):
python
# YOLOv5 源码
class C3(nn.Module):
cv1 = Conv(c1, c_, 1, 1) # ① 主分支降维
cv2 = Conv(c1, c_, 1, 1) # ② 跳跃分支降维
cv3 = Conv(2*c_, c2, 1) # ③ 拼接后融合
Input
│
┌─────────┴─────────┐
│ │
cv1 cv2 ← 两个分支各自的 1×1 降维
│ │
Bottleneck × n │ ← 主分支:B1→B2→...→Bn 链式串联
│ │
└──────Concat───────┘ ← 只拼接最后一个 Bottleneck 的输出
│
cv3 ← 拼接后 1×1 融合
│
Output
- 外围 3 个主卷积(cv1, cv2, cv3)→ 故名 C3
- CSP 分流:输入分成两路,主分支经过 Bottleneck 链,跳跃分支直通
- 只有最后一个 Bottleneck 的输出参与拼接
- 梯度必须逐层回传:Loss → cv3 → Concat → Bn → ... → B2 → B1 → cv1
C2f(Cross Stage Partial Bottleneck with 2 Convolutions and finer flow,跨阶段部分瓶颈-2卷积-细粒度流):
python
# YOLOv8 源码
class C2f(nn.Module):
cv1 = Conv(c1, 2*c_, 1, 1) # ① 入口卷积
cv2 = Conv((2+n)*c_, c2, 1) # ② 出口卷积(处理拼接后的多通道)
Input
│
cv1
│
┌─────────┴─────────┐
│ │
y0 (skip) B1
│ │
│ B2
│ │
│ B3
│ │
▼ ▼ ▼ ▼
┌────────────────────────┐
│ Concat(y0, B1, B2, B3) │
└────────────────────────┘
│
cv2
│
Output
注意:每个 Bottleneck 的输出(B1、B2、B3)都独立参与 Concat,而不仅仅是最后一个 B3。这是 C2f 与 C3 的核心区别。
- 外围仅 2 个主卷积(cv1, cv2)→ 故名 C2
- 后缀 f = finer flow(更细粒度的梯度流)
- 每个 Bottleneck 的输出都直接参与最终拼接(类似 DenseNet 的密集连接 + CSP 分流)
- 梯度路径更短:Loss → Concat → B1/B2/B3/skip 各自独立回传
核心差异不是卷积数量,而是特征拼接策略:
| 对比维度 | C3 | C2f |
|---|---|---|
| 外围卷积数 | 3(cv1, cv2, cv3) | 2(cv1, cv2) |
| Bottleneck 输出拼接 | 仅最后一个 | 所有 Bottleneck 输出 |
| 梯度回传路径 | 链式逐层(B3→B2→B1) | 并联直达(各层独立) |
| Concat 通道数 | 2 × c_ |
(2 + n) × c_(n = Bottleneck 数) |
| 参数量 | --- | 与 C3 同量级(取决于 n、e、c1、c2 具体配置) |
| 真正收益 | --- | 梯度流优化、特征复用增强、小目标特征保留更好 |
注意 :C2f 的优势不在于减少参数量(实际参数量与 C3 同量级,有时略低、有时持平、有时甚至略大),而在于梯度流优化和特征复用。
核心差异对比图:
YOLOv5 C3 YOLOv8 C2f
Input Input
│ │
┌─┴─┐ cv1
│ │ │
cv1 cv2 split → [y0, y1]
│ │ │
B │ ├─ y0 (skip)
│ │ ├─ y1
B │ │
│ │ B1
B │ │
│ │ B2
│ │ │
Concat│ B3
│ │ │
cv3 Concat(y0, y1, B1, B2, B3)
│
cv2
│
Output
本质区别:只拼接最后一个 Bottleneck → 拼接所有 Bottleneck 输出
本项目场景启示 :对于跑冒滴漏、积水、烟火、鼠类等小目标和弱纹理目标,C2f 的多层特征保留能力更强------浅层细节不会在链式传递中丢失,这比单纯提升 FPS 更有价值。
Bottleneck 模块详解
C3 和 C2f 内部反复出现的 Bottleneck(瓶颈模块) 是 CNN 中最经典的基础积木之一,本质上是一个带残差连接的轻量特征提取单元。
为什么叫"瓶颈"? ------源自 ResNet,通道数经历 宽 → 窄 → 宽 的变化,形似瓶颈:
256 通道(宽)
↓ 1×1 Conv 压缩
64 通道(窄)← 在此做 3×3 卷积,计算量大幅减少
↓ 1×1 Conv 恢复
256 通道(宽)
目的:先用 1×1 卷积降通道减少计算量,在窄通道上做 3×3 特征提取,最后恢复通道数。
YOLOv5/YOLOv8 中的 Bottleneck 实现:
python
# 源码逻辑
cv1 = Conv(c1, c_, 1) # 1×1 降维
cv2 = Conv(c_, c2, 3) # 3×3 特征提取
return x + cv2(cv1(x)) # 残差连接
┌────────────┐
Input ─────►│ 1×1 Conv │
└─────┬──────┘
│
┌─────▼──────┐
│ 3×3 Conv │
└─────┬──────┘
│
▼
Feature
┌───────────┐
Input ───────────────────►│ Add (+) ├──► Output
└───────────┘
残差连接(Residual)的作用 :Output = F(x) + x,梯度可通过跳跃连接直接回传,缓解深层网络的梯度消失问题。
层级关系(从小到大):
Backbone(主干网络)
└─ C2f / C3(特征组织模块)
└─ Bottleneck × n(特征提取单元,重复 n 次)
├─ 1×1 Conv(降维)
├─ 3×3 Conv(特征提取)
└─ Residual Add(残差连接)
类比:Backbone 是一栋楼,C2f 是一个房间,Bottleneck 是房间里的工位,Conv 是具体干活的员工。真正提取特征的核心单元是 Bottleneck,C2f 的作用是把多个 Bottleneck 组织起来,让梯度和特征流动得更高效。
与 YOLOv7 的对比:YOLOv8 未采用 E-ELAN/RepConv 等重参数化技巧,结构更接近 YOLOv5 的简洁路线。
1.2 Neck:PAN-FPN 双向融合
为什么需要 Neck? Backbone 已经提取了特征,但存在一个根本矛盾:
深层特征(P5):知道"是什么",但不知道"在哪里"(语义强,定位弱)
浅层特征(P3):知道"在哪里",但不知道"是什么"(定位强,语义弱)
Neck 的作用就是把不同尺度的信息融合起来。
P3/P4/P5 到底是什么?(特征图详解)
P3/P4/P5 不是图片尺寸 ,而是特征图(Feature Map)的尺寸。
P 是什么的缩写? ------来自 FPN(Feature Pyramid Network)论文的命名惯例,P = Pyramid Level(金字塔层级):
| 命名 | 含义 | 来源 |
|---|---|---|
| C (C2, C3, C4, C5) | Conv Stage(骨干网络的卷积阶段输出) | Backbone 原始特征层 |
| P (P2, P3, P4, P5) | Pyramid Level(金字塔特征层) | 经 FPN 融合后的特征层 |
YOLO 系列沿用了这个习惯,配置文件中
Detect: [P3, P4, P5]意思就是"在小/中/大三个金字塔层上做检测",不用纠结它是某个具体单词的首字母。
下采样过程:Backbone 中每经过一个 stride=2 的卷积,特征图尺寸缩小一半:
输入图片 640×640
↓ stride=2(÷2)
320×320
↓ stride=2(÷2)
160×160
↓ stride=2(÷2)
80×80 ← P3(累计缩小 8 倍 → 记为 P3/8)
↓ stride=2(÷2)
40×40 ← P4(累计缩小 16 倍 → 记为 P4/16)
↓ stride=2(÷2)
20×20 ← P5(累计缩小 32 倍 → 记为 P5/32)
特征图不是图片 :P3 的完整形态是 80×80×256------80×80 是空间位置,256 是特征通道数。这些通道不是 RGB 颜色,而是网络学到的抽象特征(边缘、纹理、形状、语义等),即:
80×80 个小格子,每个格子记录 256 种特征
为什么不同层适合不同大小的目标?
以一个 20×20 像素的老鼠为例:
| 特征层 | 映射后大小 | 结果 |
|---|---|---|
| P3/8 | 20÷8 ≈ 2.5 格 | 占 2~3 格,还能看见 |
| P5/32 | 20÷32 ≈ 0.6 格 | 不到 1 格,几乎消失 |
以一个 200×400 像素的人为例:
| 特征层 | 映射后大小 | 结果 |
|---|---|---|
| P3/8 | 25×50 格 | 太大,很多格子描述同一个人,计算浪费 |
| P5/32 | 6×12 格 | 刚好合适 |
因此:
P3/8 → 小目标检测层(分辨率高,看得细、看得近)
P4/16 → 中目标检测层(中等分辨率)
P5/32 → 大目标检测层(感受野大,看得远、看得全)
Detect(P3, P4, P5)即"小/中/大目标检测层",对应同一张输入图缩小 8/16/32 倍后的特征图。
Backbone 输出了什么?
| 层级 | 分辨率 | 下采样 | 特点 | 本项目场景 |
|---|---|---|---|---|
| P3 | 80×80 | ÷8 | 分辨率高,看得细、看得近 | 漏水、水滴、烟火、鼠类(最重要) |
| P4 | 40×40 | ÷16 | 中等 | 猫、狗、积水 |
| P5 | 20×20 | ÷32 | 感受野大,看得远、看得全 | 人员入侵 |
Neck 中的三个核心操作
理解 Neck 之前,先搞懂它反复使用的三个操作:
① Upsample(上采样)------ 放大特征图,统一尺寸
P5 是 20×20,P4 是 40×40,尺寸不同无法直接融合。Upsample 把 P5 放大到 40×40,才能与 P4 拼接:
20×20 特征图 Upsample 2×后 40×40 特征图
┌────┐ ┌────────────────┐
│1 2 │ │1 1 2 2│
│3 4 │ 最近邻插值 │1 1 2 2│
└────┘ ──────────► │3 3 4 4│
│3 3 4 4│
└────────────────┘
- YOLOv8 默认使用最近邻插值(Nearest Neighbor),速度最快
- 作用类比:把一张小照片放大,和另一张同样大小的照片放在一起比较
- 本质:每个格子复制成 2×2 个格子,通道数不变(20×20×512 → 40×40×512)
② Concat(拼接)------ 把特征堆在一起,通道数相加
Concat 不是加法,而是沿通道维度堆叠:
P4 原始特征: 40×40×256 (256 种特征:边缘、纹理、轮廓...)
P5 上采样后: 40×40×512 (512 种特征:类别语义...)
──── Concat ────
拼接结果: 40×40×768 (768 种特征全部保留)
- 空间尺寸不变(仍是 40×40),只增加通道数
- 类比:两个部门开会,把各自的资料都堆到桌上------还没讨论,只是放一起
③ C2f(融合处理)------ 真正"炒菜",完成特征融合
Concat 只是把特征堆在一起(768 通道里有大量冗余),C2f 才负责真正的融合:
输入:40×40×768(P4 定位特征 + P5 语义特征的简单堆叠)
│
C2f
┌──────────────┐
│ cv1 → split │
│ ├─ skip ─────────────────────┐
│ ├─ B1(融合筛选)──────────┤
│ ├─ B2(增强优化)─────────┤
│ └─ B3(进一步提炼)───────┤
│ Concat → cv2 │
└──────────────┘
│
输出:40×40×c2(融合后的精炼特征:既有定位,又有语义)
- C2f 内部的多个 Bottleneck 对拼接后的特征进行融合、筛选、增强
- 类比:Concat 是把菜倒进锅里,C2f 才是真正炒菜
- 最终输出通道数由
c2参数控制,通常会压缩回合理范围
三步串联总结:
P5(20×20×512)
│
Upsample ← 第①步:放大,统一尺寸
│
40×40×512
│
Concat(P4) ← 第②步:拼接,堆叠特征
│
40×40×768
│
C2f ← 第③步:融合,提炼精华
│
40×40×c2 ← 融合后的精炼特征
总结:Upsample 将高层特征送到低层,Concat 将特征堆叠,C2f 完成特征融合。
第一步:FPN(Feature Pyramid Network)------ 语义向下传播
P5 语义丰富但分辨率低(20×20),定位不准;P3 分辨率高但语义不足。FPN 把 P5 的高级语义自顶向下传递给浅层:
P5(20×20,强语义)
│
Upsample(上采样放大)
│
▼
P4 ── Concat(拼接)
│
C2f(融合处理)
│
Upsample
│
▼
P3 ── Concat(拼接)
│
C2f(融合处理)
│
输出 N3(80×80,兼具语义 + 定位)
效果 :P3 不再只是边缘和纹理,而是变成了带有类别语义的小目标特征。
第二步:PAN(Path Aggregation Network)------ 位置向上传播
FPN 自上而下传递语义时,位置信息被稀释 了。PAN 反方向再融合一次,把浅层的精确定位信息自底向上送回高层:
P3(80×80,强定位)
│
Conv s=2(步长2下采样,缩小分辨率)
│
▼
P4 ── Concat(拼接)
│
C2f(融合处理)
│
Conv s=2(下采样)
│
▼
P5 ── Concat(拼接)
│
C2f(融合处理)
│
输出 N5(20×20,兼具语义 + 定位)
纠正一个常见误解:很多文章写"PAN 传递位置信息、FPN 传递语义信息",容易让人误以为 P3 里只有位置、P5 里只有语义。更准确的理解是:
层级 更擅长什么 不是什么 P3 保留更多空间细节(定位占优势) ❌ 不是"只有位置" P5 保留更多抽象语义(分类占优势) ❌ 不是"只有语义"
"位置信息"到底是什么?
不是目标的坐标值(x=102, y=217),而是有助于边界框回归的边缘、轮廓、纹理、形状等细节特征:
以 640×640 图片中一只老鼠为例:
P3(80×80):老鼠坐标映射到格子(13,27)
→ 耳朵、尾巴、轮廓等细节还在 ← 定位能力强
P5(20×20):同一只老鼠只剩不到1个格子
→ 耳朵没了、尾巴没了、边缘模糊了
→ 只剩"这是个动物"这种抽象信息 ← 语义能力强
FPN 向下传播的是什么?
把 P5 的高级认知("这是猫""这是人""这是漏水")送给 P4 和 P3
原来的 P3:看见轮廓,但不知道是猫还是狗
融合 P5 后:既知道轮廓,又知道类别
PAN 向上传播的是什么?
经过 FPN 后,P3/P4/P5 都有语义了,但高层仍然缺少精细边界。PAN 把 P3 的高分辨率特征重新送回去:
送的不是坐标值(x=100, y=200)
而是:边缘、轮廓、纹理、形状 ← 有助于边界框回归的信息
总结:FPN 将高层语义特征("是什么")传递给低层;PAN 将低层空间细节特征("边界在哪里")传递给高层。
本项目场景:漏水、水滴、火苗、鼠类这些目标边界都比较模糊,小目标又多,PAN 的价值往往比很多人想象的更大。没有 PAN,仅靠 FPN,检测框通常会更粗、更飘,尤其是漏水和火苗这类目标。
双向融合总览
PAN 阶段的输入不是 Backbone 的原始 P3/P4/P5,而是 FPN 的输出。两阶段是串联关系:
命名说明 :N3/N4/N5 和 N3'/N4'/N5' 不是 YOLOv8 官方命名,官方源码始终使用 P3/P4/P5。N 是论文和博客中为区分 Neck 不同阶段特征而添加的非正式标签(N = Neck Feature)。实际工程中,由于空间尺寸始终为 80×80/40×40/20×20,很多资料统称 P3/P4/P5,只是内部特征已被 FPN 和 PAN 重新融合。
┌─── FPN(自顶向下)───┐ ┌─── PAN(自底向上)───┐
│ 增强低层语义表达能力 │ │ 增强高层空间细节能力 │
│ │ │ │
│ P5 ──────────┐ │ │ │
│ ↓ Upsample │ │ │ N3 ──────────┐ │
│ P4 ← Concat │ │ │ ↓ Conv s=2 │ │
│ ↓ C2f │ │ │ N4 ← Concat │ │
│ ↓ Upsample │ │ │ ↓ C2f │ │
│ P3 ← Concat │ │ │ ↓ Conv s=2 │ │
│ ↓ C2f │ │ │ N5 ← Concat │ │
│ ↓ │ │ │ ↓ C2f │ │
│ 输出 N3 │ ───► │ │ ↓ │ │
└───────────────┘ │ │ 输出 N5' │ │
│ └───────────────┘
完整数据流:
Backbone 输出 FPN 阶段 PAN 阶段 最终输出
───────────── ──────────────── ──────────────── ────────────────
P5 (20×20) ──┐ N3 (80×80) ──┐
│ │
P4 (40×40) ──┼── FPN ──► N3 (80×80) ──┐ ├── PAN ──► N3' (80×80)
│ N4 (40×40) ──┼──┐ │ N4' (40×40)
P3 (80×80) ──┘ N5 (20×20) ──┘ └──┐ │ N5' (20×20)
└────┘
FPN / PAN 实际作用:
| 阶段 | 层级 | 操作 | 实际作用 |
|---|---|---|---|
| FPN(Top-Down) | P5→P4→P3 | Upsample → Concat → C2f | 增强低层特征的语义表达能力(将高层强语义注入低层高分辨率特征,提升小目标识别) |
| PAN(Bottom-Up) | N3→N4→N5 | Conv-s2 → Concat → C2f | 增强高层特征的空间细节与定位能力(将低层边缘轮廓信息传回高层,提升目标定位与边界回归) |
注意 :严格来说 P5 也有位置信息、P3 也有语义,只是占比不同。FPN 向下传播的准确术语是 Semantic Feature (语义特征),PAN 向上传播的是 Localization Feature(空间细节特征:边缘、轮廓、纹理),均非坐标值。
Detect 输出三尺度
最终 Neck 输出三个尺度的特征图,送给 Detect Head:
| 输出层 | 分辨率 | 更擅长检测 | 本项目场景 |
|---|---|---|---|
| P3/8 | 80×80 | 小目标 | 漏水、水滴、烟火、鼠类 |
| P4/16 | 40×40 | 中目标 | 积水、猫、狗 |
| P5/32 | 20×20 | 大目标 | 人员入侵 |
注意:表中"更擅长检测"是经验规律而非硬规则。训练时 TaskAlignedAssigner(TAL)会动态决定每个目标由哪个尺度层负责。一个中等大小目标(如 120×120)可能同时在 P3 和 P4 产生候选框,最终由 TAL 分配最优匹配。
本项目场景的尺度分布:
| 目标 | 主要检测尺度 |
|---|---|
| 水滴 | P3 |
| 小面积漏水 | P3 |
| 火苗 | P3 |
| 鼠类 | P3 |
| 猫、狗 | P3/P4 |
| 积水 | P4 |
| 人员入侵 | P4/P5 |
对于跑冒滴漏等小目标检测任务,检测效果主要取决于输入分辨率、Backbone 特征提取能力以及 Neck 的 PAN-FPN 多尺度特征融合能力。Detect Head 负责最终分类与边界框回归,但小目标特征能否在网络中被有效保留,关键在于 Backbone 与 Neck 的设计。
二、Anchor-free 解耦检测头
2.1 解耦设计(Decoupled Head)
YOLOv8 采用 Anchor-free 解耦检测头,共享输入特征、独立预测分支:
┌─ cv2(回归分支)→ 4×reg_max 个回归分布通道
特征图 ──→ Detect ┤
└─ cv3(分类分支)→ nc 个类别通道
- cv2 (
nn.ModuleList):输出4×reg_max个回归分布通道(reg_max=16),表示 left/top/right/bottom 四个方向的概率分布,经 DFL 解码后得到边界框坐标 - cv3 (
nn.ModuleList):输出nc个类别通道,得到各类别概率 - 两者共享输入特征图 ,但使用独立的卷积层进行预测优化
回归分支完整流程:
cv2
↓
4×reg_max 回归分布(64个通道,表示 LTRB 概率分布)
↓
DFL 解码(Distribution Focal Loss)
↓
LTRB 距离值
↓
decode(结合网格中心点)
↓
xywh 边界框坐标
DFL 与 reg_max 深度解析(YOLOv8 检测头的核心创新)
理解 reg_max、DFL、Anchor-free 三者的关系,是掌握 YOLOv8 检测头的关键。
1. YOLOv5 的回归方式:直接预测连续值
假设中心点 (x,y),目标框的四条边距离为:
Top
↑
│ 7.3
│
3.2 ← ● → 5.8
│
│ 4.7
↓
Bottom
YOLOv5 直接预测这 4 个浮点数:
Feature → Conv → [3.2, 7.3, 5.8, 4.7]
问题:对于真实值 7.3,网络需要直接学习这个连续值,训练比较困难。
2. YOLOv8 的创新:概率分布回归
YOLOv8 不再直接预测 7.3,而是预测7 附近的概率、8 附近的概率。
例如,真实距离 Left = 7.3,网络预测:
| 距离桶 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10~15 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 概率 | 0.00 | 0.00 | 0.00 | 0.01 | 0.03 | 0.08 | 0.25 | 0.45 | 0.15 | 0.03 | ≈0 |
网络表达的是:"我觉得 7 最可能,8 也可能,6 有一点可能"。这种方式更容易学习。
3. reg_max 到底是什么?
源码中 reg_max = 16 表示距离范围 0~15 共 16 个桶(bin):
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
每个桶代表一个距离区间。例如 Left = 7.3 对应 7、8 两个桶,所以 reg_max=16 表示每个方向用 16 个概率表示。
3.1 reg_max=16 怎么表示 100 像素距离?
DFL 的 16 个桶预测的是特征图上的距离(网格单位),而不是原图上的像素距离。最后通过 stride 映射回原图坐标。
Anchor-Free 预测的是什么?
YOLOv8 不再预测 (x, y, w, h),而是选一个网格中心点,预测四条边界离这个点有多远:
Top=50
↑
│
Left=100 ● Right=100 ● = 网格中心点 (200, 300)
│
↓
Bottom=50
目标框:左上角 (100, 250),右下角 (300, 350)
Left = 200 - 100 = 100 像素
Top = 300 - 250 = 50 像素
Right = 300 - 200 = 100 像素
Bottom = 350 - 300 = 50 像素
stride(步长)的作用
YOLOv8 的检测是在特征图上完成的。以 P3 层为例:
原图:640×640×3(RGB 像素)
P3: 80×80×256(特征向量)
stride = 640 ÷ 80 = 8
特征图格子不是像素:原图每个位置存储 (R, G, B) 颜色值,而特征图每个格子存储 256 维特征向量(边缘强度、纹理、语义等抽象信息)。由于 CNN 的感受野,1 个 P3 格子对应原图 8×8 区域的信息,所以 stride=8 表示特征图 1 格对应原图 8 像素。
为什么是 256 维特征向量?
256 维不是数学上必须的,而是网络设计者故意给每个位置准备了 256 个"观察角度"。
从原图到特征图的维度变化过程:
原图 (640×640×3)
↓ 第一层 Conv:64 个卷积核,每个学习一种模式
640×640×64
↓ 继续下采样 + 卷积
80×80×256 ← P3
每层卷积核学习不同的特征模式:
通道 1:水平边缘
通道 2:垂直边缘
通道 3:斜线
通道 4:圆形
通道 5:纹理
...
通道 256:某种抽象语义
所以 P3 上位置 (20, 35) 的 256 维向量可能是:
[边缘强度, 纹理强度, 圆形程度, 耳朵特征, 尾巴特征, 猫脸特征, 动物特征, ...]
共 256 个数字
为什么需要这么多维度? 一个位置可能同时包含很多信息(这里有边缘、有毛发纹理、有耳朵、有眼睛、像猫、不像狗......),一个数字无法表达,需要 256 个维度共同描述。
通道数的选择是工程权衡:太少(如 8)信息不够,太多(如 10000)显存和计算爆炸。YOLOv8 的经验值:
P3: 80×80×256
P4: 40×40×512
P5: 20×20×1024
这和大语言模型中的 embedding 类似------词 "cat" 不会表示成单个数字 1,而是几百维向量 [0.12, -0.35, 0.88, ...],因为一个数字无法表达丰富语义。
Detect Head 的工作方式:
256 维特征向量
↓
分类头(cv3)→ 这是猫
↓
回归头(cv2)→ 框的位置
检测头就在这个 256 维向量上工作,根据丰富的特征信息判断:这里是不是目标?是什么目标?边界在哪里?
Detect Head 接收的输入已经是特征图(80×80×256),它天然只能在特征图坐标系里预测距离,最后再乘以 stride 映射回原图坐标系。这样设计比直接预测原图像素坐标更容易训练。
原图上 100 像素的距离,映射到 P3 特征图:
100 ÷ 8 = 12.5 格
此时 DFL 不需要预测 100,它预测 12.5 就够了:
桶 12 → 0.5
桶 13 → 0.5
DFL 解码:12 × 0.5 + 13 × 0.5 = 12.5(特征图网格单位)
映射回原图:12.5 × 8 = 100 像素
各层单侧边界距离的有效表达范围
| 特征层 | stride | DFL 最大距离(15 格) | 单侧边界有效范围 |
|---|---|---|---|
| P3 | 8 | 15 | 15 × 8 = 120 像素 |
| P4 | 16 | 15 | 15 × 16 = 240 像素 |
| P5 | 32 | 15 | 15 × 32 = 480 像素 |
注意 :这些数值表示该层上单侧边界距离(L/T/R/B 之一)的有效表达范围,而非目标框的最大覆盖范围。实际上:
- 目标框尺寸不受此限制:目标的 width/height 由两侧边界共同决定,且一个 GT 不会固定只在某个尺度层负责
- TAL 动态分配:TaskAlignedAssigner 会根据目标大小将其分配到合适的尺度层(大目标分配到更高 stride 的层)
- 多尺度协同:同一个目标可能在多个尺度层产生候选框,最终由 TAL 选择最优匹配
因此,P3 层并非只能检测 ≤120px 的目标,而是其单侧边界预测在该范围内表达最精确。
3.2 为什么选择 16 而不是更多?
16 个桶并不是理论上必须的。YOLOv8 选择 16,是在精度、计算量、显存占用、训练稳定性之间做的工程权衡。
桶数增加的影响:
reg_max=16 → 4×16 = 64 通道
reg_max=30 → 4×30 = 120 通道(翻倍)
但对于局部精度,16 个桶和 30 个桶结果一样------真实值 7.3 时都是 7→0.7, 8→0.3。增加桶数提升的是距离范围,不是局部精度。
GFL 论文实验结果:
reg_max = 4 → 精度不足
reg_max = 8 → 还行
reg_max = 16 → 最佳
reg_max = 32 → 收益很小
reg_max = 64 → 基本不涨
8→16 精度提升明显,16→24 提升极小,24→32 几乎没有提升,但参数量、显存、推理时间持续增加。
16 不是数学上最优,而是工程上最划算的点(sweet spot)。 就像 Transformer 的 attention head 经常取 8 或 16,不是因为别的不行,而是实验发现再大收益已经很小了。
4. 为什么是 4×reg_max = 64 通道?
框有四条边(Left/Top/Right/Bottom),每条边需要 16 个桶:
Top
↑
│
Left ← ● → Right ● = 网格中心点
│
↓
Bottom
Left: [p₀, p₁, ..., p₁₅] → 16 个概率,表示左边界距离 0~15 的可能性
Top: [p₀, p₁, ..., p₁₅] → 16 个概率
Right: [p₀, p₁, ..., p₁₅] → 16 个概率
Bottom: [p₀, p₁, ..., p₁₅] → 16 个概率
──────────────────────────────────────────
总计: 4 × 16 = 64 个通道
检测头输出 64 channels 的来源就在这里。
5. DFL(Distribution Focal Loss)是什么?
全称 Distribution Focal Loss,核心思想:预测概率分布,而不是预测数值。
GT 标签构造方式(源自 GFL 论文):
left = floor(y) = 7
right = ceil(y) = 8
w_left = right - y = 8 - 7.3 = 0.7
w_right = y - left = 7.3 - 7 = 0.3
即 GT 标签分布为:
7 → 0.7
8 → 0.3
解码后:7 × 0.7 + 8 × 0.3 = 7.3 ✓
注意 :GT 标签是上述精确分布,但网络预测的输出分布(Prediction)通常不会完全等于 GT 分布,例如预测可能是 7→0.6, 8→0.35, ...。DFL 训练目标是通过交叉熵让预测分布逼近 GT 分布,而非让输出严格等于 0.7/0.3。
6. DFL 解码过程:计算期望值
假设预测结果:
| 桶 | 6 | 7 | 8 | 9 |
|---|---|---|---|---|
| 概率 | 0.10 | 0.60 | 0.25 | 0.05 |
DFL 解码计算期望值:
d = ∑ i = 0 15 p i × i d = \sum_{i=0}^{15} p_i \times i d=i=0∑15pi×i
代入:
6 × 0.10 + 7 × 0.60 + 8 × 0.25 + 9 × 0.05 = 0.6 + 4.2 + 2.0 + 0.45 = 7.25 6 \times 0.10 + 7 \times 0.60 + 8 \times 0.25 + 9 \times 0.05 = 0.6 + 4.2 + 2.0 + 0.45 = 7.25 6×0.10+7×0.60+8×0.25+9×0.05=0.6+4.2+2.0+0.45=7.25
这就是最终距离。
7. 完整推理流程示例
假设 P3 层(80×80)的某个格子 (20, 35):
回归头输出 64 通道
↓
拆分为 L/T/R/B 各 16 通道
↓
DFL 解码得到:L=7.3, T=5.1, R=9.4, B=6.7
↓
结合网格中心点 (20, 35) 解码
↓
计算边界框坐标:
x₁ = 20 - 7.3 = 12.7
y₁ = 35 - 5.1 = 29.9
x₂ = 20 + 9.4 = 29.4
y₂ = 35 + 6.7 = 41.7
↓
最终 Bounding Box: (12.7, 29.9, 29.4, 41.7)
8. YOLOv5 vs YOLOv8 对比
YOLOv5: YOLOv8:
Feature Feature
↓ ↓
Conv Conv
↓ ↓
x, y, w, h (直接回归坐标) L: [p₀...p₁₅] 16个概率
优点:简单、速度快 T: [p₀...p₁₅] 16个概率
缺点:定位精度有限 R: [p₀...p₁₅] 16个概率
B: [p₀...p₁₅] 16个概率
共 64 通道
↓
DFL Decoder(计算期望值)
↓
x, y, w, h (坐标)
优点:更容易训练、更稳定、
定位更准、高 IoU 表现更好
9. 为什么 YOLOv8 要这样改?
概率分布回归的优势:
- 收敛更稳定
- 定位更准确
- 高 IoU 场景下精度提升更明显
- mAP@50-95 提升明显(虽然 mAP@50 提升不一定特别大)
对本项目的意义:
对于漏水、水滴、烟火、鼠类这类目标,特点是目标小、边界模糊。传统回归方式框容易飘,而 DFL 让边界定位更稳定。因此 YOLOv8 在 mAP@50-95(衡量严格定位精度的指标)上提升明显,原因之一就是 Anchor-free + DFL 让边界框回归精度提高了。
2.2 Anchor-free 检测机制
YOLOv8 采用 Anchor-free(无锚框)检测方式,不再依赖预定义的 Anchor Box 宽高,而是以特征图上的网格中心点(Grid Point)作为空间参考进行目标定位。
Anchor-based(YOLOv5)
YOLOv5 使用预定义 Anchor:
yaml
anchors:
- [10,13, 16,30, 33,23]
- [30,61, 62,45, 59,119]
- [116,90, 156,198, 373,326]
训练时需要:
- 为每个 GT(Ground Truth)寻找最匹配的 Anchor
- 预测相对于 Anchor 的偏移量
即:
预测:Δx, Δy, Δw, Δh
最终框:Anchor + Offset
因此预测结果与 Anchor 尺寸强相关。
Anchor-free(YOLOv8)
YOLOv8 不再定义 Anchor 宽高。配置文件中 Detect 层仅保留:
yaml
Detect:
- nc
不再存在 anchors: ...。网络直接以特征图网格中心点作为参考点:
P3 (80×80)
□ □ □ □
□ □ ● □ ● = 网格中心点
□ □ □ □
检测头直接预测 Left/Top/Right/Bottom 四个方向到目标边界的距离,再通过 DFL 解码得到最终边界框。
make_anchors 的真实含义
源码中虽然存在 make_anchors(),但这里生成的并不是传统意义上的 Anchor Box。其作用仅仅是生成 (x_center, y_center) 形式的网格中心点坐标,例如 (0.5, 0.5), (1.5, 0.5), (2.5, 0.5), ...。
YOLOv8 中的
make_anchors本质上是在生成 Reference Points(参考点),而不是生成 Anchor Box。这一实现方式与 FCOS 系列检测器较为接近。
Anchor-free 的优势
相比 Anchor-based:
- 不需要人工设计 Anchor 尺寸
- 不需要 Anchor 聚类(K-Means)
- 减少超参数
- 对不同尺寸目标泛化更好
- 训练流程更简单
尤其对于尺寸变化较大的场景(漏水、火苗、鼠类、人员),无需针对目标尺寸重新设计 Anchor。
2.3 解耦检测头与 TaskAlignedAssigner
YOLOv8 使用 Decoupled Head(解耦检测头)。输入特征共享,随后分类与回归分支分别进行优化:
Feature
│
┌──┴──┐
│ │
Cls Reg
│ │
分类 回归
分类分支(Classification Branch)
预测"这是猫?这是狗?这是漏水?",输出 Class Score。
回归分支(Regression Branch)
预测 Left/Top/Right/Bottom 对应的 DFL 分布(4×reg_max),输出 Bounding Box。
为什么要解耦?
分类任务关注"是什么",回归任务关注"在哪里",两者优化目标不同。如果强行共享同一套预测参数,分类梯度和回归梯度可能互相干扰。因此 YOLOv8 将二者拆分,分别学习,通常能获得更稳定训练、更快收敛、更高定位精度。
TaskAlignedAssigner(TAL)
YOLOv8 精度提升并不仅仅来自解耦头。另一个关键组件是 TaskAlignedAssigner(TAL)。
其核心思想是:标签分配时同时考虑分类质量和定位质量。传统匹配通常只看 IoU 或 Anchor 匹配程度,而 TAL(源自 TOOD 论文)使用分类得分和 IoU 的加权组合构建对齐指标:
t = s^α · u^β
s = Classification Score(分类得分)
u = IoU(预测框与 GT 框的交并比)
α = 0.5(默认)
β = 6.0(默认,IoU 权重远大于分类权重)
因此"分类好定位差"或者"分类差定位好"都不一定被选为最佳匹配。由于 β >> α,TAL 实际上更重视定位质量。TAL 使分类目标和定位目标在训练过程中更加一致。
说明
YOLOv8 的性能提升来源于多项改进共同作用:
- C2f Backbone
- PAN-FPN Neck
- Anchor-free 检测机制
- Decoupled Head
- Distribution Focal Loss(DFL)
- CIoU Loss
- TaskAlignedAssigner(TAL)
因此不能将精度提升简单归因于某一个模块。尤其在小目标场景中,Backbone、Neck、DFL 与 TAL 往往同样重要。
三、损失函数设计
YOLOv8 损失函数包含三个组成部分:box_loss (边界框回归)、dfl_loss (分布焦点损失)、cls_loss(分类损失)。
3.1 IoU-based Box Loss(边界框回归)
YOLOv8 默认采用 IoU-based Box Loss,当前实现中使用 CIoU(Complete IoU)。
实现说明 :源码中通过
bbox_iou(..., CIoU=True)调用,但 Ultralytics 框架支持多种 IoU 变体(CIoU/EIoU/SIoU/WIoU),不同版本或配置可能有所调整。
CIoU(Zheng et al., CVPR 2020)同时考虑三个几何因素:
CIoU = IoU − (ρ²/c² + v·α)
| 项 | 含义 | 公式 |
|---|---|---|
IoU |
重叠面积 | 预测框 ∩ 真实框 / 预测框 ∪ 真实框 |
ρ²/c² |
归一化中心距离 | ρ = 两中心点欧氏距离,c = 最小包围框对角线 |
v·α |
宽高比一致性 | v = (4/π²)(arctan(w₂/h₂) − arctan(w₁/h₁))²,α 为动态权重 |
对比其他 IoU 损失:
- GIoU:仅考虑重叠 + 包围框
- DIoU:重叠 + 中心距离(缺少宽高比)
- CIoU:几何建模最完整
CIoU 在 YOLOv3/SSD/Faster R-CNN 等多个检测器上带来一致 AP 提升(但 Faster R-CNN 小目标 AP 略有下降)。
3.2 Distribution Focal Loss / DFL(边界框建模)
DFL (Li et al., arXiv:2006.04388)将边界框坐标从单一值 (Dirac delta)建模为离散概率分布:
DFL(Sᵢ, Sᵢ₊₁) = −[(yᵢ₊₁ − y)log(Sᵢ) + (y − yᵢ)log(Sᵢ₊₁)]
- Ultralytics 实现采用 reg_max=16,对应每条边预测 16 个离散概率值(0~15)
- 全局最优解使估计值无限逼近标签
- 核心优势:DFL 允许网络表达边界位置的不确定性,而非直接回归单一点值。例如真实距离为 7.3 时,网络预测"7 的概率为 0.7,8 的概率为 0.3"比直接预测 7.3 更容易优化
背景 :GFLv2(arXiv:2011.12885, CVPR 2021)进一步验证了 General Distribution 表示的有效性,发现分布统计特征与定位质量具有显著相关性(distribution statistics are highly correlated with localization quality)。例如,集中在真实值附近的分布通常对应较高 IoU,但这是相关性而非充分必要条件------偏移但尖锐的分布可能 IoU 很差,稍宽但中心正确的分布反而 IoU 更高。GFLv2 还提出轻量 DGQP 子网络(两层 FC,隐藏层 p=64)即可从分布形状预测定位质量。
3.3 BCE(分类损失)
YOLOv8 使用标准 Binary Cross-Entropy (BCEWithLogitsLoss)作为分类损失,未采用 QFL(Quality Focal Loss)。
常见误解:很多人以为"用了 DFL = 用了 GFL = 用了 QFL",实际上 YOLOv8 分类损失确实是标准 BCE,不是 QFL。
最终损失组合 :Loss = box_loss + cls_loss + dfl_loss
权重来自配置文件(default.yaml):
yaml
box: 7.5
cls: 0.5
dfl: 1.5
3.4 为什么既有 CIoU 又有 DFL?
这是很多人第一次看 YOLOv8 损失函数最困惑的地方:DFL 已经在回归边界框了,为什么还要 CIoU?
两者的职责不同:
- DFL :学习边界距离的概率分布(L/T/R/B 各 16 个概率值)
- CIoU :优化解码后最终框的几何关系(重叠面积、中心距离、宽高比)
训练时的数据流:
DFL
↓ 预测 L/T/R/B 的 16 个概率
解码
↓ DFL 解码为 4 个距离值
Bounding Box
↓ 结合网格中心点计算最终框坐标
CIoU
↓ 比较预测框和 GT 框的几何关系
因此 DFL 和 CIoU 不是替代关系,而是协作关系:DFL 负责从分布中学习到精确的边界距离,CIoU 负责确保最终框在几何意义上尽可能与 GT 对齐。两者共同完成定位学习。
四、YOLOv8 模型规模变体(n/s/m/l/x)
YOLOv8 通过 三维缩放机制 对网络深度、宽度和最深层通道数进行灵活调整,以满足不同场景的精度与计算资源需求。
4.1 三维缩放机制
| 参数 | 控制内容 | 注释 |
|---|---|---|
depth_multiple |
C2f 模块内部 Bottleneck 重复次数 | 控制网络深度,越大网络越深,感受野更大,特征表达能力增强 |
width_multiple |
通道数缩放 | 控制网络每层通道数,增加通道可提升特征表达能力,但增加计算量 |
max_channels |
最深层通道上限 | 限制网络最深层最大通道数,避免过大导致显存浪费或过拟合 |
说明:三维缩放机制允许网络在参数量、FLOPs 和精度之间做平衡,同时为边缘设备部署提供可控空间。
4.2 模型规模参数与性能
| 变体 | depth | width | max_ch | 参数量 | FLOPs | COCO mAP@50-95 (Val2017) |
|---|---|---|---|---|---|---|
| n | 0.33 | 0.25 | 1024 | 3.2M | 8.7B | 37.3 |
| s | 0.33 | 0.50 | 1024 | 11.2M | 28.6B | 44.9 |
| m | 0.67 | 0.75 | 768 | 25.9M | 78.9B | 50.2 |
| l | 1.00 | 1.00 | 512 | 43.7M | 165.2B | 52.9 |
| x | 1.00 | 1.25 | 512 | 68.2M | 257.8B | 53.9 |
备注:
max_channels在 m/l/x 递减(1024→768→512),用于在保持表达能力的前提下降低深层计算量和显存消耗。- FLOPs 与参数量基于 640×640 输入图像 测算,不同输入分辨率计算量会成比例变化。
- mAP 为官方 Val2017 自报结果,社区复现可能略低(±0.5~1 mAP)。
4.3 精度-效率权衡
YOLOv8 各规模模型在精度与效率上的边际收益呈递减趋势:
| 升级 | 参数增加 | mAP 增益 | 分析 |
|---|---|---|---|
| n→s | +3.5× | +7.6 | 性价比高,适合资源受限场景 |
| s→m | +2.3× | +5.3 | 仍合理,适合中高端设备 |
| m→l | +1.7× | +2.7 | 边际收益开始下降 |
| l→x | +1.6× | +1.0 | 增益有限,适合高算力追求极限精度场景 |
说明:随着模型规模增大,每增加单位参数量带来的 mAP 提升逐渐减小,选择模型需根据算力与实际应用场景权衡。
4.4 边缘设备部署建议
| 芯片 | 推荐变体 | 理由 |
|---|---|---|
| RK3568 (1 TOPS) | n / s | 高算力模型如 m(25.9M/78.9B)可能无法达到实时帧率 |
| RK3588 (6 TOPS) | n / s / m | 算力充裕,s 是精度与速度平衡点,可适当选择 m 提升精度 |
注意:
- TOPS 为理论峰值,实际部署 FPS 受输入分辨率、内存带宽、NPU/CPU 调度、后处理开销等因素影响。
- 以上推荐仅供参考,实际部署需根据硬件测试实时帧率调整。
五、训练策略与数据增强
5.1 默认增强策略
| 增强方法 | 默认概率 | 说明 |
|---|---|---|
| Mosaic | 1.0 | 4 图拼接,增加小目标和上下文多样性 |
| MixUp | 0.0 | 两图混合叠加,默认关闭 |
| Copy-Paste | 0.0 | 实例级复制粘贴,默认关闭 |
关键细节:
- close_mosaic=10:训练最后 10 个 epoch 自动关闭 Mosaic,避免过度增强影响收敛(Mosaic 生成的图像分布与真实推理图像分布不同,训练结束前持续使用会影响最终收敛)
- 当前 Ultralytics 实现中,Copy-Paste 主要用于实例分割(Segment)任务,在目标检测(Detect)任务中通常不会生效(这是实现限制而非算法原理限制,很多论文在 Detect 上使用 Copy-Paste)
5.2 HSV 增强(容易忽略的重要增强)
YOLOv8 默认包含 HSV 颜色空间增强:
yaml
hsv_h: 0.015 # 色调变化
hsv_s: 0.7 # 饱和度变化
hsv_v: 0.4 # 亮度变化
HSV 增强对以下场景影响很大:
- 室外摄像头(白天/夜晚、阴天/晴天)
- 工厂监控(光照变化)
- 不同季节/时间段
实际项目经验:很多工业检测项目中,HSV 增强的贡献 > MixUp 的贡献。
5.3 本项目(管道泄露 + 人员检测)的调优建议
默认配置已较合理:
yaml
mosaic: 1.0
mixup: 0.0
copy_paste: 0.0
close_mosaic: 10
若 leak 样本稀少,优先考虑以下方案(按优先级排序):
- 增加真实样本:数据采集是最有效的方式
- 类别重采样(Class Rebalancing):增加少数类采样频率
- 保持 Mosaic:已默认开启,对小目标有帮助
- 适度增强 Scale/Translate/Flip:
yaml
degrees: 5
translate: 0.1
scale: 0.5
fliplr: 0.5
- 保留 HSV 增强:默认已开启,对光照变化有帮助
不推荐的方案:
- MixUp:对于小目标、弱纹理、低对比度的泄漏目标,MixUp 可能使目标更模糊,反而伤害检测。MixUp 更适合分类任务和大目标检测(如 COCO、ImageNet)
- Copy-Paste:当前 YOLOv8 Detect 任务中通常不会生效,如需使用需自行扩展实现
总结:工业缺陷检测项目通常优先使用 Mosaic + HSV + Scale/Translate/Flip,而非 MixUp。
六、边缘部署:RKNN 转换与量化
6.1 RKNN 导出支持
RKNN 已被 Ultralytics 纳入官方导出格式列表,可通过 model.export(format='rknn') 调用。底层流程以 ONNX 作为中间表示,再调用 RKNN Toolkit2 完成模型编译与量化。
支持能力:
- 支持 INT8 量化
- 当前 Ultralytics 的 RKNN 导出能力主要面向检测模型,其他任务(分类、分割、姿态估计)的支持情况需以对应版本文档为准
环境要求:
- RKNN Toolkit2 官方推荐在 x86 Linux 环境完成模型转换与量化,板端通常仅负责推理部署
- 需安装与目标 NPU 平台兼容的 RKNN Toolkit2 版本
6.2 本项目流水线 vs 官方 API
| 方面 | 官方 model.export(format='rknn') |
本项目 export_onnx.py + build_rknn.py |
|---|---|---|
| 控制粒度 | 封装度高,参数有限 | 精细控制量化数据集、RKNN 参数 |
| 灵活性 | 低 | 高 |
| 建议 | 快速验证 | 生产环境继续使用 |
6.3 ONNX 导出注意事项
int8参数:ONNX Runtime INT8 量化与 RKNN INT8 量化是两套独立的校准流程。RKNN 通常使用自身校准流程完成 INT8 量化,不依赖 Ultralytics 导出的 ONNX Runtime INT8 模型half参数:FP16 ONNX 在某些 RKNN 版本和平台上可以正常转换,但为提高兼容性,通常建议导出 FP32 ONNX,再由 RKNN Toolkit 完成量化dynamic参数:RKNN 更适合固定输入尺寸模型。虽然部分版本支持动态输入,但通常不建议在生产环境启用 dynamic,因为可能导致 NPU 无法充分优化- 本项目应使用
simplify=True(图优化)和正确的imgsz(必须匹配 RKNN 配置)
6.4 INT8 量化校准建议
对于 RK3568/RK3588 项目,量化精度主要取决于校准集(Calibration Dataset)质量,而非 ONNX 导出参数。
校准集要求:
- 覆盖多种场景:白天、夜晚、室内、室外、泄漏场景、非泄漏场景
- 推荐 50~500 张代表性图片
- 图片应与实际部署环境一致(分辨率、光照、角度)
总结:量化误差主要由校准集质量决定。校准集越能代表真实推理场景,量化后的精度损失越小。
参考来源
一手来源(Primary)
- CIoU 论文 --- Zheng et al., CVPR 2020
- GFL / DFL 论文 --- Li et al., NeurIPS 2020
- GFLv2 论文 --- Li et al., CVPR 2021
- Ultralytics RKNN 集成
- Ultralytics 模型页面
- rknn_model_zoo
- ultralytics/ultralytics yolov8.yaml --- 模型结构定义
- ultralytics default.yaml --- 训练默认参数
- ultralytics head.py --- 检测头实现