在语音识别、实时音频处理等场景中,Sherpa 是 k2-fsa 社区推出的轻量级工具集,支持 PyTorch 与 ONNX 双后端。本文将详解基于 Python 3.10 的 CPU 版安装流程,包含 torch、k2、kaldifeat 等核心组件的部署技巧。
一、环境准备
1. 系统与 Python 要求
-
操作系统 :Ubuntu 18.04+/CentOS 7+(需支持
manylinux_2_17
标准) -
Python 版本 :3.10.x(对应 whl 文件的
cp310
标识) -
依赖工具 :
pip ≥ 20.0.0
、wget
(建议提前升级 pip:pip install --upgrade pip
)
2. 虚拟环境建议
为避免依赖冲突,推荐使用虚拟环境隔离安装:
bash
# 创建虚拟环境
python3.10 -m venv sherpa-env
# 激活环境
source sherpa-env/bin/activate
二、组件安装步骤
1. PyTorch 核心依赖(torch 2.5.0)
作为基础计算框架,需优先安装匹配版本的 PyTorch 套件:
bash
pip install torch==2.5.0 torchvision==0.20.0 torchaudio==2.5.0 --index-url https://download.pytorch.org/whl/cpu
说明:指定
cpu
索引源可跳过 GPU 版本下载,节省带宽与磁盘空间。
2. k2 有限状态 transducer 库
k2 提供高效的语音识别解码能力,需离线下载预编译 whl 文件:
下载地址:
本地安装:
bash
pip install k2-1.24.4.dev20250307%2Bcpu.torch2.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
3. kaldifeat 特征提取工具
用于音频特征提取,安装流程与 k2 一致:
下载地址:
本地安装:
bash
pip install kaldifeat-1.25.5.dev20250307%2Bcpu.torch2.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
4. k2_sherpa 核心组件
Sherpa 的 PyTorch 后端实现,需匹配上述组件版本:
下载地址:
本地安装:
bash
pip install k2_sherpa-1.4.0.dev20250307%2Bcpu.torch2.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
5. Sherpa-ONNX 轻量推理引擎
适用于轻量化部署场景,支持直接在线安装:
bash
# 国内用户建议添加清华镜像加速
pip install sherpa-onnx sherpa-onnx-bin -i https://pypi.tuna.tsinghua.edu.cn/simple
三、安装验证
1. 基础功能测试
运行以下代码检查核心组件是否正常导入:
import torch
import k2
import kaldifeat
import sherpa_onnx
print("PyTorch版本:", torch.__version__)
print("k2版本:", k2.__dev_version__)
print("Sherpa-ONNX版本:", sherpa_onnx.__version__)
print("安装成功!")

