ZipVoice AXERA C++
ZipVoice TTS 在 AXERA NPU 板卡上的 C++ 推理实现。全链路 axmodel,无 Python 依赖(英文分词除外)。
性能 (AX650)
Distill 模型
| 场景 | 音频 | 耗时 | RTF |
|---|---|---|---|
| 中文句子 | 6.41s | 1.057s | 0.165 |
| 中文段落 | 44.97s | 7.357s | 0.164 |
| 英文句子 | 6.41s | 1.067s | 0.166 |
| 英文段落 | 59.31s | 10.529s | 0.178 |
普通模型
| 场景 | 音频 | 耗时 | RTF |
|---|---|---|---|
| 中文句子 | 6.41s | 5.709s | 0.891 |
| 中文段落 | 44.97s | 39.714s | 0.883 |
| 英文句子 | 6.41s | 5.693s | 0.888 |
| 英文段落 | 59.31s | 56.759s | 0.957 |
目录结构
├── CMakeLists.txt # 构建配置
├── zipvoice.cpp # 主程序
├── build_ax650.sh # 交叉编译脚本
├── download_bsp.sh # 下载 BSP SDK
├── cmake/
│ └── msp_dependencies.cmake # MSP SDK 配置
├── toolchains/
│ └── aarch64-none-linux-gnu.toolchain.cmake # 工具链
├── third_party/kissfft/ # kissfft (vocoder IRFFT)
├── utils/ # 日志/IO/检查
├── src/ # 核心源码
│ ├── EngineWrapper.* # AX引擎封装
│ ├── tokenizer.* # 中文分词 (41K汉字pinyin映射)
│ ├── pinyin_table.hpp # 汉字→拼音表 (自动生成)
│ ├── fbank.* # Mel滤波器 (FFT)
│ ├── zipvoice_engine.* # 推理引擎 (encoder+decoder4)
│ ├── vocoder.* # 声码器 (axmodel+kissfft IRFFT)
│ └── wav_writer.hpp # WAV写入
├── vocoder/
│ └── vocos_full.axmodel # 量化声码器 (15MB)
├── scripts/ # Python辅助脚本
│ ├── gen_cat_tokens.py # 预计算token
│ ├── gen_pinyin_table.py # 生成汉字映射表
│ ├── export_vocos_onnx.py # 导出ONNX
│ ├── generate_vocoder_calib.py # 校准数据
│ └── quantize_vocoder.sh # pulsar2量化
└── README.md
环境准备
# 下载 BSP SDK
bash download_bsp.sh
# 安装交叉编译器
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz
tar -xf gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz
# 编译时传 -DTOOLCHAIN_DIR=/path/to/gcc-arm-... 或在 toolchains/ 中修改
编译
mkdir build_ax650 && cd build_ax650
cmake .. \
-DCMAKE_TOOLCHAIN_FILE=../toolchains/aarch64-none-linux-gnu.toolchain.cmake \
-DTOOLCHAIN_DIR=/path/to/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu \
-DCMAKE_INSTALL_PREFIX=../install/ax650 \
-DCMAKE_BUILD_TYPE=Release
make -j$(nproc) && make install
板端推理
所有命令在 repo 根目录(ZipVoice.AXERA/)下执行。
中文
# 普通模型 — 句子
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_ax650 \
--token-file ./resources/zipvoice_hf/zipvoice/tokens.txt \
--prompt-wav ./assets/moss_prompts/zh_1_4p5s.wav \
--prompt-text "不管怎么样我和汤姆还是要感谢贝尔卡金的援手" \
--text "今天午后天气很好,我打开窗户,听见远处有人聊天,水杯也轻轻晃了一下。" \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output.wav --seed 42
推理结果:
Segments: 1
Audio duration: 6.41 s
Total time: 5.71 s
RTF (端到端): 0.891
# 蒸馏模型 — 句子 (约3倍速)
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_distill_ax650 \
--token-file ./resources/zipvoice_hf/zipvoice/tokens.txt \
--prompt-wav ./assets/moss_prompts/zh_1_4p5s.wav \
--prompt-text "不管怎么样我和汤姆还是要感谢贝尔卡金的援手" \
--text "今天午后天气很好,我打开窗户,听见远处有人聊天,水杯也轻轻晃了一下。" \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output.wav --seed 42
推理结果:
Segments: 1
Audio duration: 6.41 s
Total time: 1.06 s
RTF (端到端): 0.165
# 普通模型 — 段落
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_ax650 \
--token-file ./resources/zipvoice_hf/zipvoice/tokens.txt \
--prompt-wav ./assets/moss_prompts/zh_1_4p5s.wav \
--prompt-text "不管怎么样我和汤姆还是要感谢贝尔卡金的援手" \
--text-file ./assets/paragraphs/zh_ginkgo.txt \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output.wav --seed 42
推理结果:
Segments: 7
Audio duration: 44.97 s
Total time: 39.71 s
RTF (端到端): 0.883
# 蒸馏模型 — 段落
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_distill_ax650 \
--token-file ./resources/zipvoice_hf/zipvoice/tokens.txt \
--prompt-wav ./assets/moss_prompts/zh_1_4p5s.wav \
--prompt-text "不管怎么样我和汤姆还是要感谢贝尔卡金的援手" \
--text-file ./assets/paragraphs/zh_ginkgo.txt \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output.wav --seed 42
推理结果:
Segments: 7
Audio duration: 44.97 s
Total time: 7.38 s
RTF (端到端): 0.164
英文 (加 --repo-dir . 自动调 Python 分词器)
# 普通模型 — 句子
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_ax650 \
--prompt-wav ./assets/moss_prompts/en_4_4p5s.wav \
--prompt-text "This is almost twice the current industry production level per train." \
--text "This morning, a small train left the station, carrying sleepy passengers toward a bright coastal town." \
--repo-dir . \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output_en.wav --seed 42
推理结果:
Segments: 1
Audio duration: 6.41 s
Total time: 5.69 s
RTF (端到端): 0.888
# 蒸馏模型 — 句子
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_distill_ax650 \
--prompt-wav ./assets/moss_prompts/en_4_4p5s.wav \
--prompt-text "This is almost twice the current industry production level per train." \
--text "This morning, a small train left the station, carrying sleepy passengers toward a bright coastal town." \
--repo-dir . \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output_en.wav --seed 42
推理结果:
Segments: 1
Audio duration: 6.41 s
Total time: 1.06 s
RTF (端到端): 0.166
# 普通模型 — 段落
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_ax650 \
--prompt-wav ./assets/moss_prompts/en_4_4p5s.wav \
--prompt-text "This is almost twice the current industry production level per train." \
--text-file ./assets/paragraphs/en_scavenger.txt \
--repo-dir . \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output_en.wav --seed 42
推理结果:
Segments: 10
Audio duration: 59.31 s
Total time: 56.76 s
RTF (端到端): 0.957
# 蒸馏模型 — 段落
cpp/install/ax650/zipvoice_axera \
--model-dir ./models/zipvoice_distill_ax650 \
--prompt-wav ./assets/moss_prompts/en_4_4p5s.wav \
--prompt-text "This is almost twice the current industry production level per train." \
--text-file ./assets/paragraphs/en_scavenger.txt \
--repo-dir . \
--vocoder-model ./cpp/vocoder/vocos_full.axmodel \
--output-wav output_en.wav --seed 42
推理结果:
Segments: 10
Audio duration: 59.31 s
Total time: 10.56 s
RTF (端到端): 0.178
命令行参数
| 参数 | 说明 | 默认值 |
|---|---|---|
--model-dir |
模型目录 | 必填 |
--token-file |
tokens.txt (中文) | 可选 |
--prompt-wav |
提示音频 | 必填 |
--prompt-text |
提示文本 | 必填 |
--text / --text-file |
合成文本 | 二选一 |
--repo-dir |
repo根目录 (英文分词) | 可选 |
--vocoder-model |
vocos axmodel 路径 | 必填 |
--output-wav |
输出WAV | output.wav |
--num-step |
采样步数 | 10 (distill: 4) |
--speed |
语速 | 1.0 |
--seed |
随机种子 | 42 |
重新量化 vocoder
cd cpp/scripts
python3 export_vocos_onnx.py # 导出ONNX
python3 generate_vocoder_calib.py # 生成校准数据
source /path/to/npu_dev && bash quantize_vocoder.sh # 量化
实现要点
- 中文分词: C++ 内置, 基于 pypinyin 的 41K 汉字→拼音映射表, 0ms 开销
- 英文分词: Python daemon 持久进程, 首次 import ~8s, 后续每次 ~10ms
- 长文本分段: 对齐 Python
text_processing.build_segments, 自动按 token/帧数约束切段 - 声码器: vocos axmodel (NPU) + kissfft IRFFT (CPU), 比手写逐点版快 ~30x
- RTF 口径: 仅计入增量推理 (tokenizer + encoder + decoder + vocoder), 不含一次性初始化
许可
MIT License