第五章:嵌入式平台 (RV1126B) 流式 ASR 模型 (Zipformer) INT8 端到端量化与部署

[项目复盘报告 V5.0] 嵌入式平台 (RV1126B) 流式 ASR 模型 (Zipformer) INT8 端到端量化与部署

项目属性内容
项目名称第五部分:RV1126BP平台 Sherpa ASR RKNN量化
项目周期2025-08-21 ~ 2025-09-23
项目用时40(约5人天)
复盘日期2025-09-27
核心人员Potter White

1. 项目目标 (Project Objective)

为基于 Rockchip RV1126B SoC 的嵌入式设备,将一个 FP32 精度的流式 Zipformer ASR (Automatic Speech Recognition) ONNX 模型,转换为 INT8 精度的 RKNN 模型,并在 sherpa-onnx C++ 推理框架中完成部署与验证,以满足低延迟和低功耗的运行要求。

2. 执行方法与流程 (Methodology & Workflow)

本项目采用了一套系统性的方法,覆盖从模型分析、运行时环境改造、量化数据生成到最终模型验证的全过程。

graph TD
    classDef main fill:#2c3e50,color:white,stroke:#8e9eab;
    classDef task fill:#4b3e58,color:white,stroke:#b8a3d3;
    classDef check fill:#27ae60,color:white,stroke:#88d1a1;
    classDef fail fill:#c0392b,color:white,stroke:#e69a93;
    classDef success fill:#16a085,color:white,stroke:#72d6c1;
    classDef note fill:#f39c12,color:white,stroke:#f8c471;

    S[<b>开始: FP32 ONNX 模型</b>]:::main
    A["<div style='text-align:left; padding:10px;'><b>1. 初始模型分析与转换</b><br>- 使用预量化的 INT8 ONNX 模型进行直接转换</div>"]:::task

    %% --- THIS IS THE MISSING LINE THAT FIXES THE CONNECTION ---
    S --> A

    A --> R1{"<div style='text-align:center'>转换是否成功?</div>"}:::check
    R1 -- "否: 存在 `DynamicQuantizeLinear` 算子" --> B

    B["<div style='text-align:left; padding:10px;'><b>2. C++ 运行时适配</b><br>- 分析 `sherpa-onnx` RKNN 后端代码<br>- 增加对 `RKNN_TENSOR_INT8` 类型的处理分支<br>- 实现 INT8 输出到 FP32 的手动反量化逻辑</div>"]:::task
    B --> C

    C["<div style='text-align:left; padding:10px;'><b>3. 校准数据集迭代</b><br><b>3.1 (快照法):</b> 提取特征帧, 状态张量补零<br><b>3.2 (流式模拟):</b> 使用 `onnxruntime` 模拟流式推理, 捕获真实的非零状态张量</div>"]:::task
    C --> R2{"<div style='text-align:center'>INT8 模型推理结果?</div>"}:::check

    R2 -- "3.1 -> Garbled Output" --> C
    R2 -- "3.2 (`interval=1`) -> <b>First Success</b>" --> D

    D["<div style='text-align:left; padding:10px;'><b>4. 量化策略调优</b><br>- <b>算法:</b> 测试 `normal` (默认) 与 `kl_divergence` 算法<br>- <b>混合精度:</b> 尝试手动及自动混合量化</div>"]:::task
    D --> E

    E["<div style='text-align:left; padding:10px;'><b>5. 最终方案验证</b><br>- 对比不同策略下的模型精度与性能 (RTF)</div>"]:::task
    E --> F[<b>完成: 产出可部署的 INT8 RKNN 模型</b>]:::success

    subgraph "关键技术点"
      K1[静态图 vs. 动态图]:::note
      K2[有状态模型的校准]:::note
      K3[量化算法内存分析]:::note
      K4[混合精度量化]:::note
    end

    A --> K1
    C --> K2
    D --> K3 & K4

3. 工程实施细节与关键问题记录 (Implementation & Key Findings)

3.1 初始模型转换

  • 执行动作: 尝试使用 rknn-toolkit2 直接转换模型提供方发布的 int8.onnx 模型。
  • 观察结果: 转换失败。工具链报错,指出模型中包含 DynamicQuantizeLinear 算子,该算子与 RKNN NPU 的静态图 (Static Graph) 计算模式不兼容。
  • 采取措施: 确定了必须使用 FP32 ONNX 模型作为输入源,并利用 rknn-toolkit2 自身的静态量化 (Static Quantization) 功能进行转换。

