s2.cpp 项目背景与概述
1. 一个缺口:S2 Pro 语音质量很好,但只能在 Python 里跑
2025 年以来,基于”语义 token + 声学 codec”的文本转语音(TTS)模型迅速成熟。Fish Audio 推出的 S2 Pro 采用 Dual-AR(双自回归) 架构:一个大 Transformer 逐帧预测语义 token,一个小 Transformer 紧接着逐码本解码声学 token,再经神经音频 codec 还原成 44.1 kHz 波形。官方推理链路基于 PyTorch/HuggingFace,部署时要装 Python、torch、一堆 CUDA 库,体积大、启动慢,嵌入桌面应用和服务端都不方便。
社区开发者 rodrigomatta 发起的 s2.cpp 填的就是这个缺口:用纯 C++17、基于 ggml 张量库,把 S2 Pro 的完整推理链路——分词、Dual-AR 生成、codec 编解码、WAV 输出——全部重写一遍。构建完成后运行时完全不需要 Python,并支持 CPU、Vulkan、CUDA、Metal 四种后端。项目自我定位见 README.md:6:
Fish Audio’s S2 Pro Dual-AR text-to-speech model running locally via a pure C++/GGML inference engine with CPU, Vulkan, CUDA, and Metal GPU backends. No Python runtime required after build.
项目被明确标注为 ALPHA 实验性软件(README.md:3-4):接口可能变动、不承诺生产可用,但核心链路已经完整,且提供 CLI、HTTP 服务和 C ABI 三种使用方式。
2. 它在整个流水线中的位置
一次完整的 TTS 推理,s2.cpp 全部在进程内完成(README.md:22):
文本
│ Qwen3 BPE 分词(tokenizer.json)
▼
token 序列(含对话模板 / 参考音频占位)
│ Slow-AR:36 层 Qwen3 风格 Transformer(4.13B 参数,持久 KV cache)
▼
每帧 1 个语义 token + 隐状态向量
│ Fast-AR:4 层小 Transformer(0.42B 参数,无 KV cache)
▼
每帧 10 个码本 token(1 语义 + 9 残差 RVQ),码本大小 4096
│ 音频 codec:卷积编码器/解码器 + 残差向量量化
▼
44.1 kHz 波形 → WAV / PCM(可流式分块输出)
三个核心组件各自独立、又共享同一个 GGUF 文件:
| 组件 | 角色 | 实现文件 |
|---|---|---|
| Slow-AR | 36 层大 Transformer,文本 → 语义 token,GQA + RoPE(1M) + QK norm | s2_model.cpp |
| Fast-AR | 4 层小 Transformer,每个语义步解码 10 个声学码本 | s2_model.cpp |
| Audio Codec | 卷积编解码器 + RVQ(10 × 4096),波形 ↔ 离散码 | s2_codec.cpp |
参数量合计约 4.56B(Slow-AR 4.13B + Fast-AR 0.42B),架构说明见 README.md:526-534。
3. 三种使用形态
s2.cpp 虽然是个推理引擎,但交付的形态不止一个命令行工具:
-
CLI 可执行文件
s2:单次合成、声音克隆、流式写文件。参数解析见 main.cpp:158-226,例如:./s2 --model s2-pro-q4_k_m.gguf --cuda 0 \ --text "你好,世界" --output out.wav -
HTTP 服务:
--server启动,基于内嵌的 cpp-httplib,只暴露一个POST /generatemultipart 接口,支持一次性 WAV、流式 WAV、实时分块 PCM。服务实现见 s2_server.cpp;同时提供 OpenAPI 规范。 -
导出库(C ABI):
s2_shared/s2_static两个目标,通过 s2_export_api.h 暴露不抛异常的 C 接口(不透明指针 + Alloc/Release),仓库自带 Python(ctypes)、C#、Go 调用示例。
4. 模型文件与许可证
- GGUF 权重不在仓库内,由社区从官方 checkpoint 转换,发布在 HuggingFace 的 rodrigomt/s2-pro-gguf,从 f16(9.9 GB)到 q2_k(2.6 GB)共 7 个量化档(README.md:32-40)。
- 转换脚本 unified_export_gguf.py 是仓库里唯一与 Python 相关的部分,且只用于离线导出,运行时不参与。
- 一个 GGUF 同时装下 Transformer 和 codec(README.md:42);量化时 codec 张量(
c.*)保留 F16,只量化 AR 部分。 - 许可证需要特别注意:权重遵循 Fish Audio Research License(Copyright © 39 AI, INC.),研究/非商业免费,商业使用需向 Fish Audio 另行授权;引擎源码作为衍生作品同样适用该许可证(README.md:571-584)。
5. 本分析的范围与组织
本分析基于 s2.cpp 仓库固定提交 2c33261(以 git submodule 形式钉在 s2cpp/ 目录),所有代码链接均指向该提交,发布时由 CI 重写为 GitHub 上的固定 blob URL。全文按”从整体到细节”的顺序组织:
| 章节 | 内容 |
|---|---|
| 02 整体架构与数据流 | 张量形状、双 AR 交接、码行偏移约定 |
| 03 代码结构与构建 | 目录布局、CMake、ggml 子模块与本地补丁 |
| 04 模型加载与 GGUF | 元数据默认值、权重放置、多 buffer 切分 |
| 05 Slow-AR 计算图 | eval_cached、GQA、KV cache、tied embedding |
| 06 Fast-AR 与生成主循环 | fast_decode、generate 主循环、RAS |
| 07 采样器 | top-k/top-p/温度的具体实现 |
| 08 音频编解码器 | 卷积 codec、RVQ、余弦 VQ、缓存图 |
| 09 语音克隆与声音档案 | 参考音频编码、.s2voice、对话模板 |
| 10 流水线与流式合成 | stride/holdback/context、codec 自动选型 |
| 11 HTTP 服务 | /generate、503 单并发、分块与分句 |
| 12 导出库 API | C ABI、回调式流式、各语言示例 |
关键文件
| 文件 | 行数 | 职责 |
|---|---|---|
| README.md | 623 | 项目说明、模型选型、架构与限制 |
| src/main.cpp | 340 | CLI 入口与参数解析 |
| src/s2_model.cpp | 1257 | Slow-AR / Fast-AR 模型与计算图 |
| src/s2_codec.cpp | 1447 | 音频 codec 全部实现 |
| src/s2_pipeline.cpp | 1205 | 组装流水线、流式窗口解码 |
| src/s2_generate.cpp | 218 | Dual-AR 生成主循环 |