1. 实验环境与结果
实验使用的主要环境如下:
项目 | 配置 |
|---|---|
开发板 | Horizon Robotics J6E MatrixB |
BPU 架构 | nash-e |
BPU 核心 | Core 0 |
开发环境 | OpenExplorer 3.8.1 GPU Docker |
PyTorch | 2.8.0+cu128 |
horizon-plugin-pytorch | 3.2.4 |
HBDK4 Compiler | 4.9.7 |
部署方式 | x86 端通过 hbm_infer 调用板端 BPU |
各阶段精度如下:
阶段 | Top-1 | 精度变化 |
|---|---|---|
Float PyTorch | 84.40% | 基线 |
Calibration | 84.26% | -0.14pp |
QAT PyTorch | 86.03% | 相对 Float +1.63pp |
QAT BC | 85.91% | 相对 QAT -0.12pp |
Quantized BC | 85.89% | -0.02pp |
J6E HBM | 85.89% | 相对 Quantized BC 0.00pp |
延时测试使用固定输入,预热 100 帧后正式测量 1,000 帧:
指标 | Mean | P50 | P95 | P99 |
|---|---|---|---|---|
x86 UCP 端到端 | 2.133 ms | 2.135 ms | 2.320 ms | 2.503 ms |
gRPC 发送到接收 | 1.765 ms | 1.762 ms | 1.928 ms | 2.130 ms |
板端总处理 | 0.633 ms | 0.616 ms | 0.762 ms | 0.947 ms |
BPU 纯推理 | 0.445 ms | 0.430 ms | 0.491 ms | 0.740 ms |
2. 整体流程
本次实践的主线如下:
3. 数据预处理必须保持一致
本次使用 CIFAR-10 数据集:
训练集 50,000 张
测试集 10,000 张
- 图像尺寸为 32×32
共 10 个类别
模型使用的输入预处理为:
对应的数据变化是:
训练、BC 验证和实板验证必须执行完全相同的预处理。预处理不一致时,模型通常仍能正常运行,但输出精度会明显异常。
这类问题很容易被误判为量化误差或板端计算误差,因此应在部署前固定预处理流程,并在每个验证阶段复用同一份实现。
4. 模型的 QAT 适配
实验模型选择 MobileNetV2。它规模适中,同时包含普通卷积、深度可分离卷积和残差连接,适合作为 QAT 入门模型。
4.1 设置目标架构
march 必须与目标板卡的 BPU 架构一致。
4.2 添加量化边界
4.3 处理 ReLU6 兼容性
5. QConfig、Template 和 prepare
在 Horizon QAT 流程中,可以这样理解三个概念:
QConfig 决定 Observer 类型、数据类型、量化粒度和对称方式。例如:
Template 则负责按模块名或输入输出位置匹配量化配置。本次实验使用全局双 INT8 配置,没有加入 INT16 或 FP16 混合精度策略。
根据 Template 计算各位置的最终 QConfig。
将浮点模块替换为 QAT 兼容模块。
插入 Observer 和 FakeQuantize 节点。
检查量化边界、模块执行次数和异常配置。
生成能够在校准、QAT 和验证状态之间切换的模型。
常见状态包括:
- CALIBRATION:收集激活统计信息。
- QAT:训练过程中启用 FakeQuant。
- VALIDATION:冻结统计信息并验证当前量化精度。
- FLOAT:关闭 FakeQuant,用于浮点行为检查。
执行后应检查 QConfig 变更日志和模型检查报告,确认没有异常配置或非预期量化边界。
6. 浮点训练、校准与 QAT
6.1 浮点模型
浮点模型使用 Adam 训练 100 个 epoch:
最终 Top-1 为:
QAT 不应替代正常的浮点训练。更稳妥的做法是先得到精度可用的浮点模型,再使用更小的学习率进行量化微调。
6.2 校准
结果如下:
校准阶段不通过梯度更新模型权重,主要作用是收集激活分布并确定量化范围。0.14 个百分点的下降处于可接受范围内,说明当前 INT8 配置可以继续进入 QAT。
6.3 QAT 微调
最终结果:
QAT 精度高于浮点基线不代表量化天然能够提升模型精度。本次浮点模型在第 100 个 epoch 仍然取得最佳结果,说明训练尚未完全进入平台期。QAT 又增加了 20 个 epoch,同时改变了优化器和训练噪声,因此精度提升更可能来自额外微调和 FakeQuant 带来的正则化效果。
7. 从 QAT 模型导出 BC
QAT 模型导出后得到:
导出过程中曾遇到一个值得记录的问题:文件保存成功后,进程在退出阶段出现原生库段错误。
仅凭这条日志无法判断 BC 是否损坏。随后我在一个全新的进程中重新加载 BC,并检查函数数量和输入输出签名:
函数签名为:
因此该 BC 可以继续使用。
这里的经验是:产物已经生成,不等于产物一定有效;进程异常退出,也不等于产物一定损坏。更可靠的方法是在独立进程中重新加载产物并执行结构检查。
8. Quantized BC 与整数 IO
转换带来的精度变化很小。
9. 编译 HBM
编译结果:
生成的 HBM 为:
编译完成后,建议保存 HBM 的文件大小和 SHA256。这样可以确认实板测试使用的模型是否与编译产物一致。
10. 通过 hbm_infer 部署到 J6E
通过 SSH 连接开发板。
部署 HBM、板端服务和运行库。
启动推理服务。
通过 gRPC 发送输入并接收结果。
关闭服务并清理临时文件。
HBM 不需要提前手工复制到开发板。
临时目录不要放在 NFS 上
将临时目录改到板端本地文件系统后,问题消失:
11. 整数输入输出的量化处理
从 HBM 中读取到的输入信息如下:
应用侧需要按照模型的量化参数将浮点输入转换为 INT8:
输出信息如下:
10 个类别分别使用独立的 scale,因此输出需要逐通道反量化:
12. 实板精度验证
正式评测前,可以先用少量样本检查整个链路:
小样本结果只用于确认预处理、输入量化、推理和输出解析是否正常。
在 CIFAR-10 的 10,000 张测试图像上,最终结果为:
HBM 与 Quantized BC 的精度完全一致,说明以下环节在 x86 和实板之间保持一致:
图像预处理
INT8 输入量化
HBM 计算
INT32 输出反量化
Top-1 计算
13. 独立测试推理延时
完整精度测试包含数据读取、图像预处理和输入量化。延时测试使用一份提前完成预处理和量化的固定输入:
测试时需要区分几种延时:
- host_call:x86 Python 调用一次 session(...) 的总耗时。
- sd2rv_duration:请求经 gRPC 发出到响应返回的耗时。
- board_duration:板端预处理、推理和后处理总耗时。
- infer_duration:BPU 纯推理耗时。
