sherpa-onnx流式语音识别RK3566部署实战指南与RKNN避坑
2026/9/21 6:08:00 网站建设 项目流程

sherpa-onnx流式语音识别RK3566部署实战指南与RKNN避坑

【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx

sherpa-onnx 是一个基于 ONNX Runtime 的离线语音工具链,核心能力包括流式语音识别、文本转语音、VAD 端点检测和说话人分离,支持 12 种编程语言,无需联网即可运行。我们在一块 RK3566 四核开发板(4 核 Cortex-A55 @ 2.0GHz,4GB 内存)上,用它的 RKNN 后端(RKNN 是 Rockchip NPU 的运行时,负责把量化后的模型调度到 NPU 上执行)跑通了 zipformer 流式识别模型,实测 RTF 0.35。这篇文章记录从段错误到跑通的完整排错过程,以及踩过的每一个坑。

段错误先撞上 rknn_run:RK3566 上的第一堵墙

第一次在板子上直接跑流式识别,程序没有任何识别输出就退出了:

./build/bin/sherpa-onnx --provider=rknn ... Segmentation fault (core dumped)

一开始我也以为是板子内存不够——RK3566 只有 4GB LPDDR4,加载模型时 free 里可见内存掉得很凶。但把换行输出重定向后反复试,故障稳定复现,说明不是偶发的内存抖动。用 GDB 挂了调试器,才拿到真正的堆栈:

gdb ./build/bin/sherpa-onnx (gdb) run --provider=rknn --transducer-encoder=encoder.rknn ... test.wav Program received signal SIGSEGV, Segmentation fault. #0 rknn_run (...) from /usr/lib/librknnrt.so (gdb) bt

关键信息是#0落在librknnrt.sorknn_run内部,而不是 sherpa-onnx 自己的代码里。这个结论很重要:崩溃发生在 RKNN 运行时库内部,大概率是运行时版本与模型格式不匹配,sherpa-onnx 侧的逻辑基本可以排除。怎么验证的?把同样的命令换成--provider=cpu用 ONNX 原版模型跑,同一份音频顺利出识别结果——模型本身和参数都没问题,问题锁定在 RKNN 这条路径上。

排错日志:三个 RKNN 版本,只有 2.2.0 能用

为了确认是版本问题,我们把 rknn-toolkit2 的 2.1.0、2.2.0、2.3.2 三个版本在板子上各装了一遍,跑完全相同的模型和命令:

RKNN 运行时版本运行结果具体表现
2.1.0报错退出推理时报 "Meet unsupported input dtype for gather",gather 算子的输入数据类型不被支持
2.2.0正常全程无异常,识别结果与 CPU 后端一致
2.3.2段错误段错误复现,GDB 堆栈同样指向rknn_run内部

结论是必须固定在 2.2.0。2.1.0 的 gather 算子 dtype 校验过严,2.3.2 则退化成段错误,都是运行时库与模型序列化格式之间的底层兼容问题,应用层无法绕过。验证方法就是上表的做法:模型不动、命令不动,只换运行时版本,三组结果一比即知。装的时候注意 2.2.0 需要装配套的 Python 依赖(pip3 install -r requirements.txt后再pip3 install .),少一步都会让工具链行为异常。

编译 sherpa-onnx:一个 CMake 开关和一个环境变量

sherpa-onnx 的 RKNN 适配层是独立编译的:流式/离线模型的 RKNN 推理实现集中在 sherpa-onnx/csrc/rknn/,包含 zipformer 流式 transducer、paraformer 离线模型、silero VAD 等,默认不编进主库。编译开关定义在 sherpa-onnx/csrc/CMakeLists.txt,打开后会把上述源文件加入sherpa-onnx-core并链接rknnrt

在源码根目录执行克隆与配置(板端直接编译,省去交叉工具链):

git clone https://gitcode.com/GitHub_Trending/sh/sherpa-onnx cd sherpa-onnx && mkdir build && cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DSHERPA_ONNX_ENABLE_C_API=ON \ -DSHERPA_ONNX_ENABLE_RKNN=ON \ -DSHERPA_ONNX_RKNN_TOOLKIT2_LIB_DIR=/opt/rknn-toolkit2/lib make -j4

关键配置项:

  • -DSHERPA_ONNX_ENABLE_RKNN=ON:打开 RKNN 后端,这是段错误排查中最容易被漏掉的一项——没开这个开关编译出的二进制,--provider=rknn根本不可用
  • SHERPA_ONNX_RKNN_TOOLKIT2_LIB_DIR:指向板端 rknn-toolkit2 的 lib 目录,CMake 用它定位librknnrt.so,指向错会直接链接失败
  • 可用后端清单在 sherpa-onnx/csrc/provider-config.cc 中注册,cpu, cuda, coreml, trt, rknn, qnn,改 provider 行为先看这个文件
  • 模型扩展名路由在 sherpa-onnx/csrc/online-model-config.cc:配置项里出现.rknn后缀就会走 RKNN 实现,所以 encoder/decoder/joiner 三个文件都要是.rknn

把 zipformer 流式模型转成 .rknn 并跑通

