OddTTS更新:集成MOSS-TTS-Nano 0.1B ONNX,纯CPU实时语音克隆与20种语言支持

引言

几天前,经 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 引擎,包括 EdgeTTSKokoro-82M-v1.1-zhAudio8ChatTTSBert-VITS2GptSovits v2MOSS-TTS-Nano 等,同时也支持 OpenAI TTS API 的调用。

  • 仓库: https://github.com/oddmeta/oddtts
  • 版本: v1.3.27
  • 安装: pip install oddtts
  • 运行: oddtts
  • 演示: http://localhost:9001

Python 测试

import openai
client = openai.OpenAI(base_url="http://localhost:9001/v1", api_key="dummy")
response = client.audio.speech.create(input="你好,欢迎使用 OddTTS 小奥语音合成服务。")

curl 测试

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 纯自回归流水线:

  1. 文本预处理:输入文本经文本正则化与分词处理(可选 WeTextProcessing 进行中文数字读法规范化)。
  2. 音频编码:参考音频(提示语音)经音频分词器编码为离散 Token 流。
  3. 自回归生成:轻量级语言模型以文本 Token 和音频 Token 为条件,自回归生成音频 Token。
  4. 音频解码:音频分词器解码器将 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 版
推理框架PyTorchONNX 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/ 目录下:

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:

模型ModelScopeHuggingFace
TTS 模型openmoss/MOSS-TTS-Nano-100M-ONNXOpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX
Codec 模型openmoss/MOSS-Audio-Tokenizer-Nano-ONNXOpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX

2.3 Windows 下 WeTextProcessing 的编译依赖

问题:MOSS-TTS-Nano 支持通过 WeTextProcessing 进行中文文本规范化(如将阿拉伯数字转为中文读法),但 WeTextProcessing 依赖 pynini,而 Windows 上没有预编译的 pynini wheel,直接 pip install 会因缺少 MSVC 编译器而失败。

解决方案

  1. 在 OddTTS 的 tts_moss_nano.py 中,将 WeTextProcessing 设为可选依赖:即使未安装,合成依然能正常运行,只是缺少中文数字读法规范化。
  2. 在测试脚本 tests/test_moss-tts_0_1b_onnx.py 中,针对 Windows 自动尝试通过 conda-forge 安装预编译的 pynini
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.124000 Hz55字2.68秒8.18秒0.33
MOSS-TTS-Nano ONNX48000 Hz55字10.59秒9.20秒1.15
MOSS-TTS-Nano ONNX 极速模式48000 Hz55字~4.6秒9.20秒~0.50
Audio8 0.1B ONNX INT844100 Hz55字27.85秒8.54秒3.26

极速模式参数:sample_mode=greedydo_sample=False,关闭 WeTextProcessing,启用多线程(最多 8 线程)。

测试数据

MOSS-TTS-Nano ONNX 基础合成速度(48kHz)

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 中新增枚举值:

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 中注册策略:

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() 进行合成,关键参数如下:

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 中的 ratevolumepitch 参数对 MOSS-TTS-Nano 引擎无效,仅 voiceresponse_format 有效。

4.3 流式生成实现

虽然 generate_tts_stream() 方法返回的是异步生成器,但受限于底层 OnnxTtsRuntime 的同步 API,当前实现是先完整合成音频,再作为单个 chunk 返回

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 安装与配置

# 安装 OddTTS(会自动包含 MOSS-TTS-Nano 的 vendoring 依赖)
pip install oddtts

# 启动服务(首次启动会自动下载 ONNX 模型)
oddtts

如果希望启用中文文本规范化(数字读法优化),额外执行:

conda install -c conda-forge pynini=2.1.6.post1 -y
pip install WeTextProcessing

5.2 切换引擎

在 Web 界面或配置文件中切换默认引擎:

# oddtts_config.py
"tts_type": ODDTTS_TYPE.ODDTTS_MOSS_NANO,

5.3 API 调用示例

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:

conda activate oddtts
python tests/test_moss-tts_0_1b_onnx.py

该脚本会自动:

  1. 克隆 MOSS-TTS-Nano 官方仓库(如未安装)
  2. 安装 ONNX 最小依赖(跳过 PyTorch)
  3. 下载 ONNX 模型(优先 ModelScope)
  4. 执行基础合成、语音克隆、多语言、CLI 生成等测试项

六、总结与展望

6.1 本次更新的意义

  1. 实时场景突破:MOSS-TTS-Nano 在极速模式下 RTF 约 0.5,标志着 OddTTS 首次拥有能在普通 CPU 上接近实时运行的语音克隆引擎,填补了 Audio8 在实时性上的不足。
  2. 多语言与音质兼得:支持近 20 种语言,输出 48 kHz 立体声,在语言覆盖度和音质上都达到了较高水准。
  3. 部署简化:通过 setup.py 的自定义 vendoring 机制,用户无需手动克隆仓库或配置复杂环境,pip install oddtts 即可获得完整功能。
  4. 生态扩展:为 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 后续优化方向

  1. 真流式输出:等待 MOSS-TTS-Nano 官方支持逐 token 流式解码,进一步降低首音延迟。
  2. 更多预设音色:当前仅内置 Junhao 一个音色,后续可通过参考音频扩展更多预设音色列表。
  3. 参数暴露:将 sample_modedo_sampletemperature 等生成参数通过 API 暴露,供用户按需调节。
  4. GPU 加速:虽然定位纯 CPU,但后续可探索 onnxruntime-gpu 后端,进一步压榨性能。

6.4 社区贡献

欢迎开发者参与 OddTTS 的开发和优化:

结语

MOSS-TTS-Nano 的集成是 OddTTS 在「轻量级、纯 CPU、实时语音克隆」方向上的一次重要尝试。0.1B 参数却能输出 48 kHz 立体声、支持近 20 种语言、实现 RTF 0.5 的实时推理,这让我们看到了小模型在端侧和实时场景中的巨大潜力。期待更多开发者加入,共同推动语音合成技术的普及与落地。


相关资源

Leave a comment

Your email address will not be published. Required fields are marked *