YOLOv8 检测头 INT8 量化与 DFL 总结
1. DFL 是什么?
DFL = Distribution Focal Loss,中文通常称为分布焦点损失。
它最早来自论文 Generalized Focal Loss: Learning Qualified and Distributed Bounding Boxes for Dense Object Detection。这里的核心思想是:
不要让检测器直接预测一个连续的边界框距离,而是让它预测这个距离对应的概率分布。
这是理解 YOLOv8 检测头的关键。
2. 普通边界框回归是什么?
假设一个目标框:
┌──────────────────────┐
│ │
│ Object │
│ │
└──────────────────────┘
对于某个网格点/anchor point,通常可以表示成:
l = 到左边界的距离
t = 到上边界的距离
r = 到右边界的距离
b = 到下边界的距离
传统方式可能直接回归:
l = 12.3
t = 8.7
r = 15.2
b = 10.6
也就是:
feature → 一个连续数值
3. DFL 的核心思想
DFL 不直接预测:
l = 12.3
而是预测:
l 属于 0、1、2、3、...、15 的概率
例如:
distance = 12.3
概率分布:
0 0.00
1 0.00
...
11 0.03
12 0.67
13 0.30
14 0.00
...
15 0.00
然后通过概率期望得到最终的连续距离:
12 × 0.67 + 13 × 0.30 + ...
≈ 12.3
所以它不是简单地:
预测一个数字
而是:
预测一个离散概率分布
↓
计算概率期望
↓
得到连续距离
这就是 DFL 思想的核心。
4. 为什么这样做?
因为直接预测:
12.3
对于神经网络来说,边界框的位置变化实际上并不是一个特别简单的连续回归问题。
DFL 把它转换成:
12附近的概率是多少?
13附近的概率是多少?
这样网络可以表达:
12.1
12.3
12.7
这种连续位置的不确定性。
因此边界框定位通常可以得到更细粒度的表达。
5. YOLOv8 中 DFL 在哪里?
YOLOv8 的检测头可以粗略理解成:
┌── 分类分支
Backbone → Neck → Detect
└── 边界框分支
│
↓
DFL
│
↓
bbox / box decode
边界框分支不是简单输出:
4 个数字
而是输出:
4 × reg_max
个值。
以常见的 reg_max = 16 为例:
左:16 个值
上:16 个值
右:16 个值
下:16 个值
总共:
4 × 16 = 64
这些值经过类似:
logits
↓
softmax
↓
概率分布
↓
× [0,1,2,...,15]
↓
sum
↓
连续距离
最终得到:
l
t
r
b
6. 所以 DFL 并不等于 DFL Loss
这里特别容易产生误解。
严格来说:
DFL = Distribution Focal Loss
它首先是一个损失函数/训练思想。
但在 YOLOv8 的工程实现中,我们经常也把检测头中负责:
离散分布
→ softmax
→ expectation
→ 连续 bbox distance
这一套推理过程称为 DFL。
所以在讨论 RKNN 模型结构时,大家说:
“YOLOv8 的 DFL”
很多时候实际上指的是:
DFL regression head / DFL integral,也就是训练时的分布式框回归思想以及推理时的分布积分过程。
两者不要完全等同。
7. 为什么 DFL 对 INT8 比较敏感?
这里就和你的 RKNN 问题直接关联起来了。
DFL 有一条比较敏感的计算链:
INT8 feature
↓
quantized logits
↓
softmax
↓
probability distribution
↓
weighted sum
↓
bbox distance
假设原始 logits 是:
[... -1.2 2.8 4.1 1.3 ...]
量化以后存在误差:
[... -1.2 2.7 4.0 1.4 ...]
看起来每个数字只差一点。
但是经过:
softmax
以后,它们会被转换成概率分布。
然后又进行:
Σ probability × bin
最终得到 bbox distance。
所以:
前面的量化误差会经过 softmax + expectation 继续传递到边界框坐标。
这就是 DFL 对量化比较敏感的原因之一。
8. 分类分支和 DFL 分支的问题其实不完全一样
YOLOv8 检测头大致可以拆成:
Detect Head
│
┌───────────┴───────────┐
↓ ↓
Classification Box Regression
│ │
sigmoid DFL
│ │
class score l/t/r/b
两边的量化敏感点不同。
分类分支
主要是:
logits
↓
sigmoid
↓
class score
大量背景位置可能非常接近:
0.0001
0.001
0.005
0.01
只有少数目标:
0.6
0.8
0.9
因此存在明显的长尾动态范围。
Box Regression / DFL
则是:
distribution logits
↓
softmax
↓
probability distribution
↓
expectation
↓
bounding box
这里对 logits 的相对差异比较敏感。
因此:
分类分支和 DFL 分支都可能对 INT8 敏感,但敏感机制不同。
不能简单说:
“YOLOv8 因为 DFL 所以 INT8 一定会崩。”
这不准确。
9. 为什么混合量化可能有效?
因此在 RKNN 中可能采用:
Backbone INT8
Neck INT8
普通 Conv INT8
Detect Head 部分 FP16
DFL FP16
Output FP16
而不是:
整个模型全部 INT8
目的就是:
大部分计算
↓
INT8
↓
获得 NPU 性能
敏感检测头
↓
FP16
↓
减少量化误差
这就是混合精度/混合量化的基本思路。
10. 回到你看到的“输出变成 0”
因此,对于:
全 INT8 后 output0 出现大量 0 / 峰值异常
不能直接下结论说:
“DFL 导致 output0 归零。”
应该把问题拆成:
全 INT8
│
├── 分类分支
│ └── 动态范围/量化分辨率问题
│
└── Box Regression
│
└── DFL
├── logits 量化误差
├── softmax
└── expectation
然后检查:
① output0 到底是什么张量?
② output0 前面的算子是什么?
③ RKNN 给这个张量分配了什么 scale?
④ zero-point 是多少?
⑤ 校准集覆盖了真实推理分布吗?
⑥ 是否发生 saturation?
⑦ 是否大量小值量化到 zero?
⑧ DFL 是不是被量化了?
只有把这些确认下来,才能确定“0”究竟是分类分支量化问题、DFL 量化问题,还是 RKNN 输出/后处理接口解释错误。
一句话理解 DFL
可以把它记成:
DFL(Distribution Focal Loss)是一种把“直接预测边界框距离”改成“预测距离的离散概率分布,再通过概率期望恢复连续距离”的目标框回归方法。
所以 YOLOv8 的边界框预测不是简单的:
feature → 4 个 bbox 数字
而更接近:
feature
↓
4 × reg_max 个 logits
↓
4 组概率分布
↓
softmax
↓
概率期望
↓
l / t / r / b
↓
bbox
这也解释了为什么在 RKNN 全 INT8 量化场景下,YOLOv8 的检测头需要重点关注:分类分数的动态范围 + DFL 分布计算的数值精度。
283



被折叠的 条评论
为什么被折叠?