为什么只选流式模型。sherpa-onnx 里流式(online)模型采用分块(chunk-based)架构,encoder 按固定大小的音频块增量计算,内存占用小、首包延迟低;离线(offline)模型需要一次性喂入整段音频的中间张量,在 RK3566 上内存和 NPU 都吃紧,我们实测离线模型在板端无法稳定运行。所以部署到 RK3566,直接锁定 zipformer 流式双语(中英)模型。

模型转换。从 sherpa-onnx 官方模型仓库下载 zipformer-bilingual-zh-en 的 encoder.onnx、decoder.onnx、joiner.onnx 和 tokens.txt,用 rknn-toolkit2 2.2.0 逐一转换(在转换机执行,每个文件跑一遍):

from rknn.api import RKNN rknn = RKNN() rknn.load_onnx(model='encoder.onnx') rknn.config(target_platform='rk3566') rknn.build(do_quantization=True, dataset='dataset.txt') rknn.export_rknn('encoder.rknn')
  • do_quantization=True开启 INT8 量化,这是上 NPU 加速的前提,量化数据集用几百段普通语音的 wav 列表即可
  • target_platform必须写成rk3566,写rk3588等其它平台导出的模型在 3566 上会直接加载失败

板端运行命令。转换得到的三个.rknn文件与 tokens.txt 拷到板子,执行:

./build/bin/sherpa-onnx \ --provider=rknn \ --transducer-encoder=encoder.rknn \ --transducer-decoder=decoder.rknn \ --transducer-joiner=joiner.rknn \ --tokens=tokens.txt \ --num-threads=4 \ test.wav
  • --provider=rknn:让推理走 NPU 后端而不是 CPU
  • --num-threads=4:与 RK3566 的 4 个 A55 核数对齐,前处理/后处理线程超过核数只会增加上下文切换开销
  • --chunk-size不用显式传,zipformer 流式模型按内置 chunk 配置增量解码

效果验证:RTF 0.35 在 RK3566 上意味着什么

用一段 10 秒的中文 wav 实测,数据如下(同一块板、RKNN 2.2.0、INT8 量化模型):

指标数值说明
模型加载时间约 1.2 秒三个 .rknn 文件加载进 NPU 内存
持续识别延迟约 0.15 秒流式模式下单块音频的处理耗时
实时因子 RTF0.35处理 1 秒音频耗时 0.35 秒,小于 1 即满足实时
峰值内存约 180MB/proc/self/status 里 VmHWM 峰值
CPU 利用率约 75%4 核均值,NPU 分担主推理

RTF 0.35 的实际含义:RK3566 处理语音的速度是实时语速的约 3 倍,边说边识别有充足余量,即使 NPU 与 CPU 抢占也大概率不掉帧。验证方法很简单:time包住整段推理,用 Elapsed 除以音频时长即为 RTF。

作为对照,sherpa-onnx 的 Web 演示端(Python 包自带)在桌面端跑同一框架的界面如下,上传文件或实时录音都能出识别结果,板端跑通的正是同一套 C++ 内核:

同一套内核的跨平台表现也顺带验证了:官方 Flutter 示例的 TTS 应用直接在 Ubuntu 和 macOS 上跑,macOS 端的合成日志里能看到 RTF 0.305 这类逐次输出,说明框架在多平台上行为一致,RK3566 上跑通后迁移到别的平台成本很低。

如果你也卡在 RK3566 上:优先查这 3 点

折腾了两天最大的体会是:RK3566 上的部署问题 90% 出在运行时链路,而不是模型本身。如果你复现时卡住,按顺序查:

  1. RKNN 运行时是不是 2.2.0。2.1.0 报 "Meet unsupported input dtype for gather",2.3.2 直接段错误且堆栈指向rknn_run——看到这两种现象先查版本,不要在模型上花时间。
  2. 模型是不是流式 + 三个 .rknn 齐全。离线模型在 3566 上跑不稳;transducer 三件套(encoder/decoder/joiner)任何一个还是 .onnx,配置路由就会退回或不匹配,识别结果异常且难排查。
  3. 编译开关和环境变量是否生效。改过SHERPA_ONNX_RKNN_TOOLKIT2_LIB_DIR后必须删掉 CMakeCache.txt 重跑 cmake,否则新值不会进入链接行;用ldd build/bin/sherpa-onnx | grep rknnrt确认动态库解析到的是 2.2.0 的 librknnrt.so,而不是系统里残留的旧版本。

最后留一个隔离手段:怀疑模型或参数问题时,先用--provider=cpu加原版 .onnx 模型跑一遍,跑通再切 RKNN——这一步能立刻把"模型问题"和"运行时问题"切开,比翻日志快得多。

【免费下载链接】sherpa-onnxSpeech-to-text, text-to-speech, speaker diarization, speech enhancement, source separation, and VAD using next-gen Kaldi with onnxruntime without Internet connection. Support embedded systems, Android, iOS, HarmonyOS, Raspberry Pi, RISC-V, RK NPU, Axera NPU, Ascend NPU, x86_64 servers, websocket server/client, support 12 programming languages项目地址: https://gitcode.com/GitHub_Trending/sh/sherpa-onnx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询