Create README.md
Browse files
README.md
ADDED
|
@@ -0,0 +1,646 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
base_model:
|
| 3 |
+
- openbmb/VoxCPM-0.5B
|
| 4 |
+
---
|
| 5 |
+
# VoxCPM ONNX
|
| 6 |
+
|
| 7 |
+
[Github Repo](https://github.com/bluryar/VoxCPM-ONNX)
|
| 8 |
+
|
| 9 |
+
VoxCPM ONNX 是对 [OpenBMB/VoxCPM](https://github.com/OpenBMB/VoxCPM) 开源模型的 ONNX 导出与推理扩展项目。支持将 VoxCPM 文本转语音模型导出为 ONNX 格式并提供高效的推理服务,支持 CPU 和 GPU 部署,提供 REST API 接口。
|
| 10 |
+
|
| 11 |
+
> ⚠️ **重要声明**
|
| 12 |
+
> 1. 本项目代码与本文档完全由生成式AI驱动生成!
|
| 13 |
+
> 2. 使用本项目需遵守VoxCPM以及相关方面的版权规定
|
| 14 |
+
> 3. 当前导出代码因为将所有Decode步骤合并到一个模块中,不得不把固定求解欧拉方程的`timesteps`参数(默认为10,但经过测试timesteps=5也是可用的,并且解码速度可大大提升)
|
| 15 |
+
> 4. 当前导出代码重复导出了两份VoxCPM的权重(Prefill和Decode)
|
| 16 |
+
|
| 17 |
+
## 项目背景
|
| 18 |
+
|
| 19 |
+
本项目基于 OpenBMB 团队的 VoxCPM 模型,该模型是一个无需分词器的文本转语音系统,具有以下特点:
|
| 20 |
+
- **上下文感知语音生成**: 能够理解文本内容并生成适当的韵律
|
| 21 |
+
- **真实声音克隆**: 仅需短参考音频即可实现零样本声音克隆
|
| 22 |
+
- **高效合成**: 支持流式合成,适用于实时应用场景
|
| 23 |
+
|
| 24 |
+
我们的扩展工作专注于 ONNX 导出和推理优化,使模型更易于部署和使用。
|
| 25 |
+
|
| 26 |
+
## 功能特性
|
| 27 |
+
|
| 28 |
+
### 原始 VoxCPM 模型能力
|
| 29 |
+
- 🎯 **无需分词器的 TTS**: 直接在连续空间中建模语音,克服离散分词限制
|
| 30 |
+
- 🗣️ **上下文感知语音生成**: 理解文本内容并生成适当的韵律和表达
|
| 31 |
+
- 🎭 **真实声音克隆**: 仅需短参考音频即可实现零样本声音克隆
|
| 32 |
+
- ⚡ **高效合成**: 支持流式合成,适用于实时应用场景
|
| 33 |
+
|
| 34 |
+
### ONNX 扩展功能
|
| 35 |
+
- 🚀 **ONNX 导出**: 将 PyTorch 模型导出为 ONNX 格式
|
| 36 |
+
- 🔧 **模型优化**: 自动优化导出的 ONNX 模型
|
| 37 |
+
- 🐳 **容器化部署**: 支持 Docker Compose 一键部署
|
| 38 |
+
- 🎯 **REST API**: 提供 OpenAI 兼容的 TTS API
|
| 39 |
+
- 💻 **多平台支持**: 支持 CPU 和 GPU 推理
|
| 40 |
+
- 🎙️ **高质量语音**: 支持多种语音风格和参考音频
|
| 41 |
+
|
| 42 |
+
## 项目结构
|
| 43 |
+
|
| 44 |
+
```
|
| 45 |
+
VoxCPM-ONNX/
|
| 46 |
+
├── onnx/ # ONNX 导出脚本
|
| 47 |
+
│ ├── export_audio_vae_encoder.py
|
| 48 |
+
│ ├── export_audio_vae_decoder.py
|
| 49 |
+
│ ├── export_voxcpm_prefill.py
|
| 50 |
+
│ └── export_voxcpm_decode.py
|
| 51 |
+
├── src/
|
| 52 |
+
│ ├── onnx_infer/ # ONNX 推理引擎
|
| 53 |
+
│ └── server/ # FastAPI 服务
|
| 54 |
+
├── export.sh # ONNX 导出主脚本
|
| 55 |
+
├── opt.sh # 模型优化脚本
|
| 56 |
+
├── docker-compose.yml # Docker 部署配置
|
| 57 |
+
├── pyproject.toml # 项目配置和依赖管理
|
| 58 |
+
├── uv.lock # uv 依赖锁定文件
|
| 59 |
+
└── infer.py # 独立推理脚本
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
## 快速开始
|
| 63 |
+
|
| 64 |
+
### 1. 环境准备
|
| 65 |
+
|
| 66 |
+
#### 系统要求
|
| 67 |
+
- Python 3.10+
|
| 68 |
+
- CUDA 11.8+ (GPU 版本)
|
| 69 |
+
- Docker 和 Docker Compose (可选)
|
| 70 |
+
|
| 71 |
+
#### 环境管理
|
| 72 |
+
|
| 73 |
+
本项目使用 [uv](https://docs.astral.sh/uv/) 进行环境管理,确保依赖的一致性和可重现性。
|
| 74 |
+
|
| 75 |
+
**使用 uv 创建开发环境:**
|
| 76 |
+
```bash
|
| 77 |
+
# 克隆项目后,使用 uv 同步环境
|
| 78 |
+
uv sync
|
| 79 |
+
|
| 80 |
+
# 激活虚拟环境
|
| 81 |
+
uv run bash
|
| 82 |
+
# 或
|
| 83 |
+
source .venv/bin/activate
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
**安装依赖:**
|
| 87 |
+
|
| 88 |
+
**开发环境 (完整功能):**
|
| 89 |
+
```bash
|
| 90 |
+
uv pip install -e .
|
| 91 |
+
# 或
|
| 92 |
+
pip install -r pyproject.toml
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
**CPU 推理环境:**
|
| 96 |
+
```bash
|
| 97 |
+
uv pip install -r requirement.txt
|
| 98 |
+
# 或
|
| 99 |
+
pip install -r requirement.txt
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
**GPU 推理环境:**
|
| 103 |
+
```bash
|
| 104 |
+
uv pip install -r requirement-gpu.txt
|
| 105 |
+
# 或
|
| 106 |
+
pip install -r requirement-gpu.txt
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
### 2. 获取预训练模型
|
| 110 |
+
|
| 111 |
+
从官方 VoxCPM 仓库下载预训练模型(VoxCPM-0.5B):
|
| 112 |
+
|
| 113 |
+
**自动下载(推荐):**
|
| 114 |
+
```python
|
| 115 |
+
from huggingface_hub import snapshot_download
|
| 116 |
+
snapshot_download("openbmb/VoxCPM-0.5B")
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
**手动下载:**
|
| 120 |
+
```bash
|
| 121 |
+
# 创建模型目录
|
| 122 |
+
mkdir -p VoxCPM-0.5B
|
| 123 |
+
|
| 124 |
+
# 下载模型文件到该目录
|
| 125 |
+
# 访问 https://huggingface.co/openbmb/VoxCPM-0.5B 获取模型文件
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
**可选增强模型(用于语音增强和提示处理):**
|
| 129 |
+
```python
|
| 130 |
+
from modelscope import snapshot_download
|
| 131 |
+
snapshot_download('iic/speech_zipenhancer_ans_multiloss_16k_base')
|
| 132 |
+
snapshot_download('iic/SenseVoiceSmall')
|
| 133 |
+
```
|
| 134 |
+
|
| 135 |
+
### 3. 导出 ONNX 模型
|
| 136 |
+
|
| 137 |
+
使用一键导出脚本将 PyTorch 模型导出为 ONNX 格式:
|
| 138 |
+
|
| 139 |
+
```bash
|
| 140 |
+
# 基本用法
|
| 141 |
+
bash export.sh
|
| 142 |
+
|
| 143 |
+
# 自定义参数
|
| 144 |
+
MODEL_PATH=./VoxCPM-0.5B OUTPUT_DIR=./onnx_models TIMESTEPS=10 CFG_VALUE=2.0 bash export.sh
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
导出过程将生成以下模型文件:
|
| 148 |
+
- `audio_vae_encoder.onnx` - 音频 VAE 编码器
|
| 149 |
+
- `audio_vae_decoder.onnx` - 音频 VAE 解码器
|
| 150 |
+
- `voxcpm_prefill.onnx` - VoxCPM 预填充模型
|
| 151 |
+
- `voxcpm_decode_step.onnx` - VoxCPM 解码步骤模型
|
| 152 |
+
|
| 153 |
+
### 4. 优化 ONNX 模型
|
| 154 |
+
|
| 155 |
+
使用优化脚本对导出的模型进行进一步优化:
|
| 156 |
+
|
| 157 |
+
```bash
|
| 158 |
+
bash opt.sh
|
| 159 |
+
```
|
| 160 |
+
|
| 161 |
+
优化后的模型将保存在 `onnx_models_processed/` 目录中。
|
| 162 |
+
|
| 163 |
+
### 5. 启动服务
|
| 164 |
+
|
| 165 |
+
#### 使用 Docker Compose (推荐)
|
| 166 |
+
|
| 167 |
+
**GPU 版本:**
|
| 168 |
+
```bash
|
| 169 |
+
# 确保已安装 NVIDIA Container Toolkit
|
| 170 |
+
docker-compose up voxcpm-gpu
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
**CPU 版本:**
|
| 174 |
+
```bash
|
| 175 |
+
# 取消 docker-compose.yml 中 voxcpm-cpu 服务的注释
|
| 176 |
+
docker-compose up voxcpm-cpu
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
服务启动后,API 将在以下地址可用:
|
| 180 |
+
- 主服务: http://localhost:8100
|
| 181 |
+
- 健康检查: http://localhost:8100/health
|
| 182 |
+
- **📚 交互式API文档**: http://localhost:8100/docs (Swagger UI界面,可在线测试所有接口)
|
| 183 |
+
|
| 184 |
+
#### 手动启动
|
| 185 |
+
|
| 186 |
+
**GPU 版本:**
|
| 187 |
+
```bash
|
| 188 |
+
# 设置环境变量
|
| 189 |
+
export VOX_OUTPUT_DIR=./outputs
|
| 190 |
+
export VOX_SQLITE_PATH=./ref_feats.db
|
| 191 |
+
export VOX_DEVICE=cuda
|
| 192 |
+
export VOX_DEVICE_ID=0
|
| 193 |
+
export VOX_MODELS_DIR=./models/onnx_models_quantized
|
| 194 |
+
export VOX_TOKENIZER_DIR=./models/onnx_models_quantized
|
| 195 |
+
export PYTHONPATH=./src
|
| 196 |
+
|
| 197 |
+
# 启动服务
|
| 198 |
+
python -m uvicorn src.server.app:app --host 0.0.0.0 --port 8000
|
| 199 |
+
|
| 200 |
+
# 服务启动后访问
|
| 201 |
+
# 📚 交互式API文档: http://localhost:8000/docs
|
| 202 |
+
```
|
| 203 |
+
|
| 204 |
+
**CPU 版本:**
|
| 205 |
+
```bash
|
| 206 |
+
# 设置环境变量
|
| 207 |
+
export VOX_OUTPUT_DIR=./outputs
|
| 208 |
+
export VOX_SQLITE_PATH=./ref_feats.db
|
| 209 |
+
export VOX_DEVICE=cpu
|
| 210 |
+
export VOX_DEVICE_ID=0
|
| 211 |
+
export VOX_MODELS_DIR=./models/onnx_models_quantized
|
| 212 |
+
export VOX_TOKENIZER_DIR=./models/onnx_models_quantized
|
| 213 |
+
export PYTHONPATH=./src
|
| 214 |
+
|
| 215 |
+
# 启动服务
|
| 216 |
+
python -m uvicorn src.server.app:app --host 0.0.0.0 --port 8000
|
| 217 |
+
```
|
| 218 |
+
|
| 219 |
+
## API 使用
|
| 220 |
+
|
| 221 |
+
### 可用端点
|
| 222 |
+
|
| 223 |
+
**📚 API文档**: 部署Docker服务后,访问 `http://<HOST>:<PORT>/docs` 即可查看所有接口的交互式文档(Swagger UI)!
|
| 224 |
+
|
| 225 |
+
**健康检查:**
|
| 226 |
+
- `GET /health` - 检查服务状态和模型加载情况
|
| 227 |
+
|
| 228 |
+
**参考音频管理:**
|
| 229 |
+
- `POST /ref_feat` - 上传参考音频并编码存储特征到数据库
|
| 230 |
+
|
| 231 |
+
**文本转语音:**
|
| 232 |
+
- `POST /tts` - TTS语音生成(POST方式,支持文件上传)
|
| 233 |
+
- `GET /tts` - TTS语音生成(GET方式,仅URL参数)
|
| 234 |
+
|
| 235 |
+
### 接口详细说明
|
| 236 |
+
|
| 237 |
+
#### 1. 健康检查 (GET /health)
|
| 238 |
+
```bash
|
| 239 |
+
curl http://localhost:8100/health
|
| 240 |
+
```
|
| 241 |
+
**响应示例:**
|
| 242 |
+
```json
|
| 243 |
+
{
|
| 244 |
+
"status": "ok",
|
| 245 |
+
"initialized": true,
|
| 246 |
+
"models_dir": "/root/code/VoxCPM/onnx_models",
|
| 247 |
+
"device_type": "cuda",
|
| 248 |
+
"device_id": 0
|
| 249 |
+
}
|
| 250 |
+
```
|
| 251 |
+
|
| 252 |
+
#### 2. 上传参考音频 (POST /ref_feat)
|
| 253 |
+
|
| 254 |
+
**功能说明**: 上传参考音频文件,系统会提取音频特征并持久化存储到 SQLite 数据库中。上传后的参考音频可以通过 `feat_id` 在后续的 TTS 请求中重复使用。
|
| 255 |
+
|
| 256 |
+
**使用场景**:
|
| 257 |
+
- 创建个性化的语音克隆
|
| 258 |
+
- 保存特定说话人的声音特征
|
| 259 |
+
- 避免重复上传相同的参考音频
|
| 260 |
+
|
| 261 |
+
**请求参数**:
|
| 262 |
+
- `feat_id` (必填): 参考音频的唯一标识符,后续通过此 ID 引用该音频
|
| 263 |
+
- `prompt_audio` (必填): 参考音频文件 (支持 WAV、MP3 等格式)
|
| 264 |
+
- `prompt_text` (可选): 参考音频对应的文本内容,有助于提高合成质量
|
| 265 |
+
|
| 266 |
+
**使用示例**:
|
| 267 |
+
```bash
|
| 268 |
+
curl -X POST http://localhost:8100/ref_feat \
|
| 269 |
+
-F "feat_id=my_voice" \
|
| 270 |
+
-F "prompt_audio=@reference.wav" \
|
| 271 |
+
-F "prompt_text=这是参考文本内容,可以帮助模型更好地理解声音特征"
|
| 272 |
+
```
|
| 273 |
+
|
| 274 |
+
**响应示例:**
|
| 275 |
+
```json
|
| 276 |
+
{
|
| 277 |
+
"feat_id": "my_voice",
|
| 278 |
+
"patches_shape": [1, 100, 64]
|
| 279 |
+
}
|
| 280 |
+
```
|
| 281 |
+
|
| 282 |
+
**持久化存储**: 上传的参考音频特征会永久保存在 SQLite 数据库中(路径由 `VOX_SQLITE_PATH` 环境变量配置),服务重启后仍然可用。
|
| 283 |
+
|
| 284 |
+
#### 3. 文本转语音 - POST方式
|
| 285 |
+
|
| 286 |
+
**voice 参数作用说明**:
|
| 287 |
+
- `"default"`: 使用系统默认的参考音频进行语音合成
|
| 288 |
+
- 自定义 `feat_id`: 使用通过 `/ref_feat` 上传的参考音频进行语音克隆
|
| 289 |
+
- 留空或不传: 不使用参考音频,仅基于文本进行基础合成
|
| 290 |
+
|
| 291 |
+
**使用场景**:
|
| 292 |
+
- **默认声音**: 快速测试或基础语音合成
|
| 293 |
+
- **自定义声音**: 个性化语音克隆,复现已上传的说话人声音
|
| 294 |
+
- **声音切换**: 在同一服务中使用多个不同的说话人声音
|
| 295 |
+
|
| 296 |
+
**请求示例**:
|
| 297 |
+
```bash
|
| 298 |
+
# 使用默认声音
|
| 299 |
+
curl -X POST http://localhost:8100/tts \
|
| 300 |
+
-F "input=你好,这是一个测试文本。" \
|
| 301 |
+
-F "voice=default" \
|
| 302 |
+
-F "response_format=mp3"
|
| 303 |
+
|
| 304 |
+
# 使用自定义参考声音(需要先通过 /ref_feat 上传)
|
| 305 |
+
curl -X POST http://localhost:8100/tts \
|
| 306 |
+
-F "input=使用自定义声音合成这段文本。" \
|
| 307 |
+
-F "voice=my_custom_voice" \
|
| 308 |
+
-F "response_format=mp3"
|
| 309 |
+
|
| 310 |
+
# 完整参数示例
|
| 311 |
+
curl -X POST http://localhost:8100/tts \
|
| 312 |
+
-F "input=你好,这是一个测试文本。" \
|
| 313 |
+
-F "voice=my_voice" \
|
| 314 |
+
-F "response_format=mp3" \
|
| 315 |
+
-F "speed=1.0" \
|
| 316 |
+
-F "min_len=2" \
|
| 317 |
+
-F "max_len=2000" \
|
| 318 |
+
-F "cfg_value=2.0" \
|
| 319 |
+
--output output.mp3
|
| 320 |
+
```
|
| 321 |
+
|
| 322 |
+
#### 4. 文本转语音 - GET方式
|
| 323 |
+
|
| 324 |
+
**voice 参数说明**: 与 POST 方式相同,支持 `"default"`、自定义 `feat_id` 或留空。
|
| 325 |
+
|
| 326 |
+
**使用示例**:
|
| 327 |
+
```bash
|
| 328 |
+
# 使用默认声音
|
| 329 |
+
curl "http://localhost:8100/tts?input=你好,世界!&voice=default&response_format=mp3" \
|
| 330 |
+
--output output.mp3
|
| 331 |
+
|
| 332 |
+
# 使用自定义参考声音
|
| 333 |
+
curl "http://localhost:8100/tts?input=使用自定义声音合成这段文本��&voice=my_custom_voice&response_format=wav" \
|
| 334 |
+
--output custom_output.wav
|
| 335 |
+
|
| 336 |
+
# 不使用参考音频(基础合成)
|
| 337 |
+
curl "http://localhost:8100/tts?input=基础语音合成测试&response_format=mp3" \
|
| 338 |
+
--output basic_output.mp3
|
| 339 |
+
```
|
| 340 |
+
|
| 341 |
+
### 参数说明
|
| 342 |
+
|
| 343 |
+
**通用参数:**
|
| 344 |
+
- `input` (必填): 要转换的文本内容
|
| 345 |
+
- `voice`: 参考音频ID,支持 "default" 或自定义ID
|
| 346 |
+
- `response_format`: 输出格式 (mp3, wav, opus, aac, flac, pcm),默认 mp3
|
| 347 |
+
- `speed`: 语速 (占位符,暂不支持变速)
|
| 348 |
+
- `prompt_text`: 参考音频对应的文本内容
|
| 349 |
+
- `min_len`: 最小音频长度,默认 2
|
| 350 |
+
- `max_len`: 最大音频长度,默认 2000
|
| 351 |
+
- `cfg_value`: CFG系数,默认 2.0
|
| 352 |
+
|
| 353 |
+
### 完整工作流程示例
|
| 354 |
+
|
| 355 |
+
#### 步骤 1: 上传参考音频(一次性操作)
|
| 356 |
+
```python
|
| 357 |
+
import requests
|
| 358 |
+
|
| 359 |
+
# 上传参考音频文件
|
| 360 |
+
with open("my_reference_audio.wav", "rb") as f:
|
| 361 |
+
files = {"prompt_audio": f}
|
| 362 |
+
data = {
|
| 363 |
+
"feat_id": "speaker_john", # 自定义标识符
|
| 364 |
+
"prompt_text": "这是参考音频的文本内容"
|
| 365 |
+
}
|
| 366 |
+
response = requests.post("http://localhost:8100/ref_feat", files=files, data=data)
|
| 367 |
+
|
| 368 |
+
if response.status_code == 200:
|
| 369 |
+
print(f"参考音频上传成功: {response.json()}")
|
| 370 |
+
# 输出: {'feat_id': 'speaker_john', 'patches_shape': [1, 100, 64]}
|
| 371 |
+
else:
|
| 372 |
+
print(f"上传失败: {response.text}")
|
| 373 |
+
```
|
| 374 |
+
|
| 375 |
+
#### 步骤 2: 使用上传的参考音频进行语音合成
|
| 376 |
+
```python
|
| 377 |
+
import requests
|
| 378 |
+
|
| 379 |
+
# 使用已上传的参考音频进行语音合成
|
| 380 |
+
response = requests.post(
|
| 381 |
+
"http://localhost:8100/tts",
|
| 382 |
+
data={
|
| 383 |
+
"input": "使用约翰的声音合成这段文本。",
|
| 384 |
+
"voice": "speaker_john", # 使用步骤1中上传的参考音频ID
|
| 385 |
+
"response_format": "mp3",
|
| 386 |
+
"cfg_value": 2.0
|
| 387 |
+
}
|
| 388 |
+
)
|
| 389 |
+
|
| 390 |
+
if response.status_code == 200:
|
| 391 |
+
with open("john_voice_output.mp3", "wb") as f:
|
| 392 |
+
f.write(response.content)
|
| 393 |
+
print("语音合成成功,文件已保存为 john_voice_output.mp3")
|
| 394 |
+
else:
|
| 395 |
+
print(f"合成失败: {response.text}")
|
| 396 |
+
```
|
| 397 |
+
|
| 398 |
+
#### 步骤 3: 验证参考音频是否可用
|
| 399 |
+
```python
|
| 400 |
+
import requests
|
| 401 |
+
|
| 402 |
+
# 检查服务状态和已上传的参考音频
|
| 403 |
+
response = requests.get("http://localhost:8100/health")
|
| 404 |
+
health_info = response.json()
|
| 405 |
+
|
| 406 |
+
if health_info["initialized"]:
|
| 407 |
+
print("服务正常运行")
|
| 408 |
+
print(f"模型目录: {health_info['models_dir']}")
|
| 409 |
+
print(f"设备类型: {health_info['device_type']}")
|
| 410 |
+
else:
|
| 411 |
+
print(f"服务未初始化: {health_info.get('error', '未知错误')}")
|
| 412 |
+
```
|
| 413 |
+
|
| 414 |
+
### Python 客户端示例
|
| 415 |
+
|
| 416 |
+
#### 基础TTS请求
|
| 417 |
+
```python
|
| 418 |
+
import requests
|
| 419 |
+
|
| 420 |
+
# GET方式简单请求
|
| 421 |
+
response = requests.get(
|
| 422 |
+
"http://localhost:8100/tts",
|
| 423 |
+
params={
|
| 424 |
+
"input": "欢迎使用 VoxCPM ONNX 文本转语音服务。",
|
| 425 |
+
"voice": "default",
|
| 426 |
+
"response_format": "wav"
|
| 427 |
+
}
|
| 428 |
+
)
|
| 429 |
+
|
| 430 |
+
# 保存音频文件
|
| 431 |
+
with open("output.wav", "wb") as f:
|
| 432 |
+
f.write(response.content)
|
| 433 |
+
```
|
| 434 |
+
|
| 435 |
+
#### 上传参考音频
|
| 436 |
+
```python
|
| 437 |
+
import requests
|
| 438 |
+
|
| 439 |
+
# 上传参考音频
|
| 440 |
+
with open("reference.wav", "rb") as f:
|
| 441 |
+
files = {"prompt_audio": f}
|
| 442 |
+
data = {
|
| 443 |
+
"feat_id": "my_custom_voice",
|
| 444 |
+
"prompt_text": "这是参考音频的文本内容"
|
| 445 |
+
}
|
| 446 |
+
response = requests.post("http://localhost:8100/ref_feat", files=files, data=data)
|
| 447 |
+
|
| 448 |
+
print(response.json())
|
| 449 |
+
```
|
| 450 |
+
|
| 451 |
+
#### 使用自定义参考音频进行TTS
|
| 452 |
+
```python
|
| 453 |
+
import requests
|
| 454 |
+
|
| 455 |
+
# 使用已上传的参考音频
|
| 456 |
+
response = requests.post(
|
| 457 |
+
"http://localhost:8100/tts",
|
| 458 |
+
data={
|
| 459 |
+
"input": "使用自定义声音合成这段文本。",
|
| 460 |
+
"voice": "my_custom_voice",
|
| 461 |
+
"response_format": "mp3"
|
| 462 |
+
}
|
| 463 |
+
)
|
| 464 |
+
|
| 465 |
+
with open("custom_voice_output.mp3", "wb") as f:
|
| 466 |
+
f.write(response.content)
|
| 467 |
+
```
|
| 468 |
+
|
| 469 |
+
## 环境变量配置
|
| 470 |
+
|
| 471 |
+
| 变量名 | 说明 | 默认值 |
|
| 472 |
+
|--------|------|--------|
|
| 473 |
+
| `VOX_OUTPUT_DIR` | 输出音频文件目录 | `./outputs` |
|
| 474 |
+
| `VOX_SQLITE_PATH` | 参考特征数据库路径 | `./ref_feats.db` |
|
| 475 |
+
| `VOX_DEVICE` | 推理设备 (cpu/cuda) | `cuda` |
|
| 476 |
+
| `VOX_DEVICE_ID` | GPU 设备 ID | `0` |
|
| 477 |
+
| `VOX_MODELS_DIR` | ONNX 模型目录 | `./models/onnx_models_quantized` |
|
| 478 |
+
| `VOX_TOKENIZER_DIR` | 分词器目录 | `./models/onnx_models_quantized` |
|
| 479 |
+
| `VOX_KEEP_AUDIO_FILES` | 是否保留生成的音频文件 | `false` |
|
| 480 |
+
| `PYTHONPATH` | Python 模块路径 | `./src` |
|
| 481 |
+
|
| 482 |
+
## 高级配置
|
| 483 |
+
|
| 484 |
+
### 导出参数
|
| 485 |
+
|
| 486 |
+
在运行 `export.sh` 时,可以通过环境变量自定义以下参数:
|
| 487 |
+
|
| 488 |
+
| 变量名 | 说明 | 默认值 |
|
| 489 |
+
|--------|------|--------|
|
| 490 |
+
| `MODEL_PATH` | 原始模型路径 | `./VoxCPM-0.5B` |
|
| 491 |
+
| `OUTPUT_DIR` | ONNX 模型输出目录 | `./onnx_models` |
|
| 492 |
+
| `OPSET_VERSION` | ONNX 算子集版本 | `20` |
|
| 493 |
+
| `AUDIO_LENGTH` | 音频长度 | `16000` |
|
| 494 |
+
| `LATENT_LENGTH` | 潜变量长度 | `100` |
|
| 495 |
+
| `LATENT_DIM` | 潜变量维度 | `64` |
|
| 496 |
+
| `TIMESTEPS` | 扩散步数 | `10` |
|
| 497 |
+
| `CFG_VALUE` | CFG 系数 | `2.0` |
|
| 498 |
+
| `RTOL` | 验证相对容差 | `1e-3` |
|
| 499 |
+
| `ATOL` | 验证绝对容差 | `1e-4` |
|
| 500 |
+
| `NUM_TESTS` | 验证测试次数 | `5` |
|
| 501 |
+
|
| 502 |
+
### 自定义参考音频
|
| 503 |
+
|
| 504 |
+
1. 准备参考音频文件(WAV 格式,16kHz)
|
| 505 |
+
2. 使用 `infer.py` 脚本提取特征:
|
| 506 |
+
|
| 507 |
+
```bash
|
| 508 |
+
python infer.py \
|
| 509 |
+
--model_dir ./models/onnx_models_quantized \
|
| 510 |
+
--ref_audio ./reference.wav \
|
| 511 |
+
--ref_text "参考文本内容" \
|
| 512 |
+
--feat_id custom_voice
|
| 513 |
+
```
|
| 514 |
+
|
| 515 |
+
## 技术说明与限制
|
| 516 |
+
|
| 517 |
+
### 当前实现限制
|
| 518 |
+
|
| 519 |
+
1. **Timesteps 参数固定**: 由于将所有 Decode 步骤合并到一个 ONNX 模块中,求解欧拉方程的 `timesteps` 参数被固定。默认值为 10,但测试表明 timesteps=5 也可用,且能显著提升解码速度。
|
| 520 |
+
|
| 521 |
+
2. **权重重复导出**: 当前导出代码会重复导出两份 VoxCPM 权重(Prefill 和 Decode),这会增加模型文件大小。
|
| 522 |
+
|
| 523 |
+
3. **模型优化**: 建议使用 `opt.sh` 脚本对导出的模型进行优化,以减少模型大小并提升推理性能。
|
| 524 |
+
|
| 525 |
+
### 性能优化建议
|
| 526 |
+
|
| 527 |
+
- **调整 Timesteps**: 对于速度敏感的应用,可以尝试 timesteps=5 以提升性能
|
| 528 |
+
- **模型量化**: 使用 ONNX 量化工具进一步优化模型大小
|
| 529 |
+
- **批处理**: 对于批量推理场景,考虑使用动态批处理提升吞吐量
|
| 530 |
+
|
| 531 |
+
## 故障排除
|
| 532 |
+
|
| 533 |
+
### 常见问题
|
| 534 |
+
|
| 535 |
+
**1. ONNX 导出失败**
|
| 536 |
+
- 检查 PyTorch 和 ONNX 版本兼容性
|
| 537 |
+
- 确保模型文件完整且路径正确
|
| 538 |
+
- 验证 CUDA 驱动版本(GPU 版本)
|
| 539 |
+
|
| 540 |
+
**2. Docker 容器启动失败**
|
| 541 |
+
- 检查 NVIDIA Container Toolkit 安装(GPU 版本)
|
| 542 |
+
- 验证端口是否被占用
|
| 543 |
+
- 检查卷挂载路径是否正确
|
| 544 |
+
|
| 545 |
+
**3. 推理速度慢**
|
| 546 |
+
- GPU 版本:检查 CUDA 和 cuDNN 版本
|
| 547 |
+
- CPU 版本:尝试调整 `OMP_NUM_THREADS` 环境变量
|
| 548 |
+
- 确保模型已优化 (`opt.sh`)
|
| 549 |
+
|
| 550 |
+
**4. 音频质量差**
|
| 551 |
+
- 检查输入文本质量
|
| 552 |
+
- 尝试不同的 `cfg_value` 参数
|
| 553 |
+
- 验证参考音频质量(如使用参考音频)
|
| 554 |
+
|
| 555 |
+
### 性能优化
|
| 556 |
+
|
| 557 |
+
**GPU 优化:**
|
| 558 |
+
```bash
|
| 559 |
+
export CUDA_VISIBLE_DEVICES=0
|
| 560 |
+
export OMP_NUM_THREADS=4
|
| 561 |
+
export ONNXRUNTIME_SESSION_OPTIONS_INTRA_OP_NUM_THREADS=4
|
| 562 |
+
```
|
| 563 |
+
|
| 564 |
+
**CPU 优化:**
|
| 565 |
+
```bash
|
| 566 |
+
export OMP_NUM_THREADS=$(nproc)
|
| 567 |
+
export ONNXRUNTIME_SESSION_OPTIONS_INTRA_OP_NUM_THREADS=$(nproc)
|
| 568 |
+
```
|
| 569 |
+
|
| 570 |
+
## 开发指南
|
| 571 |
+
|
| 572 |
+
### 与原始 VoxCPM 项目的关系
|
| 573 |
+
|
| 574 |
+
本项目是 VoxCPM 的 ONNX 导出和推理扩展,专注于:
|
| 575 |
+
- 将 PyTorch 模型导出为 ONNX 格式以提高部署效率
|
| 576 |
+
- 提供基于 ONNX Runtime 的高性能推理引擎
|
| 577 |
+
- 添加 REST API 服务接口
|
| 578 |
+
- 支持容器化部署
|
| 579 |
+
|
| 580 |
+
原始 VoxCPM 项目专注于模型训练和 PyTorch 推理,而本项目专注于生产环境的 ONNX 部署。
|
| 581 |
+
|
| 582 |
+
### 本地开发
|
| 583 |
+
|
| 584 |
+
1. 克隆仓库
|
| 585 |
+
2. 使用 uv 创建开发环境
|
| 586 |
+
3. 安装开发依赖
|
| 587 |
+
4. 运行测试
|
| 588 |
+
|
| 589 |
+
```bash
|
| 590 |
+
# 使用 uv 创建开发环境
|
| 591 |
+
uv sync
|
| 592 |
+
|
| 593 |
+
# 激活虚拟环境
|
| 594 |
+
uv run bash
|
| 595 |
+
# 或
|
| 596 |
+
source .venv/bin/activate
|
| 597 |
+
|
| 598 |
+
# 安装开发依赖
|
| 599 |
+
uv pip install -e .
|
| 600 |
+
|
| 601 |
+
# 运行测试
|
| 602 |
+
pytest tests/
|
| 603 |
+
|
| 604 |
+
# 代码格式化
|
| 605 |
+
black src/
|
| 606 |
+
isort src/
|
| 607 |
+
```
|
| 608 |
+
|
| 609 |
+
### 添加新功能
|
| 610 |
+
|
| 611 |
+
1. 在 `src/onnx_infer/` 中添加新的推理模块
|
| 612 |
+
2. 更新 `src/server/app.py` 中的 API 接口
|
| 613 |
+
3. 添加相应的测试用例
|
| 614 |
+
4. 更新文档
|
| 615 |
+
|
| 616 |
+
## 许可证与免责声明
|
| 617 |
+
|
| 618 |
+
### 版权说明
|
| 619 |
+
- 本项目基于原始 VoxCPM 模型的许可证
|
| 620 |
+
- 使用本项目需遵守 VoxCPM 以及相关方面的版权规定
|
| 621 |
+
- 请确保在使用前阅读并理解相关许可证条款
|
| 622 |
+
|
| 623 |
+
### AI 生成声明
|
| 624 |
+
**重要**: 本项目代码与本文档完全由生成式AI驱动生成!
|
| 625 |
+
|
| 626 |
+
### 使用限制
|
| 627 |
+
- 本项目仅供学习和研究用途
|
| 628 |
+
- 商业使用需获得相关授权
|
| 629 |
+
- 使用者需自行承担使用风险
|
| 630 |
+
|
| 631 |
+
## 致谢
|
| 632 |
+
|
| 633 |
+
- VoxCPM 原始模型和团队
|
| 634 |
+
- ONNX Runtime 项目
|
| 635 |
+
- FastAPI 框架
|
| 636 |
+
|
| 637 |
+
## 支持
|
| 638 |
+
|
| 639 |
+
如遇到问题,请:
|
| 640 |
+
1. 查看本 README 的故障排除部分
|
| 641 |
+
2. 检查 GitHub Issues
|
| 642 |
+
3. 提交新的 Issue 并提供详细信息
|
| 643 |
+
|
| 644 |
+
---
|
| 645 |
+
|
| 646 |
+
**注意**: 本项目专注于 ONNX 推理部署,如需原始 PyTorch 模型训练,请参考 VoxCPM 官方仓库。
|