☰
rknn_model_zoo 中的 Whisper ONNX 模型导出指南:从 20 秒/30 秒输入长度定制到 RKNN 部署
2026/10/4 1:54:23 网站建设 项目流程
  • 示例工程
  • 人工智能
  • 嵌入式
  • 边缘计算
  • 计算机视觉
  • 模型优化

【免费下载链接】rknn_model_zoo

项目地址:https://gitcode.com/gh_mirrors/rk/rknn_model_zoo
点击查看免费下载

本文是 rknn_model_zoo 仓库中 examples/whisper/export_onnx.md 的完整技术指南,系统讲解如何在 RKNN 开发流程中导出 OpenAI Whisper 语音识别模型的 ONNX 权重:既包括将默认 30 秒输入长度改为 20 秒的关键源码修改,也包括保持原始 30 秒长度的标准导出流程,以及导出后 Python/C++ 两套 Demo 中必须同步修改的参数。读完本文,你可以独立完成 whispertiny/base/medium三种模型 encoder/decoder 的 ONNX 导出、onnxsim 精简与后续 RKNN 转换部署。

一、为什么需要单独导出 Whisper 的 ONNX 模型

Whisper 是 OpenAI 开源的通用语音识别模型,支持多语种语音识别、语音翻译与语种识别。在 rknn_model_zoo 的 Whisper 示例 中,整个识别流程被拆分为两个可独立推理的 ONNX 模型:

  • encoder(编码器):将音频的 log-mel 频谱特征编码为语义向量,导出脚本中其输入名为x,输出名为out;
  • decoder(解码器):接收 token 序列与 encoder 输出向量,自回归地生成识别文本,导出脚本中其输入名为tokens与audio,输出名为out。

导出工具位于 examples/whisper/python/export_onnx.py,其核心逻辑是加载 OpenAI 官方 whisper 权重后,分别对model.encoder与model.decoder调用torch.onnx.export,并统一采用opset_version=12,最后用onnxsim对两个模型做常量折叠与图精简,确保导出的 ONNX 更干净、更适合后续 RKNN 工具链解析。

需要特别说明的是:仓库官方脚本当前仅支持tiny、base、medium三种模型规格,small与large暂不支持,这是导出前需要确认的前提。

二、环境准备:安装指定版本的 openai-whisper

导出脚本依赖 OpenAI 官方 Python 包,仓库固定使用 2023-11-17 版本:

pip install openai-whisper==20231117

安装后,whisper 的源码会落在 site-packages 中(例如~/python3.8/site-packages/whisper/),后续对audio.py与model.py的修改都在这个安装路径下进行。导出的 ONNX 模型默认保存到examples/whisper/model/目录,命名规则为whisper_encoder_{MODEL_TYPE}.onnx与whisper_decoder_{MODEL_TYPE}.onnx。

三、导出 20 秒输入长度的 ONNX 模型

默认的 whisper 模型按 30 秒音频输入设计(CHUNK_LENGTH = 30),而本示例的 RKNN Demo 默认按 20 秒处理,因此需要先修改官方源码,再执行导出脚本。

3.1 修改官方源码

第一步:修改whisper/audio.py中的CHUNK_LENGTH

在安装包路径(如~/python3.8/site-packages/whisper/audio.py)中找到音频分块长度定义:

CHUNK_LENGTH = 30 # 修改为: CHUNK_LENGTH = 20

该常量决定了 log-mel 频谱的输入长度,是模型输入尺寸的根基,导出时生成数据、后续 Demo 的前处理都必须与它保持一致。

第二步:修改whisper/model.py中的位置编码逻辑

model.py中原本对输入形状与位置编码形状做严格断言,并把整张位置编码加到x上。改为 20 秒后输入序列变短,需要放宽断言并改用切片索引:

assert x.shape[1:] == self.positional_embedding.shape, "incorrect audio shape" # 注释掉上面的断言,改为: # assert x.shape[1:] == self.positional_embedding.shape, "incorrect audio shape" x = (x + self.positional_embedding).to(x.dtype) # 改为: x = (x + self.positional_embedding[-x.shape[1]:, :]).to(x.dtype)

self.positional_embedding[-x.shape[1]:, :]表示按当前输入的实际序列长度截取位置编码的后半段,从而兼容任意短于完整长度的输入序列。

3.2 执行导出命令

cd python python export_onnx.py --model_type <MODEL_TYPE> --n_mels <N_MELS(optional)> # 例如: python export_onnx.py --model_type base --n_mels 80

参数说明:

参数必填含义取值范围 / 默认值
--model_type是指定模型规格tiny、base、medium(small/large暂不支持)
--n_mels否指定梅尔滤波器数量如80、128,默认80

从 export_onnx.py 源码可以看到,导出前的数据生成流程为:以sample_rate = 16000生成1 × 40 × 16000的随机音频 → 经whisper.pad_or_trim裁剪/补齐 →whisper.log_mel_spectrogram(audio, n_mels=n_mels)得到 mel 特征 → 送入model.encoder得到encoder_output;同时以max_tokens = 12生成随机 token 序列x_tokens,作为 decoder 的输入。随后依次导出:

  • encoder:torch.onnx.export(model.encoder, (x_mel), ..., input_names=["x"], output_names=["out"], opset_version=12)
  • decoder:torch.onnx.export(model.decoder, (x_tokens, encoder_output), ..., input_names=["tokens", "audio"], output_names=["out"], opset_version=12)

导出完成后脚本会对两个模型分别执行onnxsim.simplify并重新保存,并打印保存路径。

四、导出原始 30 秒输入长度的 ONNX 模型

如果希望保持 whisper 原始的 30 秒输入设计(例如与官方推理流程对齐),则无需修改任何官方源码,直接执行导出命令即可:

pip install openai-whisper==20231117 cd python python export_onnx.py --model_type <MODEL_TYPE> --n_mels <N_MELS(optional)> # 例如: python export_onnx.py --model_type base --n_mels 80

参数含义与上一节完全一致。注意,这里默认的CHUNK_LENGTH仍为 30,模型输入为 30 秒对应的特征尺寸;后续 Python/C++ Demo 中的CHUNK_LENGTH也必须相应设为 30,否则前处理与模型输入尺寸不匹配。

五、导出后的关键参数与源码对应关系

导出 ONNX 只是第一步,真正决定推理正确性的是 Demo 侧一系列与输入长度、模型维度强相关的宏/常量。它们分散在 Python 与 C++ 两套实现中,且与 export_onnx.py 导出的模型必须严格对齐。

5.1 Python Demo 中的对齐参数

在 examples/whisper/python/whisper.py 顶部定义了一组核心常量:

SAMPLE_RATE = 16000 N_FFT = 400 HOP_LENGTH = 160 CHUNK_LENGTH = 20 # 需与模型输入长度一致 N_SAMPLES = CHUNK_LENGTH * SAMPLE_RATE MAX_LENGTH = CHUNK_LENGTH * 100 N_MELS = 80

其中MAX_LENGTH = CHUNK_LENGTH * 100 = 2000对应 log-mel 频谱的时间帧数(即CHUNK_LENGTH / HOP_LENGTH * SAMPLE_RATE ≈ 20 / 160 * 16000 = 2000),N_MELS = 80对应频谱的梅尔维度。mel_filters()函数从 mel_80_filters.txt 读取80 × 201的梅尔滤波器矩阵,其中 201 等于N_FFT / 2 + 1;且源码中有assert n_mels in {80},即当前 Python Demo 只支持 n_mels=80,若导出时使用了 128,需要相应适配滤波器文件。

5.2 C++ Demo 中的对齐参数

在 examples/whisper/cpp/process.h 中定义了 C++ 侧的宏,其中两项在文档“Special Notes”中被明确要求按模型修改:

#define CHUNK_LENGTH 20 // 需与模型输入长度一致 #define ENCODER_OUTPUT_SIZE CHUNK_LENGTH * 50 * 512 // 384/512/1024 分别对应 tiny/base/medium
  • CHUNK_LENGTH:音频分块长度,必须与导出的模型输入长度一致(20 秒模型配 20,30 秒模型配 30);
  • ENCODER_OUTPUT_SIZE:encoder 输出向量的总元素数,其公式为CHUNK_LENGTH * 50 * d_model。d_model 为 transformer 隐藏维度,tiny/base/medium分别对应384/512/1024,即 base 模型为20 * 50 * 512 = 512000,换成 medium 需改为20 * 50 * 1024。

同一文件中还定义了MAX_AUDIO_LENGTH = CHUNK_LENGTH * SAMPLE_RATE、ENCODER_INPUT_SIZE = CHUNK_LENGTH * 100、N_MELS 80、MELS_FILTERS_SIZE 201、MAX_TOKENS 12、VOCAB_NUM 51865等,共同约束着前处理与解码循环。

5.3 解码循环与 token 常量

在 C++ 的 process.cc 与 Python 的whisper.py中,解码采用自回归方式:从sot(50258)开始,拼接任务 token(en 为 50259、zh 为 50260)与timestamp_begin(50364)后反复推理,直至输出endoftext(50257)。中文字符在词表中以 base64 编码存放,因此 C++ 侧实现了base64_decode,Python 侧同样有对应的解码函数——这些逻辑与导出的 decoder 输入输出完全对应。

