1. 问题背景
在 Horizon J6 Open Explorer 工具链中部署 YOLOv8s 时,最初采用 Ultralytics 标准导出的 ONNX 模型。
标准 YOLOv8 ONNX 的输出通常为:
其中:
该输出已经在 ONNX 图内完成了:
使用 Horizon 工具链对该完整模型进行 INT8 量化后,检测精度出现严重下降。
2. 初始实验现象
在同一批 COCO val2017 前 50 张图片、相同预处理和相同评测逻辑下,原完整输出 YOLOv8s 的结果为:
模型阶段 | mAP50-95 | mAP50 |
|---|---|---|
Optimized Float | 0.537 | 0.696 |
INT8 Calibrated | 0.107 | 0.216 |
INT8 PTQ | 约 0.116 | 约 0.230 |
INT16 Calibrated | 0.532 | 0.689 |
INT16 PTQ | 0.532 | 0.686 |
可以看到:
该现象说明模型并不是不能量化,而是对 INT8 位宽非常敏感。
3. 初期排查方向
最开始主要怀疑以下问题:
RGB 和 BGR 顺序不一致;
输入是否重复除以 255;
校准数据范围是否错误;
NCHW 和 NHWC 布局不一致;
LetterBox 预处理不一致;
COCO 类别编号或坐标恢复错误;
ONNX 导出本身存在问题;
Horizon 图优化阶段改变模型计算结果;
校准图片数量不足;
INT8 对 YOLOv8 检测头不友好。
经过多轮对照后,前面的大部分原因都被排除。
4. 为什么可以排除输入和校准数据问题
校准数据采用:
YAML 中运行时输入配置为:
这里并不是重复除以 255:
校准数据已经是 ONNX 输入域的 float32,范围为 0~1;
板端 NV12 输入仍然是 uint8,范围为 0~255;
- YAML 中的 scale_value 用于将板端输入转换到模型输入域。
更关键的是,同一套校准数据下,INT16 模型可以恢复到接近浮点精度。
如果 RGB/BGR、输入范围或校准数据存在严重错误,INT16 通常也不会恢复到:
因此,主要问题不在输入预处理和校准数据。
5. 根本原因分析
问题的核心在于:
Ultralytics 标准导出的 YOLOv8 ONNX 将 DFL、Softmax、Sigmoid 和边框解码全部包含在模型图中,Horizon 对整个检测图执行 INT8 量化时,这些数值敏感运算也进入了量化范围。
5.1 DFL 对 INT8 量化误差敏感
YOLOv8 的边框回归不是直接预测四个边框坐标,而是为每个方向预测 16 个离散值:
随后执行:
INT8 量化会对 logits 进行缩放、截断和取整。
即使单个 logits 的误差较小,也可能改变 16 个 bin 之间的相对关系。误差经过 Softmax 和加权求期望后,会转化为边框距离误差。
5.2 stride 会进一步放大边框误差
DFL 得到的距离还会乘以不同特征层的 stride:
例如某个方向的 DFL 距离只偏差 0.2 个网格,在 P5 上就可能产生:
四个方向都可能存在偏差,最终导致边框 IoU 明显下降。
5.3 mAP50-95 比 mAP50 下降更多
在 YOLOv8x 的对照实验中,完整输出 INT8 的结果表现为:
这说明模型仍然能够找到目标,但边框定位变得不够准确。
目标在 IoU=0.5 时可能仍然匹配,但在 IoU=0.75、0.85 或 0.95 等高阈值下无法匹配,因此 mAP50-95 下降更明显。
这与 DFL 和坐标解码误差的表现高度一致。
6. Raw6 解决方案
为避免将敏感后处理纳入 INT8 量化图,重新导出了 YOLOv8s Raw6 ONNX。
模型固定输出六路原始特征:
其中:
新的部署边界为:
CPU 后处理实现包括:
六路输出顺序检查;
NCHW/NHWC 输出适配;
DFL Softmax;
16 个 bin 的距离期望;
三尺度 anchor point 解码;
分类 Sigmoid;
class-aware NMS;
原图坐标恢复;
COCO 评测结果格式转换。
7. Raw6 实验结果
在相同的 COCO val2017 前 50 张图片上,Raw6 得到以下结果:
模型阶段 | mAP50-95 | mAP50 |
|---|---|---|
Raw6 Original Float | 0.537 | 0.696 |
Raw6 Optimized Float | 0.537 | 0.696 |
Raw6 INT8 Calibrated | 0.529 | 0.685 |
Raw6 INT8 PTQ | 0.529 | 0.685 |
完整输出模型与 Raw6 模型的对比如下:
模型形式 | 阶段 | mAP50-95 | mAP50 |
|---|---|---|---|
完整输出 [1,84,8400] | Float | 0.537 | 0.696 |
完整输出 [1,84,8400] | INT8 Calibrated | 0.107 | 0.216 |
Raw6 六路输出 | Float | 0.537 | 0.696 |
Raw6 六路输出 | INT8 Calibrated | 0.529 | 0.685 |
8. 实验结果说明
8.1 Raw6 导出和 CPU 后处理正确
Raw6 Original Float 的结果为:
与原完整输出浮点模型完全一致。
这证明以下实现均正确:
六路输出顺序;
DFL channel reshape;
DFL Softmax;
bin 加权求期望;
stride 配置;
- anchor center 使用 x+0.5、y+0.5;
分类 Sigmoid;
class-aware NMS;
LetterBox 坐标恢复;
COCO 类别编号映射;
评测代码接口。
8.2 Horizon 图优化没有影响精度
Raw6 Original Float 与 Optimized Float 完全一致:
因此 Horizon 的普通 ONNX 图优化阶段没有破坏模型计算结果。
8.3 Raw6 INT8 量化损失很小
Raw6 从浮点到 INT8:
该下降幅度较小,属于正常的 INT8 PTQ 精度损失。
8.4 检测头卷积本身不是主要问题
Raw6 模型中仍然被量化的部分包括:
但最终精度只下降 0.008。
因此可以判断:
YOLOv8 的 Detect Head 卷积本身并不是导致精度崩溃的主要原因。
真正的严重掉点发生在原始 box/cls logits 之后,即:
8.5 Raw6 INT8 接近完整输出 INT16
对比:
二者仅相差:
说明通过重新划分模型部署边界,Raw6 INT8 基本达到了完整模型 INT16 的精度,同时保留了大部分卷积算子的 INT8 执行效率。
9. 最终结论
本次精度问题不是由以下因素导致:
ONNX 模型导出错误;
Horizon 图优化错误;
RGB/BGR 配置错误;
输入重复除以 255;
校准数据格式错误;
COCO 标注或类别编号错误;
LetterBox 和 NMS 整体实现错误;
YOLOv8 Detect Head 卷积完全不支持 INT8。
真正的原因是:
标准 YOLOv8 ONNX 将 DFL、Softmax、Sigmoid、anchor point 解码和坐标计算放在模型图内。Horizon J6 对完整检测图执行 INT8 PTQ 时,这些数值敏感操作受到量化误差影响,微小的 logits 误差经过 DFL、距离期望和 stride 解码后被放大,导致边框定位偏移和 IoU 下降,最终造成 mAP50-95 严重下降。
将模型改为 Raw6 六路原始输出,并在 CPU 使用 float32 完成 DFL、Sigmoid、解码和 NMS 后:
因此,Raw6 方案已经验证为当前 Horizon J6 工具链上部署 YOLOv8 INT8 的有效方案。
10. 后续模型导出建议
对于 Horizon J6 上的 YOLOv8 INT8 部署,建议 ONNX 保留:
建议从 ONNX 中移出:
推荐输出形式:
不建议直接使用标准 Ultralytics 最终输出:
但这不是所有硬件平台的统一限制。
在 GPU、TensorRT、FP16、混合精度或对相关算子量化支持较好的平台上,完整输出模型仍然可能正常工作。
该结论仅针对:
这一具体部署环境。
