引言
几天前,经 Kid 大佬指点,有两个可以纯 CPU 跑的轻量级TTS模型:MOSS-TTS-Nano 0.1B ONNX(100M)模型 和 ZipVoice Sherpa ONNX(123M)模型。具体可以看上周这篇文章里 Kid 大佬的留言。
今天周末了,我去网上看了一下这两个模型,看上去的样子感觉的确不错,鉴于 100M < 123M,我就先把 MOSS-TTS-Nano先给整合了一下到 OddTTS。
MOSS-TTS-Nano 是 OpenMOSS 团队推出的开源多语言微型语音生成模型。仅 0.1B 参数,无需 GPU 即可在普通 CPU 上实时运行,支持语音克隆、流式推理和 ONNX 加速。------ OpenMOSS 官方介绍
相比于上周集成的 Audio8(0.1B RTF 约 3.26x),MOSS-TTS-Nano 在 CPU 上的推理效率明显更高:在禁用文本规范化的极速模式下,RTF 可达到约 0.5 ,这意味着它已经能够胜任类似 小落同学 这样的低延迟实时对话场景。同时,它支持近 20 种语言 和 48 kHz 立体声 输出,音质和语言覆盖度都非常出色。
本次更新已提交至 GitHub,版本号升级至 v1.3.27,默认引擎也切换为 ODDTTS_MOSS_NANO。下面我将从模型概览、技术挑战、性能对比和代码实现等角度,详细解析这次集成。
快速开始使用 OddTTS
OddTTS 是一个功能强大的多引擎语音合成服务,提供统一的 API 接口和友好的 Web 界面,一套接口搞定多种主流 TTS 引擎,包括 EdgeTTS、Kokoro-82M-v1.1-zh、Audio8、ChatTTS、Bert-VITS2、GptSovits v2、MOSS-TTS-Nano 等,同时也支持 OpenAI TTS API 的调用。
- 仓库:
https://github.com/oddmeta/oddtts - 版本:
v1.3.27 - 安装:
pip install oddtts - 运行:
oddtts - 演示:
http://localhost:9001
Python 测试
python
import openai
client = openai.OpenAI(base_url="http://localhost:9001/v1", api_key="dummy")
response = client.audio.speech.create(input="你好,欢迎使用 OddTTS 小奥语音合成服务。")
curl 测试
bash
curl http://127.0.0.1:9001/v1/audio/speech -H "Content-Type: application/json" -d "{\"input\": \"你好,欢迎使用 OddTTS 小奥语音合成服务。\"}" --output speech.mp3
直接听合成的效果
以下音频由 OddTTS 调用 MOSS-TTS-Nano 0.1B ONNX 引擎合成(48 kHz 立体声):
-
oddtts-20260904-mosstts-nano-100m-onnx.wav
这个声音总觉得有点。。。不知道怎么描述。。。
-
oddtts-20260904-mosstts-nano-中英混合-超长停顿问题.mp3
在前面的中文和后面的英文中间出现一个长停顿,不确定原因是什么。
一、MOSS-TTS-Nano 模型概览
1.1 基本信息
| 特性 | MOSS-TTS-Nano 0.1B ONNX |
|---|---|
| 团队 | OpenMOSS(复旦大学 NLP 实验室 + MOSI.AI) |
| 参数量 | ~0.1B(约 1 亿参数) |
| 模型文件大小 | 不到 300 MB |
| 架构 | Audio Tokenizer + LLM 纯自回归 |
| 音频分词器 | MOSS-Audio-Tokenizer-Nano(2000万参数) |
| 量化方式 | ONNX FP16 / INT8(Runtime 自动适配) |
| 采样率 | 48000 Hz 立体声 |
| 支持语言 | 近 20 种 |
| 硬件要求 | 4 核 CPU 即可流畅运行,无需 GPU |
| 开源协议 | Apache 2.0 |
1.2 核心技术架构
MOSS-TTS-Nano 采用创新的 Audio Tokenizer + LLM 纯自回归流水线:
- 文本预处理:输入文本经文本正则化与分词处理(可选 WeTextProcessing 进行中文数字读法规范化)。
- 音频编码:参考音频(提示语音)经音频分词器编码为离散 Token 流。
- 自回归生成:轻量级语言模型以文本 Token 和音频 Token 为条件,自回归生成音频 Token。
- 音频解码 :音频分词器解码器将 Token 流实时还原为 48 kHz、双声道 波形。
其中,MOSS-Audio-Tokenizer-Nano 音频分词器仅 2000 万参数,支持将 48 kHz 立体声音频压缩为 12.5 Hz 的 token 流,采用 RVQ(残差向量量化)和 16 个码本,是高保真音频压缩的关键。
1.3 支持的近 20 种语言
MOSS-TTS-Nano 支持以下语言(部分列举):
| 语言 | 代码 | 语言 | 代码 | 语言 | 代码 |
|---|---|---|---|---|---|
| 中文 | zh | 英语 | en | 德语 | de |
| 西班牙语 | es | 法语 | fr | 日语 | ja |
| 意大利语 | it | 韩语 | ko | 俄语 | ru |
| 阿拉伯语 | ar | 波兰语 | pl | 葡萄牙语 | pt |
| 捷克语 | cs | 丹麦语 | da | 瑞典语 | sv |
| 希腊语 | el | 土耳其语 | tr | 匈牙利语 | hu |
| 波斯语 | fa | ... |
1.4 ONNX 版本的优势
OddTTS 选择的是 ONNX 版本 而非 PyTorch 版本,原因如下:
| 维度 | PyTorch 版 | ONNX 版 |
|---|---|---|
| 推理框架 | PyTorch | ONNX Runtime |
| 深度学习环境 | 需要 PyTorch 全家桶 | 无需 PyTorch 依赖 |
| CPU 部署 | 可以运行 | 更适合、效率更高 |
| 推理效率 | 基准 | 约为 PyTorch 版的 2 倍 |
| 部署体积 | 大(含 PyTorch) | 更轻量 |
| 集成难度 | 较高 | 较低,更易嵌入软件 |
二、技术挑战与解决方案
2.1 外部仓库依赖与 Vendoring
问题 :MOSS-TTS-Nano 的推理依赖其官方仓库中的 onnx_tts_runtime 模块,但该模块并未发布到 PyPI,直接 pip install 无法获得。
解决方案 :在 setup.py 中自定义 build_py 命令,在构建 wheel 时自动将 moss-tts-nano 仓库 vendoring 到 oddtts/vendor/moss-tts-nano/ 目录下:
python
class build_py(_build_py):
def run(self):
super().run()
self._vendor_moss_nano()
def _vendor_moss_nano(self):
# 优先使用本地已有的源码,否则 git clone
# 复制时排除 models/、__pycache__/ 等大目录
ignore = shutil.ignore_patterns(
"models", "__pycache__", "*.egg-info",
"generated_audio", ".cache", ".git",
"*.onnx", "*.data", "*.wav",
)
shutil.copytree(src, dst, ignore=ignore, dirs_exist_ok=True)
这样,用户通过 pip install oddtts 安装后,onnx_tts_runtime 模块即可通过 oddtts/vendor/moss-tts-nano/ 自动导入,无需手动克隆仓库。
2.2 模型下载双源策略
模型下载顺序:ModelScope → HuggingFace
考虑到 OddTTS 主要面向国内用户,MOSS-TTS-Nano 的两个 ONNX 模型均优先从 ModelScope 下载,失败则自动回退 HuggingFace:
| 模型 | ModelScope | HuggingFace |
|---|---|---|
| TTS 模型 | openmoss/MOSS-TTS-Nano-100M-ONNX |
OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX |
| Codec 模型 | openmoss/MOSS-Audio-Tokenizer-Nano-ONNX |
OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX |
2.3 Windows 下 WeTextProcessing 的编译依赖
问题 :MOSS-TTS-Nano 支持通过 WeTextProcessing 进行中文文本规范化(如将阿拉伯数字转为中文读法),但 WeTextProcessing 依赖 pynini,而 Windows 上没有预编译的 pynini wheel,直接 pip install 会因缺少 MSVC 编译器而失败。
解决方案:
- 在 OddTTS 的
tts_moss_nano.py中,将 WeTextProcessing 设为可选依赖:即使未安装,合成依然能正常运行,只是缺少中文数字读法规范化。 - 在测试脚本
tests/test_moss-tts_0_1b_onnx.py中,针对 Windows 自动尝试通过conda-forge安装预编译的pynini:
bash
conda install -c conda-forge pynini=2.1.6.post1 -y
pip install WeTextProcessing
2.4 Runtime 初始化与模块路径处理
问题 :从源码运行时,onnx_tts_runtime 模块可能位于 tests/moss-tts-nano/ 或 moss-tts-nano/ 目录;而通过 pip 安装后,它位于 oddtts/vendor/moss-tts-nano/ 目录。需要兼容这两种场景。
解决方案 :在 MossNanoAPI._init_runtime() 中,优先从 pip 安装后的 vendoring 目录导入,并动态插入 sys.path;若未找到,则给出明确的错误提示和操作指引。
三、性能对比测试
3.1 测试环境
- 测试文本: 55 字中文文本(含中英混读)
- 测试条件: 纯 CPU,WAV 格式
- 硬件环境: 普通 PC(无 GPU)
- 引擎版本: OddTTS v1.3.27
3.2 性能数据
| 引擎 | 采样率 | 文本长度 | 合成耗时 | 音频时长 | RTF(实时率) |
|---|---|---|---|---|---|
| Kokoro v1.1 | 24000 Hz | 55字 | 2.68秒 | 8.18秒 | 0.33 |
| MOSS-TTS-Nano ONNX | 48000 Hz | 55字 | 10.59秒 | 9.20秒 | 1.15 |
| MOSS-TTS-Nano ONNX 极速模式 | 48000 Hz | 55字 | ~4.6秒 | 9.20秒 | ~0.50 |
| Audio8 0.1B ONNX INT8 | 44100 Hz | 55字 | 27.85秒 | 8.54秒 | 3.26 |
极速模式 参数:
sample_mode=greedy,do_sample=False,关闭 WeTextProcessing,启用多线程(最多 8 线程)。
测试数据
MOSS-TTS-Nano ONNX 基础合成速度(48kHz)
bash
ONNX 基础合成 10.59s 9.20s 1.15x
ONNX 语音克隆 12.07s 10.40s 1.16x
ONNX 中文 10.57s 9.20s 1.15x
ONNX 英文 11.23s 10.40s 1.08x
ONNX 日文 15.21s 18.32s 0.83x
ONNX 韩文 10.54s 9.04s 1.17x
3.3 性能分析
MOSS-TTS-Nano ONNX(标准模式):
- 合成速度约为 Audio8 0.1B 的 3 倍快(RTF 1.15 vs 3.26)。
- 比 Kokoro v1.1 慢约 3.5 倍(RTF 1.15 vs 0.33),但采样率更高(48kHz vs 24kHz),且支持语音克隆和多语言。
MOSS-TTS-Nano ONNX(极速模式):
- RTF 约 0.5,已经非常接近实时,可用于低延迟场景如语音助手、实时对话。
- 牺牲了一部分采样多样性(greedy 解码),但在实际听感上差异不大。
Audio8 0.1B ONNX INT8:
- 虽然同样支持多语言和语音克隆,但 RTF 高达 3.26,难以用于实时场景,更适合离线批处理。
四、代码实现细节
4.1 引擎注册与调度
在 oddtts_params.py 中新增枚举值:
python
class ODDTTS_TYPE(Enum):
ODDTTS_MOSS_NANO = 10
@property
def description(self):
return {
self.ODDTTS_MOSS_NANO: 'MOSS-TTS-Nano 0.1B ONNX - OpenMOSS 轻量级多语言TTS(纯CPU,近20种语言,48kHz)'
}
在 base_tts_driver.py 中注册策略:
python
from .tts_moss_nano import MossNanoAPI
def get_strategy(self, tts_type: ODDTTS_TYPE) -> BaseTTS:
tts = BaseTTS()
elif tts_type == ODDTTS_TYPE.ODDTTS_MOSS_NANO:
tts.client = MossNanoAPI()
return tts
4.2 合成参数配置
MossNanoAPI 使用 OnnxTtsRuntime.synthesize() 进行合成,关键参数如下:
python
self.runtime.synthesize(
text=text,
voice=voice, # 当前仅内置 "Junhao"
output_audio_path=tmp_path,
sample_mode="fixed", # 或 "greedy" 用于极速模式
do_sample=True, # False 可进一步加速
streaming=True,
enable_wetext=has_tn, # 是否启用中文文本规范化
enable_normalize_tts_text=has_tn,
)
注意 :TTSParams 中的 rate、volume、pitch 参数对 MOSS-TTS-Nano 引擎无效,仅 voice 和 response_format 有效。
4.3 流式生成实现
虽然 generate_tts_stream() 方法返回的是异步生成器,但受限于底层 OnnxTtsRuntime 的同步 API,当前实现是先完整合成音频,再作为单个 chunk 返回:
python
async def generate_tts_stream(self, text: str, tts_params: TTSParams):
audio_numpy = self._synthesize(text, tts_params) # 先完整合成
audio_data = convert_audio_format(...)
yield audio_data # 再返回结果
这是因为 ONNX Runtime 目前返回的是完整音频数组。后续如果官方支持真正的流式 token 输出,OddTTS 可以进一步实现低延迟的逐段返回。
五、实际应用指南
5.1 安装与配置
bash
# 安装 OddTTS(会自动包含 MOSS-TTS-Nano 的 vendoring 依赖)
pip install oddtts
# 启动服务(首次启动会自动下载 ONNX 模型)
oddtts
如果希望启用中文文本规范化(数字读法优化),额外执行:
bash
conda install -c conda-forge pynini=2.1.6.post1 -y
pip install WeTextProcessing
5.2 切换引擎
在 Web 界面或配置文件中切换默认引擎:
python
# oddtts_config.py
"tts_type": ODDTTS_TYPE.ODDTTS_MOSS_NANO,
5.3 API 调用示例
python
import requests
# 生成语音文件
response = requests.post("http://localhost:9001/v1/audio/speech", json={
"input": "欢迎使用 MOSS-TTS-Nano 语音合成系统",
"voice": "Junhao",
"response_format": "wav",
"model": "oddtts-moss-nano"
})
# 保存音频文件
with open("output.wav", "wb") as f:
f.write(response.content)
5.4 独立测试脚本
OddTTS 项目也提供了独立的测试脚本,无需启动服务端即可验证 MOSS-TTS-Nano:
bash
conda activate oddtts
python tests/test_moss-tts_0_1b_onnx.py
该脚本会自动:
- 克隆 MOSS-TTS-Nano 官方仓库(如未安装)
- 安装 ONNX 最小依赖(跳过 PyTorch)
- 下载 ONNX 模型(优先 ModelScope)
- 执行基础合成、语音克隆、多语言、CLI 生成等测试项
六、总结与展望
6.1 本次更新的意义
- 实时场景突破:MOSS-TTS-Nano 在极速模式下 RTF 约 0.5,标志着 OddTTS 首次拥有能在普通 CPU 上接近实时运行的语音克隆引擎,填补了 Audio8 在实时性上的不足。
- 多语言与音质兼得:支持近 20 种语言,输出 48 kHz 立体声,在语言覆盖度和音质上都达到了较高水准。
- 部署简化 :通过 setup.py 的自定义 vendoring 机制,用户无需手动克隆仓库或配置复杂环境,
pip install oddtts即可获得完整功能。 - 生态扩展:为 OddTTS 增加了又一款重量级引擎,与 Kokoro(极速中文)、Audio8(高质多语言离线)、MOSS-TTS-Nano(实时语音克隆)形成互补。
6.2 性能权衡
- Kokoro v1.1:RTF 最低(0.33),中文场景首选,但不支持语音克隆。
- MOSS-TTS-Nano ONNX 极速模式:RTF ~0.5,支持语音克隆 + 20 种语言,实时场景首选。
- MOSS-TTS-Nano ONNX 标准模式:RTF ~1.15,音质更自然,适合对延迟不敏感的在线服务。
- Audio8 0.1B/0.6B:音质和语言支持同样优秀,但 RTF 较高(3.26~4.93),适合离线批处理。
6.3 后续优化方向
- 真流式输出:等待 MOSS-TTS-Nano 官方支持逐 token 流式解码,进一步降低首音延迟。
- 更多预设音色 :当前仅内置
Junhao一个音色,后续可通过参考音频扩展更多预设音色列表。 - 参数暴露 :将
sample_mode、do_sample、temperature等生成参数通过 API 暴露,供用户按需调节。 - GPU 加速 :虽然定位纯 CPU,但后续可探索
onnxruntime-gpu后端,进一步压榨性能。
6.4 社区贡献
欢迎开发者参与 OddTTS 的开发和优化:
- GitHub: https://github.com/oddmeta/oddtts
- 问题反馈: 提交 Issue 或 Pull Request
- 功能建议: 在 GitHub Discussions 中讨论
结语
MOSS-TTS-Nano 的集成是 OddTTS 在「轻量级、纯 CPU、实时语音克隆」方向上的一次重要尝试。0.1B 参数却能输出 48 kHz 立体声、支持近 20 种语言、实现 RTF 0.5 的实时推理,这让我们看到了小模型在端侧和实时场景中的巨大潜力。期待更多开发者加入,共同推动语音合成技术的普及与落地。
相关资源: