- 示例工程
- 人工智能
- 嵌入式
- 边缘计算
- 计算机视觉
- 模型优化
【免费下载链接】rknn_model_zoo
导读
本文以 rknn_model_zoo 仓库中的 examples/whisper/README.md 为主线,完整讲解如何将 OpenAI 的开源语音识别模型 Whisper(encoder + decoder 结构)从 ONNX 转换为 RKNN 模型,并在 RK3562、RK3566、RK3568、RK3576、RK3588、RV1126B 等 Rockchip NPU 平台上运行。读完本文,你将掌握 Whisper 的 20 秒/30 秒输入模型导出、RKNN 模型转换参数、Python 端到端推理脚本用法,以及 Android/Linux 上 C++ Demo 的编译、推送与运行方法。
1. 示例背景:Whisper 是什么
Whisper 是 OpenAI 发布的一个通用语音识别(ASR)模型,基于大规模多语种音频数据集训练而成,同时具备多语种语音识别、语音翻译、语种识别等多种能力。本示例使用的模型源自 OpenAI 官方 whisper 开源项目。
在 rknn_model_zoo 中,Whisper 示例采用经典的Encoder-Decoder 双模型结构,将 Whisper 拆分为两个独立的 ONNX 子模型再分别转换为 RKNN:
- whisper_encoder_base_20s.onnx:编码器,负责把 20 秒音频对应的 log-mel 频谱特征编码为高层语义特征;
- whisper_decoder_base_20s.onnx:解码器,负责基于编码输出与 token 序列逐字自回归地生成识别文本。
仓库中该示例的完整目录结构如下:
examples/whisper/ ├── cpp/ # C++ 端(rknpu2 推理实现 + 预处理/后处理) ├── model/ # 模型下载脚本、mel 滤波器、词表与测试音频 ├── python/ # convert.py / export_onnx.py / whisper.py ├── README.md # 本文主体文档 └── export_onnx.md # ONNX 导出指南2. 当前支持平台
本示例支持的 NPU 平台包括:RK3562、RK3566、RK3568、RK3576、RK3588、RV1126B。在后续所有转换与运行命令中,<TARGET_PLATFORM>均需从上述平台中选择。
3. 预训练模型获取
3.1 直接下载已导出的 ONNX 模型
示例默认提供base规模、20 秒输入长度的预导出 ONNX 模型:
- whisper_encoder_base_20s.onnx
- whisper_decoder_base_20s.onnx
在 examples/whisper/model/download_model.sh 中可以看到下载方式,进入 model 目录执行脚本即可:
cd model ./download_model.sh脚本本质是两条wget命令,分别下载 encoder 与 decoder 两个 ONNX 文件到当前目录。
3.2 自行导出 ONNX 模型(详见 export_onnx.md)
若需要使用不同模型规模(tiny/base/medium)或不同输入时长,请参考仓库内的 examples/whisper/export_onnx.md 指南自行导出。
3.2.1 导出 20 秒输入长度的模型
第一步,安装与 OpenAI 官方版本对齐的依赖并修改安装包源码(需安装openai-whisper==20231117):
pip install openai-whisper==20231117 # 1. 修改 whisper/audio.py(例如 ~/python3.8/site-packages/whisper/audio.py)中的 CHUNK_LENGTH CHUNK_LENGTH = 30 -->> CHUNK_LENGTH = 20 # 2. 修改 whisper/model.py 中的 positional_embedding 相关代码 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)第二步,执行导出脚本:
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;<N_MELS>(可选):指定 mel 滤波器数量,如80、128,默认80。
注意:small与large规模的模型当前尚不支持导出。
3.2.2 导出原始 30 秒输入长度的模型
若不修改源码,保持默认CHUNK_LENGTH = 30,直接运行导出脚本即可得到 30 秒输入的模型:
pip install openai-whisper==20231117 cd python python export_onnx.py --model_type <MODEL_TYPE> --n_mels <N_MELS(optional)>从 examples/whisper/python/export_onnx.py 的源码可以看到导出流程:先whisper.load_model(model_type)加载官方模型,再用torch.onnx.export分别导出 encoder(输入名x,输出名out)与 decoder(输入名tokens、audio,输出名out),opset 固定为 12,最后通过onnxsim.simplify对两个模型做简化,产物分别保存为../model/whisper_encoder_{type}.onnx与../model/whisper_decoder_{type}.onnx。
4. 转换为 RKNN 模型
4.1 转换命令
进入python目录,使用 examples/whisper/python/convert.py 将 ONNX 模型转换为 RKNN 模型:
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 # 输出模型将保存在 ../model/whisper_encoder_base_20s.rknn python convert.py ../model/whisper_decoder_base_20s.onnx rk3588 # 输出模型将保存在 ../model/whisper_decoder_base_20s.rknn4.2 参数说明
<onnx_model>:指定 ONNX 模型路径;<TARGET_PLATFORM>:指定 NPU 平台名称,可选范围见第 2 节支持平台列表;<dtype>(可选):取值为i8或fp。i8表示执行 INT8 量化,fp表示不量化(浮点),默认fp;<output_rknn_path>(可选):指定 RKNN 模型保存路径,默认保存在与 ONNX 模型相同的目录(源码中即model_path.replace('.onnx', '.rknn'))。
4.3 转换流程的源码级解析
从 convert.py 可以看到转换的完整调用链:RKNN(verbose=False)创建工具对象 →rknn.config(target_platform=platform)配置目标平台 →rknn.load_onnx(model=model_path)加载 ONNX →rknn.build(do_quantization=do_quant)构建 RKNN 模型(do_quant由 dtype 是否为i8/u8决定)→rknn.export_rknn(output_path)导出 →rknn.release()释放资源。整个过程与 rknn-toolkit2 的标准工作流一致。
值得说明的是:虽然 README 的 dtype 说明只写了i8/fp,但 convert.py 的参数校验同时接受u8(与i8一样触发量化),使用时应以实际源码为准。由于 Whisper 为生成式模型,示例默认关闭量化(DEFAULT_QUANT = False)以保证识别精度,浮点模型对 NPU 显存与带宽的占用也更大,部署时需结合板卡资源评估。
5. Python Demo 推理
5.1 用法
在python目录下运行 examples/whisper/python/whisper.py:
cd python # 使用 ONNX 模型推理(CPU) python whisper.py --encoder_model_path <onnx_model> --decoder_model_path <onnx_model> --task <TASK> --audio_path <AUDIO_PATH> # 例如: 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 模型推理(NPU) python whisper.py --encoder_model_path <rknn_model> --decoder_model_path <rknn_model> --task <TASK> --audio_path <AUDIO_PATH> --target <TARGET_PLATFORM> # 例如: 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 rk35885.2 参数说明
<TARGET_PLATFORM>:指定 NPU 平台名称,范围见支持平台列表(命令行默认值为rk3588);<onnx_model / rknn_model>:指定模型路径,脚本会根据文件后缀(.rknn或.onnx)自动选择推理后端;<TASK>:指定识别任务,如en(英语识别)、zh(中文识别)。目前仅支持这两种,其他取值会打印提示并退出;<AUDIO_PATH>:指定音频文件路径。
5.3 推理流程的源码级解析
whisper.py 的核心处理链路如下:
- 音频读取与预处理:
soundfile读取音频后,ensure_channels将多声道转为单声道(对通道取均值),ensure_sample_rate用scipy.signal.resample将任意采样率统一重采样到 16000 Hz; - log-mel 频谱计算:
log_mel_spectrogram使用torch.stft(N_FFT=400、HOP_LENGTH=160、hann 窗)计算短时傅里叶变换,再与 examples/whisper/model/mel_80_filters.txt 中的 80 维 mel 滤波器做矩阵乘法,最后做log10归一化(clamp 到 1e-10,裁剪到最大值减 8,再平移缩放到 (0,1) 区间); - 填充/裁剪:
pad_or_trim将 mel 特征统一对齐到N_MELS × MAX_LENGTH(20 秒 × 100 帧),超出部分截断、不足部分补零; - Encoder 推理:
run_encoder根据模型类型调用rknn.inference或onnxruntime.run; - Decoder 自回归解码:
run_decoder以[sot, task_code, no_timestamps, ...]作为起始 token 序列(如50258为 sot、50259/50260分别为 en/zh 任务码、50364为 timestamp 起点、50257为 eot 结束符),循环调用_decode取out_decoder[0, -1].argmax()得到下一个 token,对照 examples/whisper/model/vocab_en.txt 或 examples/whisper/model/vocab_zh.txt 词表拼出文本,直到命中结束符为止;中文任务(task_code=50260)还需要对结果做 base64 解码(base64_decode)才能得到可读汉字; - 资源释放:
release_model对 RKNN 模型调用release(),对 ONNX 会话直接del。
6. Android Demo
6.1 编译构建
回到 rknn_model_zoo 根目录,设置 Android NDK 路径后调用仓库顶层的构建脚本:
# 回到 rknn_model_zoo 根目录 cd ../../ export ANDROID_NDK_PATH=<android_ndk_path> ./build-android.sh -t <TARGET_PLATFORM> -a <ARCH> -d whisper # 例如 ./build-android.sh -t rk3588 -a arm64-v8a -d whisper参数说明:
<android_ndk_path>:指定 Android NDK 路径;<TARGET_PLATFORM>:指定 NPU 平台名称(见支持平台列表);<ARCH>:指定设备系统架构,可通过以下命令查询:
# 查询架构,日志中应显示 ['arm64-v8a' 或 'armeabi-v7a'] adb shell cat /proc/version6.2 推送 demo 文件到设备
设备通过 USB 连接后,将构建产物推送到设备:
adb root adb remount adb push install/<TARGET_PLATFORM>_android_<ARCH>/rknn_whisper_demo/ /data/6.3 运行 demo
adb shell cd /data/rknn_whisper_demo export LD_LIBRARY_PATH=./lib ./rknn_whisper_demo model/whisper_encoder_base_20s.rknn model/whisper_decoder_base_20s.rknn en model/test_en.wav程序接收 5 个命令行参数:<encoder_path> <decoder_path> <task> <audio_path>(第 0 个为可执行文件名本身),对应上面的 encoder 模型、decoder 模型、任务类型(en/zh)与音频路径。
7. Linux Demo
Linux 编译工具链推荐使用
gcc-linaro-6.3.1(aarch64)/gcc-arm-8.3(armhf)/armhf-uclibcgnueabihf(armhf for RV1106/RV1103 系列)。使用其他版本可能遇到 C demo 编译失败的问题。详细的编译环境搭建请参考 docs/Compilation_Environment_Setup_Guide.md。
7.1 编译构建
# 回到 rknn_model_zoo 根目录 cd ../../ # 若编译时找不到 GCC_COMPILER,请手动设置其路径 (可选) export GCC_COMPILER=<GCC_COMPILER_PATH> ./build-linux.sh -t <TARGET_PLATFORM> -a <ARCH> -d whisper # 例如 ./build-linux.sh -t rk3588 -a aarch64 -d whisper参数说明:
<GCC_COMPILER_PATH>:GCC_COMPILER 路径;<TARGET_PLATFORM>:NPU 平台名称(见支持平台列表);<ARCH>:设备系统架构,查询方式:
# 查询架构,对于 Linux,日志中应显示 ['aarch64' 或 'armhf'] adb shell cat /proc/version7.2 推送 demo 文件到设备
- 若设备通过 USB 连接,直接推送:
adb push install/<TARGET_PLATFORM>_linux_<ARCH>/rknn_whisper_demo/ /data/- 对于其他开发板,使用
scp或其他方式将install/<TARGET_PLATFORM>_linux_<ARCH>/rknn_whisper_demo/下的所有文件拷贝到设备/data目录。
7.3 运行 demo
adb shell cd /data/rknn_whisper_demo export LD_LIBRARY_PATH=./lib ./rknn_whisper_demo model/whisper_encoder_base_20s.rknn model/whisper_decoder_base_20s.rknn en model/test_en.wav8. C++ 端实现原理(源码级解析)
C++ demo 的主体在 examples/whisper/cpp/main.cc 与 examples/whisper/cpp/process.cc 中,整体流程与 Python 版一一对应:
- 音频读取:
read_audio读取音频;双声道时convert_channels转单声道;采样率非 16000 时resample_audio重采样(相关工具函数位于 utils/audio_utils.c); - 预加载资源:
read_mel_filters读取 examples/whisper/model/mel_80_filters.txt,read_vocab按"index token"格式解析词表; - 模型初始化:
init_whisper_model依次对 encoder、decoder 调用rknn_init、rknn_query(RKNN_QUERY_IN_OUT_NUM)、rknn_query(RKNN_QUERY_INPUT_ATTR / OUTPUT_ATTR)并打印各张量的维度、格式、类型与量化参数(见 examples/whisper/cpp/rknpu2/whisper.cc); - 音频预处理:
audio_preprocess用 Hann 窗 + FFTW3 计算 STFT,再与 mel 滤波器做矩阵乘法(ENABLE_NEON开启时使用 ARM NEON 指令集加速,否则回退到 OpenCVgemm),最后clamp_and_log_max做与 Python 版一致的 log 归一化; - 推理与解码:
inference_whisper_model在 NPU 上执行 encoder 推理,随后以自回归方式逐 token 执行 decoder 推理(argmax选取最大概率 token),按词表拼接文本,中文任务同样做 base64 解码; - 性能统计:程序结束时会打印
Real Time Factor (RTF),即推理耗时与音频时长的比值(音频时长按CHUNK_LENGTH20 秒封顶),用于评估实时性(见 main.cc)。
8.1 关键宏定义:更换模型时必须同步修改
examples/whisper/cpp/process.h 中集中定义了与模型强耦合的常量,更换模型规模或输入长度时必须同步调整:
#define VOCAB_NUM 51865 #define MAX_TOKENS 12 #define SAMPLE_RATE 16000 #define N_FFT 400 #define HOP_LENGTH 160 #define CHUNK_LENGTH 20 #define MAX_AUDIO_LENGTH CHUNK_LENGTH * SAMPLE_RATE // 20 秒 × 16000 #define N_MELS 80 #define MELS_FILTERS_SIZE 201 // N_FFT / 2 + 1 #define ENCODER_INPUT_SIZE CHUNK_LENGTH * 100 #define ENCODER_OUTPUT_SIZE CHUNK_LENGTH * 50 * 512 // 384/512/1024 分别对应 tiny/base/medium #define DECODER_INPUT_SIZE ENCODER_OUTPUT_SIZE根据 export_onnx.md 中的 Special Notes:
CHUNK_LENGTH需根据模型的输入时长(20 秒或 30 秒)修改,Python 版whisper.py中的CHUNK_LENGTH同理;ENCODER_OUTPUT_SIZE需根据模型规模修改:tiny/base/medium分别对应384/512/1024。
9. 预期结果
运行 demo 后,程序会打印识别出的文本。英文任务(TASK_FOR_EN)与中文任务(TASK_FOR_ZH)的参考输出如下:
# 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: 对我做了介绍,我想说的是大家如果对我的研究感兴趣注意:不同平台、不同版本的工具链与驱动可能导致结果略有差异。
10. 常见问题与注意事项
- 模型与代码常量不匹配:无论是 Python 还是 C++ demo,
CHUNK_LENGTH(输入时长)与ENCODER_OUTPUT_SIZE(模型规模对应的编码维度)必须与实际导出的 ONNX/RKNN 模型一致,否则推理会失败或输出错误结果; - 量化精度风险:示例默认以浮点(
fp)方式转换。若希望压缩模型体积、提升 NPU 推理速度而使用i8量化,需自行评估识别精度下降是否可接受; - 中文解码依赖 base64:中文识别的原始输出是 base64 编码的文本,Python 与 C++ demo 均已内置
base64_decode处理,直接使用示例代码即可; - 音频要求:demo 会自动处理采样率与声道数,但为保证识别效果,建议输入清晰、无背景噪音的 16 kHz 单声道语音。
11. 总结
通过本文可以完整走通一条 Whisper 在 Rockchip NPU 上的部署链路:从官方 whisper 模型导出 20 秒/30 秒 ONNX 子模型(encoder/decoder),经 rknn-toolkit2 的config → load_onnx → build → export_rknn转换为 RKNN 模型,再到 Python 端到端推理、Android/Linux 上的 C++ Demo 编译运行。核心要点是理解 Whisper 的编码器-解码器结构在 NPU 上的拆分方式,以及输入时长、模型规模与代码常量的对齐关系。仓库内 examples/whisper/README.md 与 examples/whisper/export_onnx.md 是后续查阅的一手资料,源码 examples/whisper/python/whisper.py 与 examples/whisper/cpp/process.cc 则是调试与二次开发的最佳参考。
- 示例工程
- 人工智能
- 嵌入式
- 边缘计算
- 计算机视觉
- 模型优化
【免费下载链接】rknn_model_zoo
相关推荐
RKNN 部署 PP-YOLOE 全流程实战指南:模型导出、量化转换与 C/Python 双端 Demo(rknn_model_zoo)
RKNN 部署 PP YOLOE 全流程实战指南:模型导出、量化转换与 C/Python 双端 Demo(rknn_model_zoo) PP YOLOE 是百
示例工程人工智能嵌入式边缘计算计算机视觉模型优化rknn_model_zoo 实战:YOLOv5 实例分割模型在 RKNN 平台的转换与部署全流程
rknn_model_zoo 实战:YOLOv5 实例分割模型在 RKNN 平台的转换与部署全流程 导读 本文以 rknn_model_zoo 仓库中的 exa
示例工程人工智能嵌入式边缘计算计算机视觉模型优化PaddleSeg 在 Rockchip RKNPU2 上的 FastDeploy 部署实战:模型转换、C++/Python 推理全流程
PaddleSeg 在 Rockchip RKNPU2 上的 FastDeploy 部署实战:模型转换、C++/Python 推理全流程 本文基于 Paddle
人工智能计算机视觉预训练
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考