摘要: 模型在 GPU 上精度正常,到了 J6 做 INT8 量化却开始掉点,很多人的第一反应是换校准数据、调量化参数,甚至直接上 QAT。但实际工程中,问题可能早在 ONNX、图优化、量化转换或编译部署阶段就已经出现。本文结合 J6 工具链,把 PyTorch 模型到 J6 HBM 的精度变化明确拆成 4 段,通过逐阶段验证定位第一处误差,再决定到底该修模型、调 PTQ,还是进入 QAT。
1. PTQ 掉点了,真的是 PTQ 的锅吗?
最近在整理 J6 模型量化和部署流程时,又遇到了一个端侧部署中非常典型的现象:
看到这里,最自然的反应通常是继续修改 Calibration,或者干脆进入 QAT。但现在我越来越不喜欢这么快做决定,因为模型从训练环境到真正运行在 J6 上,中间远不止一次“FP32 → INT8”。
J6 工具链本身就把模型检查、性能验证、精度配置、量化、编译和部署拆成了多个阶段。官方 PTQ 深度使用指南也推荐先确认模型结构和平台支持情况,再逐渐进入性能和精度调优,而不是拿到 ONNX 就直接把所有问题交给量化解决。

图 1:J6 PTQ 推荐使用流程。图中模型检查、性能上限验证、配置生成和精度调优本身就是多个独立检查点。图片来源:地平线开发者社区。
所以现在碰到掉点,我会先把问题拆成四段:
阶段 | 核心问题 |
|---|---|
第一段:PyTorch → ONNX | 模型还没进入 J6 工具链之前是否已经产生偏差 |
第二段:ONNX → Optimized Float | 图优化或模型转换是否改变浮点模型行为 |
第三段:Float → INT8 | 真正的量化误差究竟在哪里 |
第四段:Quantized BC → HBM → J6 | 编译、输入和板端运行是否保持一致 |
这也是整篇文章唯一需要记住的原则。
第一段:PyTorch → ONNX
还没进入 J6,误差可能已经出现了
这一段其实和 J6 本身没有直接关系,却是我现在最不愿意跳过的一步。
训练模型导出:
然后执行一次:
模型能跑、Shape 对、结果看着也正常,于是默认:
ONNX 没问题。
实际上,“ONNX 能执行”和“ONNX 与 PyTorch 一致”完全是两个概念。
真实项目里最容易出现的问题往往也并不复杂,例如:
程序完全正常,模型也有输出,但结果已经悄悄变了。
例如最简单的输出检查:
单张图片主要用于 Debug,真正判断模型有没有发生变化,还是要重新计算 Accuracy、Precision、Recall、mAP 等完整指标。
检测模型还有一个额外的坑
检测模型比分类模型更容易把这种差异藏起来。
假设:
检测阈值:
两个模型最终都会画出这个框。
肉眼看:
但数值实际上已经开始发生变化。
如果后面的 INT8 再产生一点误差:
最终立刻变成:
模型 | 最终结果 |
|---|---|
PyTorch | TP |
ONNX | TP |
INT8 | FN |
最后看到的是:
INT8 漏检。
但真正的问题并不是从 INT8 才突然发生。
所以第一段的结论很简单:
PyTorch 和 ONNX 没对齐之前,不要急着讨论 PTQ。
第二段:ONNX → Optimized Float
“只是图优化”也应该验证一次
如果 PyTorch 和 ONNX 已经基本一致,下一步才进入 J6 工具链。
这一阶段我以前比较容易忽略:
因为直觉上会认为:
图优化都是等价变换,不应该影响结果。
大多数时候确实如此。
但工程上我越来越喜欢区分两个概念:
“理论上应该一样”
和:
“实际验证过一样”
J6 PTQ 转换过程中会产生不同阶段的模型产物,例如原始浮点模型、优化后的浮点模型以及后续量化模型。这恰好给了我们逐级验证的机会。
如果出现:
那就暂时不用继续研究 Calibration。
因为此时:
都还不是第一嫌疑人。

图 2:J6 QAT/定点链路中,不同阶段模型本身就是一致性定位的重要依据。图片来源:地平线开发者社区。
虽然这张图来自 QAT 一致性教程,但它体现的排错方法同样适用于 PTQ:
不要只检查:
而应该找到:
这会让问题空间小很多。
第三段:Float → INT8
到这里,才真正轮到“量化问题”
前两段确认正常以后,现在终于可以比较:
如果明显掉点发生在这里,那么“PTQ 精度问题”这个判断才真正成立。
这时候我通常不会先问:
Calibration 再加多少张图?
而是先看三个方向。
3.1 Calibration 数据有没有代表性
校准集最大的价值不是“数量足够多”,而是能不能覆盖真实输入分布。
如果模型实际运行场景和校准数据差异很大,那么量化得到的 Activation Range 本身就可能不合理。
所以:
不一定天然优于:
3.2 Activation Range 有没有被异常值拉开
假设某层绝大部分激活都集中在:
但极少量数据跑到了:
量化范围被扩大以后,有限的 INT8 表示区间需要覆盖更宽的数值范围,正常数据区域的量化精度自然会受到影响。
这也是实际项目中比较值得观察数据分布的原因。
3.3 是整个网络敏感,还是只有几个节点敏感?
这一点尤其重要。
如果模型大部分节点量化都很稳定,只有少数节点出现明显误差,那么它已经从:
“这个模型不适合 INT8”
变成了:
“这几个节点需要处理。”
J6 QAT 调优指南同样非常强调敏感度分析和混合精度,而不是全局简单地从 INT8 切换到高精度。J6E/M 主要采用 INT8+INT16 混合精度思路,而 J6P/H 可以进一步利用 FP16 等配置处理难量化结构。

