YOLO补习
从 YOLOv1 到 YOLOv8 的核心概念梳理
⚠️ 声明:本文为个人复习笔记,主要参考了 AI 菌的 YOLO 系列博客,并借助 AI 辅助整理和说明。网络架构部分(如 Darknet-53、CSPDarknet53、PANet 等)理解尚浅,仅作记录备查,如有错误欢迎指正。
YOLO 的一些特点
- 单阶段(V1)
- 划分 S×S 格机制(V1)
- Anchor Box 机制(V2)
- Darknet-19(V2)
- 细粒度特征(Fine-Grained Features)V2
- Darknet-53 V3
- 多尺度预测 V3
- 损失函数改进 V3
- 多标签分类 V3
- V4 架构
- V4 技巧
- V5 改进
- Anchor-Free 的思想 V8
一、单阶段(V1)
- 把目标检测转变成一个回归问题,利用整张图作为网络的输入,仅仅经过一个神经网络,得到 bounding box(边界框)的位置及其所属的类别。
- 双阶段:R-CNN,精度高但速度慢;生成候选区域 + 分类,精修位置。
二、划分 S×S 格机制(分而治之 V1)
- 通过”每个格子只能预测有限个目标 + 中心点唯一归属”来解决重复标注问题。
- 空间分区 + 预测数量上限来控制冗余。
- 早期的滑动窗口、或者某些密集预测模型会在每一个可能的位置都尝试预测,生成数百的候选框,给 NMS 带来极大压力。
实现
- 将一幅图像分成 S×S 个网格(V1 是 7×7),如果某个 object 的中心落在这个网格中,则这个网格就负责预测这个 object。
- 每个网格要预测 B 个 bounding box(V1 是 2 个,它们没有预定义形状,而是在训练过程中自行分化以覆盖不同的目标),每个 bounding box 要预测 $(x, y, w, h)$ 和 confidence 共 5 个值。
- 每个网格还要预测一个类别信息,记为 C 个类。
- 总的来说,S×S 个网格,每个网格要预测 B 个 bounding box,还要预测 C 个类。网络输出就是一个 $S \times S \times (5 \times B + C)$ 的张量。
YOLOv1 损失函数
YOLO 把目标检测变成一个回归问题:给一张图,直接输出一个 $S \times S \times (5B + C)$ 的张量。为了让网络学会正确输出,需要一个损失函数(Loss Function) 来衡量:
- 预测的框位置对不对?
- 预测的类别对不对?
- 有没有物体却说有?没物体却说没有?
YOLOv1 的损失函数就是把这些需求加权组合起来的一个总误差,可以拆解为以下几部分:
\[\mathcal{L} = \lambda_{\text{coord}} \cdot \mathcal{L}_{\text{loc}} + \mathcal{L}_{\text{conf}} + \lambda_{\text{noobj}} \cdot \mathcal{L}_{\text{noobj}} + \mathcal{L}_{\text{class}}\]1. 定位损失 $\mathcal{L}_{\text{loc}}$ —— “框画得准不准?”
- 只对包含物体中心的网格计算(即”负责预测”的网格)
- 对每个网格中 B 个 bounding box,只选与真实框 IoU 最大的那个来计算损失
- 损失内容:预测的 $(x, y, w, h)$ 和真实值的误差
\[\mathcal{L}_{\text{loc}} = \sum_{i=0}^{S^2} \sum_{j=0}^{B} \mathbb{1}_{ij}^{\text{obj}} \left[ (x_i - \hat{x}_i)^2 + (y_i - \hat{y}_i)^2 + (\sqrt{w_i} - \sqrt{\hat{w}_i})^2 + (\sqrt{h_i} - \sqrt{\hat{h}_i})^2 \right]\]⚠️ 注意:YOLO 对 $w$ 和 $h$ 取了平方根($\sqrt{w}, \sqrt{h}$)再算误差。为什么? 因为大框和小框的误差尺度不同。比如:真实宽=100,预测=90 → 误差 10;真实宽=10,预测=0 → 误差 10。但后者更严重!取平方根后,小框的误差会被放大,让模型更关注小物体。
- $\mathbb{1}_{ij}^{\text{obj}}$:只有当第 $i$ 个网格的第 $j$ 个框”负责”某个真实物体时才为 1,否则为 0。
2. 置信度损失(有物体)$\mathcal{L}_{\text{conf}}$ —— “你说有物体,把握大吗?”
- 同样只对负责预测的框计算
- 比较预测的 confidence 和真实 confidence
- 真实 confidence = IoU(预测框与真实框的重叠度)
- 所以不是简单的 0/1,而是”你画得越准,要求你的 confidence 越接近 1”
3. 置信度损失(无物体)$\mathcal{L}_{\text{noobj}}$ —— “没东西的地方,别瞎报!”
- 图像中绝大多数网格是背景(没有物体中心)
- 如果不惩罚这些地方的”误报”,模型会到处乱预测框
- 对所有不负责任何物体的网格,惩罚它们预测的 confidence(应该接近 0)
⚠️ 因为负样本(无物体)太多,这项损失会压倒其他项,所以 YOLO 用一个小权重 $\lambda_{\text{noobj}} = 0.5$ 来降低它的影响。
其中 \(\mathbb{1}_{ij}^{\text{noobj}} = 1 - \mathbb{1}_{ij}^{\text{obj}}\),表示该网格的该框不负责任何真实物体。
4. 分类损失 $\mathcal{L}_{\text{class}}$ —— “如果是猫,就别说成狗!”
- 只对包含物体中心的网格计算
- 比较预测的类别概率和真实标签
- 用平方误差(YOLOv1 没用交叉熵)
5. 权重系数:平衡各项的重要性
| 项 | 默认权重 | 原因 |
|---|---|---|
| 定位损失 $\mathcal{L}_{\text{loc}}$ | $\lambda_{\text{coord}} = 5$ | 定位不准比分类错更严重,要重点优化 |
| 无物体置信度损失 | $\lambda_{\text{noobj}} = 0.5$ | 负样本太多,不压低会主导训练 |
损失函数总结
| 责任 | 谁负责? | 惩罚什么? | 权重 |
|---|---|---|---|
| 框的位置 | 有物体中心的网格 | $(x, y, \sqrt{w}, \sqrt{h})$ 偏差 | ×5 |
| 有物体的置信度 | 负责预测的框 | confidence ≠ IoU | ×1 |
| 无物体的置信度 | 所有其他框 | confidence ≠ 0 | ×0.5 |
| 类别预测 | 有物体中心的网格 | 类别概率偏差 | ×1 |
💡 核心思想:让模型在”该说话的时候大声说,不该说话的时候闭嘴”,并且”说就要说准”。
🌟 核心洞见: YOLO 每个 bbox 预测的 confidence = $Pr(\text{Object}) \times \text{IoU}$, 它衡量的是”这里有物体且框画得准”的程度。
测试时最终检测得分 = 类别概率 × confidence =
\[Pr(\text{Class}_i \mid \text{Object}) \times Pr(\text{Object}) \times \text{IoU}\]
YOLOv1 损失函数的优缺点
✅ 优点:
- 统一框架:定位、置信度、分类全在一个 loss 里,端到端训练
- 抑制背景误报:通过 $\mathcal{L}_{\text{noobj}}$ 有效减少假阳性
❌ 缺点:
- 用平方误差代替交叉熵,对分类不够优化
- 一个网格只能负责一个物体 → 密集小物体容易漏检
- 对定位误差和分类误差同等对待(虽有权重,但仍是 L2)
后续版本(YOLOv2~v8)改用 Focal Loss、CIoU Loss、交叉熵 等更先进的损失函数。
V1 缺点
- 对相互靠近的物体,以及很小的群体检测效果不好,这是因为一个网格只预测了 2 个框,并且都只属于同一类。
- 由于损失函数的问题,定位误差是影响检测效果的主要原因,尤其是大小物体的处理上,还有待加强。(因为对于小的 bounding boxes,small error 影响更大)
- YOLO 对不常见的角度的目标泛化性能偏弱。
三、Anchor Box 机制(V2)
要解决的问题
- 尺度敏感:预测一个 10×10 的小框 vs 300×300 的大框,误差尺度完全不同,网络很难同时学好大小物体。
- 形状多样:单靠固定数个框很难适应所有形状。
实现
核心思想:“先猜个大概,再微调”
- 在训练前,通过聚类分析(如 K-Means)统计训练集中所有真实框的宽高比(aspect ratio)和尺度(scale),选出最常见的 B 种形状,作为 Anchor Boxes。
- 每个网格对应 B 个 Anchor。
- 模型不再预测 $(w, h)$,而是预测”偏移量”。对每个 Anchor,模型输出:
- $t_x, t_y$:中心点相对于 Anchor 中心的偏移
- $t_w, t_h$:宽高相对于 Anchor 宽高的缩放因子
然后通过公式还原真实框:
\[\begin{aligned} b_x &= \sigma(t_x) + c_x \\ b_y &= \sigma(t_y) + c_y \\ b_w &= p_w \cdot e^{t_w} \\ b_h &= p_h \cdot e^{t_h} \end{aligned}\]其中:
- $(c_x, c_y)$:当前网格/位置的左上角坐标(归一化)
- $(p_w, p_h)$:Anchor 的宽和高(归一化)
- $\sigma$:sigmoid 函数,保证中心点落在当前格子内
✅ 这样,网络只需要学习小的调整量(比如 $t_w = 0.1$ 表示”比 Anchor 宽 10%”),而不是从零预测绝对尺寸!
四、Darknet-19(V2)
架构
- 与 VGG 相似,使用了很多 3×3 卷积核;并且每一次池化后,下一层的卷积核的通道数 = 池化输出的通道 × 2。
- 在每一层卷积后,都增加了批量标准化(Batch Normalization)进行预处理。
- 采用了降维的思想,把 1×1 的卷积置于 3×3 之间,用来压缩特征。
- 在网络最后的输出增加了一个 global average pooling 层。
- 整体上采用了 19 个卷积层,5 个池化层。
技巧
1. 1×1 卷积降维(Network in Network 思想)
- 卷积:$(64 \times 64 \times 3 \times 1)$ 的图像(宽高通道个数)与 $(3 \times 3 \times 3 \times 10)$ 的卷积核(10 个 $3 \times 3 \times 3$ 的不同卷积核)得到 $(62 \times 62 \times 1 \times 10)$ 的特征图 → $(3 \times 3 \times 10 \times 10)$ 的卷积核得到 $(60 \times 60 \times 1 \times 10)$
- 这里的降维就是 $(1 \times 1 \times 10 \times 8)$ 将 10 个特征图降为 8 个。
- 实质(宽×高×通道×输出特征图个数)也可以将输出特征图个数看作一个图的不同通道。
2. 用卷积代替全连接层(Fully Convolutional)
- 整个网络变成全卷积网络(FCN)
- 支持任意尺寸输入(只要能被 32 整除)
- 参数大幅减少(全连接层参数最多!局部连接 + 权重共享实现)
- 更适合滑动窗口式检测
3. Batch Normalization(批归一化)everywhere
- 每个卷积层后都加 BN + Leaky ReLU
- 加速训练收敛,减少对 dropout 的依赖(Darknet-19 不用 dropout!),提升模型泛化能力
- 实现:训练阶段计算批均值和方差 → 归一化 → 缩放和平移(可学习参数);推理阶段使用移动平均。
- 计算:C 个独立的均值和方差(每个通道一个)
- 在卷积或池化之后,激活函数之前(激活函数会改变数据分布)
4. 高分辨率分类器预训练(High-Resolution Classifier)
先在低分辨率稳定收敛,再微调高分辨率。
5. 多尺度训练(Multi-Scale Training)
训练中每 10 batch 随机切换输入尺寸(320~608)。
五、细粒度特征(Fine-Grained Features V2)
应对问题:小物体检测时被”池化”或”下采样”为非常小的像素。
实现(Passthrough Layer 直通层)
- 从浅层提取高分辨率特征
- 将高分辨率特征”压缩”后拼接到深层:把 $26 \times 26 \times 512$ 的特征图,通过 reorg 操作(多行矩阵变单行)变成 $13 \times 13 \times 2048$
- 然后把这个 2048 通道的细粒度特征与原来的 $13 \times 13 \times 1024$ 深层特征拼接 → $13 \times 13 \times (1024+2048)$
六、Darknet-53(V3)
Darknet-53 是什么?
- 提出时间:2018 年(YOLOv3 论文)
- 定位:为高精度实时目标检测设计的 CNN 骨干网络
- 名字由来:共 53 层(含卷积层 + shortcut 连接,不含上采样/检测头)
- 灵感来源:ResNet(残差结构)+ Darknet 系列的高效设计哲学
✅ 它不是为了 ImageNet 分类刷榜,而是专为目标检测任务优化。
整体架构
基本参数
- 输入尺寸:通常 416×416(也可 608×608)
- 总层数:53(主要由卷积层 + 残差块组成)
- 无全连接层 → 全卷积网络(FCN)
- 激活函数:Leaky ReLU(负斜率 = 0.1)
- 下采样方式:步长为 2 的卷积(代替池化层)
网络结构概览
| 阶段 | 操作 | 输出尺寸(以 416 输入为例) |
|---|---|---|
| Input | 图像输入 | 416×416×3 |
| Conv 3×3 | 32 filters, stride=1 | 416×416×32 |
| Conv 3×3 | 64 filters, stride=2 | 208×208×64 |
| Residual Block ×1 | 1 个残差块 | 208×208×64 |
| Conv 3×3 | 128 filters, stride=2 | 104×104×128 |
| Residual Block ×2 | 2 个残差块 | 104×104×128 |
| Conv 3×3 | 256 filters, stride=2 | 52×52×256 |
| Residual Block ×8 | 8 个残差块 | 52×52×256 ← 用于检测小物体 |
| Conv 3×3 | 512 filters, stride=2 | 26×26×512 |
| Residual Block ×8 | 8 个残差块 | 26×26×512 ← 用于检测中等物体 |
| Conv 3×3 | 1024 filters, stride=2 | 13×13×1024 |
| Residual Block ×4 | 4 个残差块 | 13×13×1024 ← 用于检测大物体 |
💡 三个关键特征图(52×52, 26×26, 13×13)会被送入 YOLO 检测头,实现多尺度预测!
💡 网络越浅(特征图越大)细节越丰富,网络越深(特征图越小)语义越强,但是特征图越小,目标所占区间就越小,特征图越大,计算量越大,因此检测小物体不能太深,而大物体可以深一些。
核心技巧
1. 残差连接(Residual Connections)
每个 Residual Block 由两个卷积 + shortcut(跳跃连接)组成:
1
Input → Conv 1×1 → Conv 3×3 → Add(Input) → Output
作用:缓解深层网络梯度消失;允许训练更深网络(53 层 vs Darknet-19 的 19 层);提升特征复用能力。
📌 Darknet-53 共有 1+2+8+8+4 = 23 个残差块,总计 2×23 = 46 个残差卷积层 + 1 个初始卷积 + 5 个下采样卷积(stride=2)= 52 个卷积层。名称中的”53”来自不同的计数惯例(部分实现会额外包含检测头前的一个卷积层)。
2. 全卷积设计(Fully Convolutional)
- 没有池化层(MaxPool),全部下采样通过 stride=2 的卷积完成
- 没有全连接层(FC)
- 优势:支持任意尺寸输入(只要能被 32 整除);参数更少;易于与上采样、FPN 等结构融合。
3. 多尺度特征提取(为 YOLOv3 服务)
Darknet-53 天然输出三个尺度的特征图:
- 大特征图(52×52):来自较浅层,保留细粒度细节 → 检测小物体
- 中特征图(26×26):平衡语义与细节 → 检测中等物体
- 小特征图(13×13):深层语义强 → 检测大物体
🔗 YOLOv3 会在这三个尺度上分别做预测,并通过上采样 + 特征融合(类似 FPN)进一步增强。
4. 1×1 卷积降维 + 3×3 卷积提特征
每个残差块内部采用 “1×1 → 3×3” 结构:
- 1×1 卷积:压缩通道数(如 256 → 128),减少计算量
- 3×3 卷积:提取空间特征
例如:
Conv 1×1 (128) → Conv 3×3 (256)比直接Conv 3×3 (256)节省约 50% 计算量!
5. Batch Normalization + Leaky ReLU everywhere
- 每个卷积后都加 BN + Leaky ReLU
- 加速收敛、提升泛化能力、减少对 Dropout 的依赖(Darknet-53 不使用 Dropout)
Darknet-53 vs Darknet-19 对比
| 特性 | Darknet-19 (YOLOv2) | Darknet-53 (YOLOv3) |
|---|---|---|
| 层数 | 19 | 53 |
| 残差连接 | ❌ 无 | ✅ 有(23 个残差块) |
| 多尺度输出 | ❌ 仅 13×13 | ✅ 13×13, 26×26, 52×52 |
| 小物体检测 | 较弱(靠 Passthrough) | 强(直接输出高分辨率特征) |
| ImageNet top-1 精度 | 76.5% | 77.2% |
| 推理速度(Titan X) | ~90 FPS | ~60 FPS |
| 参数量 | ~20M | ~40M |
✅ 结论:Darknet-53 更强但稍慢,适合对精度要求更高的场景。
Darknet-53 在 YOLOv3 中的实际使用
YOLOv3 并非直接用 Darknet-53 输出做预测,而是:
- 从 Darknet-53 提取三个特征图:52×52, 26×26, 13×13
- 对 13×13 特征图:先经过几个卷积 → 预测大物体
- 对 13×13 上采样 2 倍 → 26×26,与原 26×26 特征图拼接(concatenate),再卷积 → 预测中等物体
- 对融合后的 26×26 上采样 2 倍 → 52×52,与原 52×52 拼接 → 预测小物体
🔁 这种自顶向下 + 特征融合的结构,类似于 FPN(Feature Pyramid Network),极大提升了小物体检测能力。
Darknet-53 的设计哲学
| 设计理念 | 具体体现 |
|---|---|
| 深度 + 残差 | 53 层 + 残差块 → 更强表达能力 |
| 效率兼顾 | 1×1 卷积降维、无 FC 层、Leaky ReLU |
| 多尺度原生支持 | 直接输出三层特征图,适配 YOLOv3 多尺度检测 |
| 工程友好 | 全卷积、易部署、支持变尺寸输入 |
🌟 Darknet-53 是“深度残差网络 + 实时检测需求”的完美结合,至今仍被 YOLOv4/v5/v7/v8 的改进版(如 CSPDarknet)所借鉴。
七、多尺度预测(V3)
详见上节 Darknet-53 的多尺度特征提取部分。YOLOv3 在三个不同尺度的特征图(52×52, 26×26, 13×13)上分别做预测,通过上采样 + 特征融合(类似 FPN)增强各层的表达能力。
八、损失函数改进(V3)
位置损失部分并没有改变,但是置信度损失和类别预测均由原来的平方和误差改为了交叉熵的损失计算方法。对于类别以及置信度的预测,使用交叉熵的效果应该更好。
交叉熵损失:越不可能发生的事,一旦发生,带来的”惊讶程度”就越高。
交叉熵损失 = $-\log(\text{模型对真实类别的预测概率})$
预测概率越接近 0,损失爆炸式增长!能惩罚”自信的错误”。
优势:梯度友好;最大似然估计的等价形式;天然惩罚”高置信度错误”。
九、多标签分类(V3)
解决的问题:在一些复杂的场景中,单一目标可能从属于多个类别。
实现:对每个类别独立做二分类
- 输出层:使用 Sigmoid 激活函数(不是 Softmax),每个神经元输出 ∈ (0, 1),表示”属于该类的概率”,各类别相互独立。
- 损失函数:使用 Binary Cross-Entropy(BCE 二元交叉熵)对每个类别分别计算,再求平均(或求和)。
二元交叉熵:$\text{BCE} = -[ y \cdot \log(p) + (1-y) \cdot \log(1-p) ]$,其中 $y$ 为真实标签(0 或 1),$p$ 为预测值(0~1)。
十、V4 架构
YOLOv4 = CSPDarknet53(主干)+ SPP 附加模块(颈)+ PANet 路径聚合(颈)+ YOLOv3(头部)
CSPDarknet53(跨阶段局部网络)
核心思想:将输入特征图分两路处理,一路直接 bypass,一路经过残差块,最后融合。
实现
- 将输入通道 split 成两部分(通常 1:1)
- Part A(50% 通道)→ 直接 bypass(直接传递)
- Part B(50% 通道)→ 送入残差块序列
- Part B 经过 N 个残差块 → 得到 processed feature
- 将 Part A 和 processed Part B 拼接(concatenate)
- 再通过一个 transition layer(1×1 卷积)融合
技巧
- Mish 激活函数(平滑、非单调、提升精度,但稍慢)
- 全卷积 + 步长卷积下采样(无池化)
- 多尺度输出 + PANet 融合(在检测头中)
- Batch Normalization + 自适应激活
SPP 附加模块(Spatial Pyramid Pooling,空间金字塔池化)
SPP 模块通过在不同尺度上做池化,然后拼接结果,使网络能捕捉多尺度上下文信息,从而提升对不同大小物体的鲁棒性。
核心思想:多尺度池化 + 特征融合
解决的问题:固定感受野有局限性,SPP 使模型既知道细节,又知道整体场景。
实现
- 所有池化使用 stride=1 + padding,保持 spatial size 不变(如 13×13)
- 使用不同 kernel size(如 5, 9, 13)模拟多尺度上下文
- 最后与原始特征拼接 → 融合局部 + 多尺度全局信息
kernel size 是经验选择的,覆盖了从局部到接近全局的范围。
PANet(Path Aggregation Network,路径聚合网络)
PANet 通过构建”自上而下 + 自下而上”的双向特征金字塔,让高层语义信息和底层定位信息充分流动,从而显著提升对小物体、大物体和遮挡物体的检测/分割性能。
解决的问题
FPN 只能将高层语义传到底层,帮助小物体分类,而底层的精确定位信息无法有效传递到高层!
核心思想:双向特征金字塔
实现
假设 backbone 输出三层特征:C3(52×52)、C4(26×26)、C5(13×13)
1. FPN 路径(自上而下):
- P5 = C5
- P4 = Upsample(P5) + C4
- P3 = Upsample(P4) + C3
- → 得到 {P3, P4, P5},语义逐层增强
2. PANet 新增路径(自下而上):
- N3 = P3
- N4 = Downsample(N3) + P4
- N5 = Downsample(N4) + P5
- → 得到 {N3, N4, N5},定位信息逐层增强
3. 输出:
- 使用 {N3, N4, N5} 作为检测头的输入
- 每一层都同时包含强语义 + 精确定位
十一、V4 技巧
免费包(Bag of Freebies)
在不增加推理成本的前提下获得更好的精度,而只改变训练策略或只增加训练成本的方法。
数据增强方法
- 随机缩放、翻转、旋转
- 图像扰动、加噪声、遮挡
- 改变亮度、对比度、饱和度、色调
- 随机裁剪(Random Crop):从原始图像中随机截取一个子区域,然后 resize 到模型输入尺寸(如 224×224)
- 随机擦除(Random Erase):随机选择一个矩形区域用随机值(或均值/0)填充该区域
- Cutout:随机擦除固定用 0(黑色)填充
- MixUp:线性插值两个样本及其标签
- CutMix:用一张图的一部分”替换”另一张图的对应区域,同时按面积比例混合标签
| 场景 | 推荐方法 |
|---|---|
| 小数据集分类 | Random Erase + CutMix |
| 大模型防过拟合 | MixUp 或 CutMix |
| 目标检测训练 | Random Crop + Mosaic + HSV 色彩扰动 |
| 提升遮挡鲁棒性 | Cutout / Random Erase(分类)或 Copy-Paste(检测) |
正则化方法
- DropOut:在全连接层中,以概率 $p$ 随机将某些神经元的输出置为 0;测试时所有神经元保留,但输出乘以 $(1-p)$
- DropConnect:不是丢弃神经元输出,而是丢弃权重连接;对权重矩阵 $W$ 中的每个元素,以概率 $p$ 置为 0
- DropBlock:在卷积特征图上,随机选择若干个 block(正方形区域),将这些 block 内的所有通道全部置 0
平衡正负样本的方法
- Focal Loss
- OHEM(在线难分样本挖掘)
回归损失方面的改进
- GIoU、DIoU、CIoU
特价包(Bag of Specials)
只增加少量推理成本但能显著提高目标检测精度的插件模块和后处理方法。
增大感受野技巧
- SPP、ASPP、RFB
注意力机制
- Squeeze-and-Excitation (SE)
- Spatial Attention Module (SAM)
特征融合集成
- FPN、SFAM、ASFF、BiFPN(出自 EfficientDet)
更好的激活函数
- ReLU、LReLU、PReLU、ReLU6、SELU、Swish、hard-Swish
后处理非极大值抑制算法
- soft-NMS、DIoU NMS
适应在单 GPU 上训练
1. Mosaic
借鉴了 CutMix 数据增强方式的思想。CutMix 利用两张图片进行拼接,但是 Mosaic 是利用四张图片进行拼接。
2. SAT(自对抗训练)
通过梯度上升修改原始图像,使其最大化当前模型的损失,得到一张”人眼看不出区别,但模型会判错”的对抗图像,然后正常更新模型参数,最小化在对抗图像上的损失,让模型学会正确识别这种”最坏情况”。
3. CmBN(跨小批量归一化)
在一次前向传播中,把 batch 分成 K 个子块(sub-batches),然后在反向传播前累积这 K 次的统计量。单 GPU 显存不足以使用大 batch 会出现统计错误的情况,但分开 + 累计可以实现大 batch 效果。
4. 修改过的 SAM
SAM(Spatial Attention Module)来自 CBAM,原始结构:输入 feature map → 分别做通道平均池化 & 最大池化 → 拼接 → 卷积 → sigmoid → 生成 spatial mask,用 mask 乘原 feature → 强调重要区域。
修改点:
- 去掉通道池化,直接对 feature map 做卷积
- 使用单个卷积层(kernel=1 或 3)生成 attention mask
- mask 应用于残差连接之后(而非替换原特征)
- 更轻量,避免性能下降
5. 修改过的 PAN
主要修改:
- 将特征融合方式从”相加(add)”改为”拼接(concatenate)”:Concat 保留更多信息(add 会丢失部分通道信息),后续用 1×1 卷积降维
- 在 PAN 路径中加入 CSP 结构:减少计算冗余,提升梯度流效率
- 配合 SPP 模块使用:在 PAN 输入前先经过 SPP,增强多尺度上下文
十二、V5 改进
自适应锚框计算
通过 K-Means 方法来获取数据集的最佳 anchors 改为将此功能嵌入到整体代码中,每次训练时自适应地计算不同训练集中的最佳锚框值。
自适应灰度填充
应对输入图片尺寸不一的问题,使用灰度填充。核心思想是将原图的长宽等比缩放对应统一尺寸,然后对于空白部分用灰色填充。
损失函数
分类用交叉熵损失函数(BCE Loss),边界框回归用 CIoU Loss。
CIoU
同时考虑重叠(IoU)+ 位置(中心距离)+ 形状(宽高比)。
公式
CIoU 度量(越大越好):
\[\text{CIoU} = \text{IoU} - \frac{\rho^2(b, b^{gt})}{c^2} - \alpha v\]实际训练使用的 CIoU Loss = $1 - \text{CIoU}$(越小越好)。
其中:
- $\rho^2(b, b^{gt})$:中心点距离平方
- $c$:最小包围盒对角线长度
- $v$:宽高比一致性度量
- $\alpha$:权重系数(自适应调整)
宽高比差异 $v$
\[v = \frac{4}{\pi^2} \left( \arctan\frac{w^{gt}}{h^{gt}} - \arctan\frac{w}{h} \right)^2\]- 衡量预测框与真实框的宽高比差异,值 ∈ [0, 1],越接近 0 表示宽高比越一致
- arctan 把宽高比映射到角度空间,对称性更好且在 $[0, \infty)$ 上更平滑,天然有界,优化更稳定
- $\frac{4}{\pi^2}$ 将角度归一化到 [0, 1]
权重 $\alpha$(自适应)
\[\alpha = \frac{v}{(1 - \text{IoU}) + v}\]- 当 IoU 较大(框已较准)时,$\alpha \to 1$,强调宽高比对齐
- 当 IoU 很小(框很偏)时,$\alpha \to 0$,优先优化位置和重叠
💡 这种自适应机制非常聪明:先定位,再调形状!
十三、Anchor-Free 的思想(V8)
总结
不再预设任何锚框(anchor boxes),而是让网络在特征图的每个位置直接预测:”这里是否存在目标?如果有,它的边界框中心偏移、宽高(或四边距离)是多少?”
解决的问题(Anchor-Based 的三大痛点)
- 依赖数据集先验(k-means 聚类)
- 超参数敏感(额外的参数)
- 正样本分配复杂(一个真实框可能匹配多个 anchor)
实现
- 每个 grid cell(S×S 的格子)只预测一个 bbox
- 预测内容:直接回归边界信息
- 模型预测从 grid cell 中心点到 bbox 四条边的距离(left, top, right, bottom)
- 采用 DFL(Distribution Focal Loss)+ 边界距离回归的方式
- 坐标解码:基于 grid cell 中心点
- 配合 TAL(Task-Aligned Assigner) 动态分配正样本,不再基于 IoU 与 anchor 匹配,而是根据预测质量动态选择正样本
损失函数改进
VFL Loss 作为分类损失
将 IoU 作为分类分数的直接监督目标。原本的分类与标框是分开的,可能出现分类低(但正确)但标框好的情况,导致相乘得到置信度被拉低,进而被 NMS 滤掉。改进后 V8 的置信度就只输出 IACS 了。
⚠️ 注意:Ultralytics 官方 YOLOv8 实现中,分类损失实际使用 BCE + task-aligned soft labels(以 IoU 作为软标签),而非严格的 VFL。以下 VFL 描述反映的是该思想的一般形式,不同实现可能有差异。
VFL 提出两个关键创新:
1. IoU-aware Classification Score(IACS)
不再让分类分支只预测”类别概率”,而是预测一个融合了分类置信度 + 定位精度的分数:
\[\text{IACS} = P(\text{class}) \times \text{IoU}\]这个分数直接用于 NMS 排序(比单纯用分类分数更合理)。
2. 不对称焦点损失(Asymmetric Focal Loss)
对正样本和负样本使用不同的聚焦因子:
\[\text{VFL}(p, q) = \begin{cases} -q \cdot \log(p), & \text{if } y = 1 \quad \text{(正样本)} \\ -\alpha \cdot p^\gamma \cdot \log(1 - p), & \text{if } y = 0 \quad \text{(负样本)} \end{cases}\]其中:
- $p$:模型预测的 IACS 分数(∈ [0,1])
- $q$:目标分数(不是 1!而是真实 IoU 值)
- $\alpha, \gamma$:超参数(通常 α=0.75, γ=2)
🌟 最关键的区别:正样本的标签不是 1,而是真实的 IoU!
DFL Loss + CIoU Loss 作为边界框回归损失
DFL 的做法:用分类模拟回归
- 将连续距离离散化:设定一个范围(如 [0, 16) 像素),将其划分为 16 个区间(bins),每个 bin 宽度 = 1。真实距离 $d=5.3$ → 落在第 5 和第 6 个 bin 之间。
- 模型输出一个概率分布:对每个边界(l/t/r/b),模型输出 17 个 logits(对应 16 个 bin 的 17 个端点),通过 softmax 得到概率分布 $p_0 \sim p_{16}$。
- 用分布计算期望值(即预测距离):实际实现中,直接用加权和 $\sum p_i \cdot i$ 求得。
Distribution Focal Loss(DFL Loss)
设真实距离 $d = 5.3$:
- 左侧整数:$l = [d] = 5$
- 右侧整数:$r = l + 1 = 6$
- 权重:$w_l = r - d = 0.7$,$w_r = d - l = 0.3$
Loss 定义为:
\[\mathcal{L}_{\text{DFL}} = - \left[ w_l \cdot \log(p_l) + w_r \cdot \log(p_r) \right]\]✅ 只监督最近的两个位置,让模型学会”插值”,从而精确表示 5.3!
样本匹配(Task-Aligned Assigner)
TAL 的核心思想:根据预测质量动态分配——”谁预测得好,谁就负责这个目标。”
实现
- 对每个 GT,计算它与所有 grid 预测框的对齐分数 $s$
- 选出 top-k 个最高分的 grid 作为正样本(k=10)
- 同时过滤掉 cls_score < 阈值(如 0.5)的低质量预测
对齐分数(Alignment Score)
\[s = \text{cls_score}^\alpha \times \text{IoU}^\beta\]cls_score:该 grid 对该类别的预测置信度IoU:该 grid 预测框与 GT 的 IoU- $\alpha, \beta$:超参数(YOLOv8 默认 $\alpha=1.0, \beta=6.0$)
💡 IoU 权重更高 → 强调定位准确性
正样本与负样本
- 正样本(Positive Sample)= 应该负责预测某个真实目标(GT)的预测位置(grid)
- 负样本(Negative Sample)= 不负责任何 GT 的预测位置
- 正样本用于计算 Loss