六、从 ONNX 到 RKNN:转换与 Demo 验证

6.1 获取/转换模型

仓库提供了官方转换脚本 examples/whisper/python/convert.py:

cd python python convert.py <onnx_model> <TARGET_PLATFORM> <dtype(optional)> <output_rknn_path(optional)> # 例如: python convert.py ../model/whisper_encoder_base_20s.onnx rk3588 python convert.py ../model/whisper_decoder_base_20s.onnx rk3588
  • <onnx_model>:导出的 ONNX 模型路径;
  • <TARGET_PLATFORM>:NPU 平台名,支持rk3562、rk3566、rk3568、rk3576、rk3588、rv1126b;
  • <dtype>(可选):i8/u8表示量化,fp表示不量化,默认fp;
  • <output_rknn_path>(可选):RKNN 模型保存路径,默认与 ONNX 同目录。

若想跳过手动导出,仓库 model/download_model.sh 直接提供了 base 20 秒模型的 ONNX 下载脚本:

cd model ./download_model.sh

6.2 运行 Python Demo 验证

cd python # 使用 ONNX 模型推理 python whisper.py --encoder_model_path ../model/whisper_encoder_base_20s.onnx --decoder_model_path ../model/whisper_decoder_base_20s.onnx --task en --audio_path ../model/test_en.wav # 使用 RKNN 模型推理(需指定目标平台) python whisper.py --encoder_model_path ../model/whisper_encoder_base_20s.rknn --decoder_model_path ../model/whisper_decoder_base_20s.rknn --task en --audio_path ../model/test_en.wav --target rk3588

--task支持en(英文识别)与zh(中文识别),--target指定 NPU 平台,--audio_path指向测试音频(仓库自带 test_en.wav 与 test_zh.wav)。运行后输出形如:

# TASK_FOR_EN Whisper output: Mr. Quilter is the apostle of the middle classes, and we are glad to welcome his gospel. # TASK_FOR_ZH Whisper output: 对我做了介绍,我想说的是大家如果对我的研究感兴趣

不同平台、工具与驱动版本下结果可能略有差异。C++ Demo 的编译、推板与运行步骤(build-android.sh/build-linux.sh、./rknn_whisper_demo <encoder.rknn> <decoder.rknn> <task> <audio>)可参见 examples/whisper/README.md。

七、常见问题与排查要点

  1. 导出后模型无法在 Demo 上跑通:优先核对三处CHUNK_LENGTH(官方audio.py、Pythonwhisper.py、C++process.h)是否一致,20 秒模型三处都应等于 20;
  2. 换了模型规格(如 base → medium):C++ 侧ENCODER_OUTPUT_SIZE必须同步从512维改为1024维,否则 decoder 输入尺寸不匹配;
  3. n_mels非默认值:当前 Python Demo 的mel_filters()有assert n_mels in {80}限制,使用其他梅尔数导出时需同步替换 mel_80_filters.txt 并放开断言;
  4. 量化失败:如需部署到 RKNN 上做i8量化,可在convert.py中传入i8,Whisper 属于较重的 Transformer 模型,量化精度受平台与工具版本影响,建议以实际识别结果为准;
  5. 模型规格限制:small/large未被官方导出脚本覆盖,如需使用需自行扩展export_onnx.py的导出逻辑。

八、总结

本指南完整覆盖了 export_onnx.md 的全部内容:20 秒模型的官方源码两处修改(audio.py的CHUNK_LENGTH与model.py的位置编码切片)、30 秒模型的一键导出、--model_type与--n_mels参数说明,以及导出后 Python/C++ Demo 中CHUNK_LENGTH与ENCODER_OUTPUT_SIZE的强制对齐要求。在此基础上,结合 export_onnx.py、convert.py、whisper.py 与 process.h 等仓库源码,进一步揭示了 encoder/decoder 的输入输出命名、opset 版本、onnxsim 精简、梅尔滤波器矩阵以及解码 token 常量等底层细节,帮助你从“能导出”走向“能对齐、能部署、能排错”。

  • 示例工程
  • 人工智能
  • 嵌入式
  • 边缘计算
  • 计算机视觉
  • 模型优化

【免费下载链接】rknn_model_zoo

项目地址:https://gitcode.com/gh_mirrors/rk/rknn_model_zoo
点击查看免费下载

相关推荐

上一篇:Analog测试策略:Vitest、Storybook、Playwright全方位指南
下一篇:如何快速配置6款苹果平方字体:跨平台字体统一终极指南

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

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

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

立即咨询