图 3:J6E/M QAT 精度调优思路中,会分别从 Float、Calibration、QAT 等阶段继续缩小量化问题范围,而不是直接把整个模型切到更高精度。图片来源:地平线开发者社区。
官方 PTQ Debug 工具的设计也很类似:通过量化误差、敏感度和数据分布继续判断问题来自 Weight 还是 Activation,并进一步决定是否使用高精度、调整网络或进入 QAT。J5→J6 迁移指南也明确说明,J6 与 J5 的 PTQ 精度 Debug 推荐思路保持一致。

图 4:PTQ 精度 Debug 的定位流程。真正有价值的并不是“模型掉了多少点”,而是继续判断误差来源及敏感节点。图片来源:地平线开发者社区。
到这里,如果确定:
那么才值得认真讨论:
第四段:Quantized BC → HBM → J6
模型没坏,也可能“部署坏了”
第四段是我觉得特别容易被忽略的一段。
假设:
这时候如果继续回去调整 QAT,很可能又找错方向。
其中非常实用的一个工具就是:

这一阶段如果模型本身已经对齐,排查重点就应该转向:
而不是:
也就是说:
板端精度异常,不一定意味着模型量化异常。
这是第四段最重要的结论。
5. 四段全部检查完,什么时候才值得上 QAT?
经过前面四段以后,QAT 的位置其实已经很清楚了。
当前状态 | 是否优先进入 QAT |
|---|---|
PTQ 已达到业务精度 | 没必要 |
PyTorch → ONNX 已经掉点 | 否 |
Optimized Float 出现明显偏差 | 否 |
BC / HBM 一致性异常 | 否 |
板端输入或后处理不一致 | 否 |
Float → INT8 存在明确量化损失 | 可以 |
Calibration 调优后仍明显掉点 | 可以 |
少数量化敏感节点影响整体精度 | 更值得尝试 |
J6 官方 QAT 调优本身也不是“打开 QAT 再训练几轮”这么简单。针对不同 J6 平台,需要根据硬件能力选择 INT8、INT16、FP16 等混合精度策略,并通过模型检查、Calibration、敏感度和 Debug 工具不断缩小问题。
所以我现在更愿意把 QAT 定义成:
确认模型确实不适应当前量化误差以后,再让模型通过训练主动适应这种误差。
而不是:
6. 最终目标:把“四段排查”变成自动回归
如果只部署一个模型,人工检查四段问题还可以接受。
但真实项目往往是:
模型每迭代一次,都重新手动检查 PyTorch、ONNX、BC、HBM,很快就会变成重复工作。
所以我更希望最后把这套流程固定下来:
最终先看一个简单的结果:
Check | Result |
|---|---|
PyTorch Baseline | PASS |
PyTorch ↔ ONNX | PASS |
ONNX ↔ Optimized Float | PASS |
Float ↔ INT8 | FAIL |
BC ↔ HBM | - |
J6 Regression | - |
这样看到的第一件事情就是:
第三段 FAIL。
而不是打开几十个 Log,再凭经验猜到底哪里出了问题。
7. 最近一个月的一个趋势:工具链开始从“量化模型”走向“诊断模型”
最近一个月看其他 AI 工具链时,这个趋势也越来越明显。
9 月 8 日,Ultralytics v8.4.143 给 YOLO26 加入了 INT8 QAT 支持,开发者可以直接在训练中模拟 INT8 量化误差。
AMD 最近则更进一步,在 Quark 量化工具中引入了 AI Agent Skills,可以从模型检查、量化方案选择、Calibration 到结果验证和 Debug 逐步组织量化工作流。
这让我觉得模型部署工具正在从过去的:
逐渐走向:
模型转换成功只是第一步,快速知道它为什么不对,才是真正提高工程效率的地方。
8. 写在最后
现在再遇到 PTQ 掉点,我不会第一时间问:
“QAT 怎么调?”
而会先把整个过程拆成四段:
然后只做一件事情:
找到第一处明显发生变化的位置。
第一段错了,就查导出和前后处理;第二段错了,就查 Float 图转换;第三段错了,才真正研究 Calibration、敏感层和 QAT;第四段错了,则重点检查 compile、输入格式和板端 Runtime。
把问题这样拆开以后,很多原本看起来很玄学的“量化掉点”,其实都会变成一个范围非常有限的工程问题。
模型部署最怕的不是掉点,而是把所有掉点都叫作量化误差。
参考资料
地平线 J6 相关流程和工具使用参考官方《PTQ 深度使用指南》《J6 平台 QAT 精度一致性问题分析流程》《J5 到 J6 算法部署迁移指南》《J6E/M、J6P/H QAT 精度调优》等资料;不同 OpenExplorer 版本的工具接口和默认策略可能继续变化,实际工程使用应以当前版本官方文档为准。