3.2 C++ 推理框架 (sherpa-onnx) 适配

  • 执行动作: 在使用 FP32 模型成功转换为 INT8 RKNN 模型后,在 sherpa-onnx 中进行推理。
  • 观察结果: 运行时报错,提示 Unsupported tensor type: 2, INT8
  • 采取措施:
    1. 修改了 sherpa-onnx 的 RKNN 后端 C++ 源码,在模型输入、输出及状态 (states) 处理逻辑中,增加了对 RKNN_TENSOR_INT8 数据类型的分支处理。
    2. 在获取模型输出后,根据 rknn_tensor_attr 中的 scalezp (zero_point) 参数,实现了手动的反量化 (Dequantization) 步骤,将 INT8 输出转换为后续解码逻辑所需的 FP32 数据。

3.3 量化校准数据集的迭代与优化

此阶段是项目核心,通过多次迭代确定了有效的校准数据生成方案。

  • 迭代 1: 快照式数据集 (Snapshot Dataset)

    • 方法: 从音频中提取多个特征帧 (x) 作为校准样本,所有状态输入 (cached_* tensors) 均使用全零张量填充。
    • 结果: 生成的 INT8 模型在推理时输出乱码或静默。
  • 迭代 2: 精确特征提取 + 快照式数据集

    • 方法: 深入分析 sherpa-onnx 的 C++ 源码 (features.h),在 Python 数据生成脚本中精确复现了其音频预处理流程,包括去直流偏置 (Remove DC Offset) 和预加重 (Pre-emphasis)。状态输入仍使用全零张量。
    • 结果: 推理结果没有改善,证明状态张量的真实性是更关键的因素。
  • 迭代 3: 模拟流式数据集 (Simulated Streaming Dataset)

    • 方法: 编写 Python 脚本,使用 onnxruntime 完整模拟 sherpa-onnx 的流式推理过程。在每个时间步 (time step),将真实的特征帧 (x) 和由上一步 onnxruntime 计算出的真实非零状态 (cached_*) 作为一组完整的校准样本保存下来。
    • 结果:
      • 使用此方法生成的完整数据集 (sampling_interval=1) 进行量化后,模型首次成功输出完整、可读的识别结果,RTF (Real-Time Factor, 实时率) 约为 0.29。
      • 数据集体积巨大 (超过 100GB),导致转换时间长达数小时。

3.4 量化策略的进一步探索

基于第 3.3 节成功的 interval=1 数据集,进行了以下策略调优:

  • 量化算法:

    • normal (默认): 成功生成模型,结果如 3.3 所述。
    • kl_divergence: 在转换过程中,因内存消耗过大导致系统内存溢出 (Out of Memory, OOM) 而失败。分析表明,该算法需要一次性加载大量样本进行统计计算,与大规模数据集不兼容。
  • 数据采样方法:

    • 系统采样 (sampling_interval > 1) / 随机采样: 尝试通过采样减少数据集体积,以配合 kl_divergence 算法。
    • 结果: 虽然转换可以成功,但生成的模型推理结果重新变为乱码。这表明 Zipformer 模型对校准数据中状态的时间连续性 (Temporal Continuity) 高度敏感。
  • 混合精度量化 (Mixed-Precision Quantization):

    • 方法: 尝试使用 rknn-toolkit2 的手动及自动混合量化功能,将 Softmax 等对精度敏感的算子保留为 FP16
    • 结果: 手动混合未能显著改善精度,并引入了新的识别错误。自动混合生成的模型在运行时报错或输出乱码。

4. 项目成果与结论 (Results & Conclusion)

  • 最终交付成果:

    1. 一个可在 RV1126B 平台上稳定运行的 INT8 RKNN ASR 模型,RTF 达到 0.29,实现了从 FP32INT8 的成功部署。
    2. 一套经过验证的、针对流式有状态 (stateful) 模型的校准数据集生成脚本 (09_generate_calibration_dataset.py),该脚本通过模拟流式推理来保证状态张量的真实性和连续性。
  • 工程结论:

    1. 对于此 Zipformer 模型,校准数据的状态真实性与时间连续性是量化成功的决定性因素,其重要性高于特征提取的微小差异。
    2. rknn-toolkit2kl_divergence 等统计型量化算法,在处理大规模、高维度的连续数据集时存在内存限制。
    3. 在当前工具链和模型架构下,使用完整的流式模拟数据集配合 normal 量化算法,是在各项约束(精度、性能、转换可行性)之间取得的最佳工程方案。