2. 语音TTS demo 运行
下载预训练模型测试实际功能:
bash
wget https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-zh-hf-fanchen-wnj.tar.bz2
tar xvf vits-zh-hf-fanchen-wnj.tar.bz2
rm vits-zh-hf-fanchen-wnj.tar.bz2
sherpa-onnx-offline-tts \
--vits-model=./vits-zh-hf-fanchen-wnj/vits-zh-hf-fanchen-wnj.onnx \
--vits-dict-dir=./vits-zh-hf-fanchen-wnj/dict \
--vits-lexicon=./vits-zh-hf-fanchen-wnj/lexicon.txt \
--vits-tokens=./vits-zh-hf-fanchen-wnj/tokens.txt \
--output-filename="./kuayue.wav" \
"你好,这是生成的声音。"
四、Python调用
python
#!/usr/bin/env python3
# simple_tts.py
import sys
import time
import logging
import sherpa_onnx
import soundfile as sf
class VitsTTS:
def __init__(self, vits_model: str, vits_tokens: str, vits_lexicon: str, vits_dict_dir: str, num_threads: int = 4):
"""
初始化通用 VITS TTS 引擎。
Args:
vits_model (str): VITS 模型的 ONNX 文件路径 (e.g., ./model/eula.onnx).
vits_tokens (str): tokens.txt 文件路径.
vits_lexicon (str): lexicon.txt 文件路径.
vits_dict_dir (str): 分词词典目录路径.
num_threads (int): 推理时使用的线程数.
"""
# 直接使用传入的路径,不再硬编码文件名
self.vits_model_path = vits_model
self.vits_tokens_path = vits_tokens
self.vits_lexicon_path = vits_lexicon
self.vits_dict_dir_path = vits_dict_dir
# 配置 VITS 模型参数
self.vits_model_config = sherpa_onnx.OfflineTtsVitsModelConfig(
model=self.vits_model_path,
tokens=self.vits_tokens_path,
lexicon=self.vits_lexicon_path,
dict_dir=self.vits_dict_dir_path,
noise_scale=0.667,
noise_scale_w=0.8,
length_scale=1.0
)
# 配置 TTS 引擎
self.model_config = sherpa_onnx.OfflineTtsModelConfig(
vits=self.vits_model_config,
num_threads=num_threads,
debug=False,
)
self.tts_config = sherpa_onnx.OfflineTtsConfig(
model=self.model_config,
)
# 初始化 TTS 引擎
self.tts = sherpa_onnx.OfflineTts(self.tts_config)
logging.info(f"TTS 引擎已使用模型 '{vits_model}' 初始化成功!")
def generate(self, text: str, sid: int = 0, speed: float = 1.0, output_filename: str = "output.wav"):
"""
生成语音并保存为 WAV 文件。
"""
logging.info(f"合成文本: {text}")
logging.info(f"说话人 ID: {sid}, 语速: {speed}")
start = time.time()
# 动态调整语速
self.vits_model_config.length_scale = 1.0 / speed
self.model_config.vits = self.vits_model_config
self.tts_config.model = self.model_config
self.tts = sherpa_onnx.OfflineTts(self.tts_config)
# 生成音频
audio = self.tts.generate(text, sid)
end = time.time()
elapsed_seconds = end - start
audio_duration = len(audio.samples) / audio.sample_rate
real_time_factor = elapsed_seconds / audio_duration
# 保存音频
sf.write(
output_filename,
audio.samples,
samplerate=audio.sample_rate,
subtype="PCM_16",
)
# 打印日志和统计信息
logging.info(f"音频已保存至: {output_filename}")
logging.info(f"采样率: {audio.sample_rate}, 音频时长: {audio_duration:.2f}秒")
print(f"推理耗时: {elapsed_seconds:.3f}秒")
print(f"音频时长: {audio_duration:.3f}秒")
print(f"实时率(RTF): {real_time_factor:.3f}")
if __name__ == "__main__":
logging.basicConfig(
format="%(asctime)s %(levelname)s: %(message)s",
level=logging.INFO,
)
# --- 使用说明 ---
# 运行命令: python3 your_script_name.py --vits-model ./model/theresa.onnx --vits-tokens ./model/tokens.txt ...
# 使用 argparse 接收所有文件路径参数
import argparse
parser = argparse.ArgumentParser(description="通用 VITS TTS 合成工具")
# 必需的模型文件参数
parser.add_argument("--vits-model", type=str, required=True, help="VITS model.onnx 文件路径")
parser.add_argument("--vits-tokens", type=str, required=True, help="tokens.txt 文件路径")
parser.add_argument("--vits-lexicon", type=str, required=True, help="lexicon.txt 文件路径")
parser.add_argument("--vits-dict-dir", type=str, required=True, help="分词词典目录路径")
# 合成参数
parser.add_argument("--text", type=str, required=True, help="要合成的文本")
parser.add_argument("--sid", type=int, default=0, help="说话人 ID")
parser.add_argument("--speed", type=float, default=1.0, help="语速")
parser.add_argument("--output", type=str, default="output.wav", help="输出文件名")
parser.add_argument("--num-threads", type=int, default=4, help="推理线程数")
args = parser.parse_args()
# 初始化 TTS
vits = VitsTTS(
vits_model=args.vits_model,
vits_tokens=args.vits_tokens,
vits_lexicon=args.vits_lexicon,
vits_dict_dir=args.vits_dict_dir,
num_threads=args.num_threads
)
# 生成音频
vits.generate(text=args.text, sid=args.sid, speed=args.speed, output_filename=args.output)
bash
python3 simple_tts.py \
--vits-model ./vits-zh-hf-theresa/theresa.onnx \
--vits-tokens ./vits-zh-hf-theresa/tokens.txt \
--vits-lexicon ./vits-zh-hf-theresa/lexicon.txt \
--vits-dict-dir ./vits-zh-hf-theresa/dict \
--text "真诚就是不欺人也不自欺。热爱就是全心投入并享受其中。" \
--sid 0 \
--output reai-0.wav