Zipformer ONNX 流式推理避坑指南
【免费下载链接】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 在本地跑流式识别时,如果你跳过上层封装、直接对 Zipformer ONNX 模型做 ONNX 推理,多半会先撞上这样一行:Required inputs missing。别慌,模型文件没坏——你只是漏传了一整组缓存输入。修好之后你会发现,这套"特征 + 缓存"的喂法其实非常固定。
⚡ 先说结论:报错不是 bug,是输入不全
Required inputs missing几乎都发生在同一个场景:调用session.Run时只传了特征张量x。Zipformer 流式 encoder 的完整输入清单是x加上每个 encoder 层的 7 组cached_*张量,少传任何一组,onnxruntime 都会直接拒收。换句话说,x只是入口之一。
类比:缓存状态是"上一段音频留给模型的记忆"
流式识别像人做速记:听到新句子时,大脑不会把前面的内容重新听一遍,而是接着"刚才听到哪儿"继续往下记。Zipformer 同理——cached_key、cached_val存着注意力已经算过的内容,cached_avg、cached_len记录均值与长度统计,cached_conv1、cached_conv2留着卷积模块的尾巴。这份"记忆"让模型收到新音频块时无需重算历史。你可以把它理解成模型的滚动工作区,每轮结束都要整体刷新。
输入张量对照表
以 batch=1 为例,流式 encoder 各输入及取值差异如下:
| 输入张量 | 形状 | 首次推理 | 后续推理 |
|---|---|---|---|
| x | [1, T, 80] | 当前块的 Mel 特征 | 新一块的特征 |
| cached_len(每层一个) | [1, 1] | 0 | 上一轮的对应输出 |
| cached_avg(每层一个) | [1, 1, D] | 全 0 | 上一轮的对应输出 |
| cached_key(每层一个) | [1, L, 1, D_attn] | 全 0 | 上一轮的对应输出 |
| cached_val / cached_val2(每层各一) | [1, L, 1, D_attn/2] | 全 0 | 上一轮的对应输出 |
| cached_conv1 / cached_conv2(每层各一) | [1, 1, D, K-1] | 全 0 | 上一轮的对应输出 |
其中 D 是 encoder 层维度,L 是左上下文长度,K 是卷积模块核宽,全部能从模型 metadata 里读到,不用背。
🔄 流式推理缓存传递:四步走
- 清零记忆:开局按上表形状给所有
cached_*造全零张量,这就是模型的初始记忆。 - 喂入特征:把当前块的 Mel 特征传给
x,连同各组缓存一起Run。 - 取走新记忆:输出第 0 项是编码结果,其余各项与缓存输入严格一一对应,直接收下作为下一轮输入。
- 滚动循环:新记忆进缓存槽,下一块音频进来重复第 2、3 步,直到整段音频说完。
🚧 高频翻车点
- 输出顺序别手排:除第 0 项外的输出和缓存输入严格一一对应,手动乱序拼接会在下一轮直接炸形状。
- 缓存不更新或跨流复用:一直拿旧缓存算,结果会越推越漂;拿 A 音频流的缓存去算 B 音频,从第一句就错。
- 形状靠猜:层数、D_attn、K 以模型 metadata 为准,先读 metadata 再建零张量,80 维特征来自 fbank 默认配置,别手改。
性能与工程化,点到为止
实时采集时,让音频块大小和特征提取窗口对齐,凑够定长帧就推一轮,避免半帧空转;cached_*体积不大,全程留在内存里即可,没必要落盘;encoder、decoder、joiner 三个 session 相互独立,多路音频各建一套模型实例,避免跨流干扰。
下一步:从 Python API 走向 C++ 源码
先用python-api-examples/下的在线解码示例把整条链路跑通,确认音频与模型配置没问题;想深挖时,直接读 online-zipformer-transducer-model.cc:GetEncoderInitStates就是"清零记忆"的参考实现,RunEncoder则是"喂特征 + 取新记忆"的完整写法。读源码时对照本文的输入张量对照表逐项核对形状,理解会快很多。
【免费下载链接】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),仅供参考