GitHub - pwilkin/openmoss: 基于GGML的OpenMOSS纯C++管道
摘要
OpenMOSS 是 MOSS-TTS 的独立 C++/GGML 移植版本,提供了一个自包含的二进制文件,用于文本转语音和语音克隆,基于 Qwen3-8B 骨干网络和 32 个 RVQ 音频码本。它包含用于一次性合成的 CLI 和用于重复生成的 HTTP 服务器。
查看缓存全文
缓存时间: 2026/05/15 15:02
pwilkin/openmoss 来源: https://github.com/pwilkin/openmoss
openmoss-ggml
一个独立的 C++/GGML (https://www.github.com/ggml-org/ggml) 移植版,基于 MOSS-TTS-Delay (https://huggingface.co/OpenMOSS-Team/MOSS-TTS) —— 包含 Qwen3-8B 语言骨干网络 + 32 个 RVQ 音频码本 + 一个 1.6 B 参数的纯 Transformer 音频编解码器,所有功能均可从单个自包含二进制文件运行。Qwen3 骨干网络由 libllama 托管(因此您可以免费获得 llama.cpp 的所有量化以及 CUDA / CPU / Vulkan 后端);嵌入层、语言模型头以及编解码器的编码器/解码器是我们自行构建的 GGML 计算图。
提供两个入口点:
moss-tts-cli— 一次性合成。加载模型,合成一段语音,写入 WAV 文件后退出。moss-tts-server— 模型常驻内存,并暴露 HTTP 接口,用于重复生成(TTS 和语音克隆)。
在单个 16 GB GPU(RTX 5060 Ti)上,Q8_0 骨干网络生成约 10 秒语音的实际耗时约 4 秒;编解码器运行速度约为实时的 50 倍。有关详细的功能矩阵、流水线示意图和基准测试数据,请参阅 docs/STATUS.md。
快速开始
# 1. 构建(假设已有一个构建好的 llama.cpp 目录)
cmake -B build -DLLAMA_CPP_DIR=/path/to/llama.cpp -DGGML_CUDA=ON
cmake --build build -j
# 2. 转换权重(仅需要执行一次)
python scripts/convert_hf_to_gguf.py \
--moss-tts OpenMOSS-Team/MOSS-TTS \
--codec OpenMOSS-Team/MOSS-Audio-Tokenizer \
--output weights/moss-tts.gguf
# 3. (可选)量化骨干网络 —— 保持嵌入表为 f16
/path/to/llama.cpp/build/bin/llama-quantize \
--token-embedding-type f16 \
weights/moss-tts.gguf weights/moss-tts-q8_0.gguf Q8_0
# 4. 合成语音
./build/moss-tts-cli \
--model weights/moss-tts-q8_0.gguf \
--text "Hello, world!" \
--output out.wav
构建
前置条件:
- 一个已构建的 llama.cpp 目录(包含
libllama.so、libggml*.so,以及ggml/include/和include/下的头文件)。使用您需要的后端进行编译(例如-DGGML_CUDA=ON用于 NVIDIA GPU)。 - CMake ≥ 3.18,支持 C++17 的编译器。
nlohmann/json.hpp(仅需要头文件;在 Debian/Ubuntu 上:apt install nlohmann-json3-dev)。- HTTP 服务器依赖于内嵌的
cpp-httplibv0.18.7 副本(third_party/cpp-httplib/httplib.h);无需额外的系统依赖。
cmake -B build \
-DLLAMA_CPP_DIR=/devel/tools/llama.cpp \
-DGGML_CUDA=ON
cmake --build build -j
输出文件:
build/moss-tts-clibuild/moss-tts-serverbuild/moss-tts-info、build/moss-tts-compute-test、build/moss-codec-roundtrip(诊断工具)
转换权重
转换器会生成 两个 并存的 GGUF 文件:
moss-tts.gguf— Qwen3-8B 骨干网络,纯 Qwen3 布局,可直接由 libllama 加载。moss-tts.extras.gguf— 辅助文件:32 个音频嵌入表、33 个 LM 头、编解码器编码器 / RVQ 码本 / 编解码器解码器,以及moss.*的 KV 命名空间(帧率、特殊 token ID 等)。由我们加载,而非 libllama。
pip install safetensors numpy huggingface_hub gguf
python scripts/convert_hf_to_gguf.py \
--moss-tts OpenMOSS-Team/MOSS-TTS \
--codec OpenMOSS-Team/MOSS-Audio-Tokenizer \
--output weights/moss-tts.gguf \
--llama-cpp-dir /path/to/llama.cpp \
--backbone-dtype f16
有用的选项:--cache-dir 指定 HF 缓存目录,--scratch-dir/--keep-scratch 用于检查中间提取出的骨干网络,--skip-extract 可以在已经运行过转换的情况下重用先前提取的骨干网络。
量化
量化骨干网络的方式与量化任何 GGUF 文件相同,但需要传递 --token-embedding-type f16:嵌入表通过 ggml_get_rows 索引,而该操作在 CUDA 上不支持量化的 src0,因此必须保持 f16。
llama-quantize --token-embedding-type f16 \
weights/moss-tts.gguf weights/moss-tts-q8_0.gguf Q8_0 # ~8.7 GB,已端到端验证
llama-quantize --token-embedding-type f16 \
weights/moss-tts.gguf weights/moss-tts-q4km.gguf Q4_K_M # ~4.7 GB
辅助文件 不 进行量化 —— 将 moss-tts.extras.gguf 与您选择的骨干网络文件放在同一目录下。CLI 和服务器通过将骨干网络文件名的 .gguf 后缀替换为 .extras.gguf 来查找辅助文件。
CLI 用法
moss-tts-cli --model <模型文件> --text "<文本>" [选项]
常用选项:
| 参数 | 含义 |
|---|---|
--text "..." | 要合成的文本(必填) |
--output PATH | 输出 WAV 文件路径(默认为 out.wav,16 位单声道 @ 24 kHz) |
--reference PATH | 用于语音克隆的参考 WAV 文件 —— 提取说话人特征并拼接到提示中 |
--instruction "..." | 语音/风格描述(语音生成模式,无参考音频时使用) |
--language CODE | 语言提示(en / zh / …) |
--tokens N | 近似音频长度(以 token 计;1 秒 ≈ 12.5 个 token) |
--max-new-tokens N | 生成上限(默认 4096) |
--main-gpu N | 将模型固定到索引为 N 的 GPU(默认:自动选择空闲显存最多的 GPU) |
--n-gpu-layers N | 骨干网络 GPU 卸载层数(默认:全部) |
--no-flash-attn | 禁用 flash attention |
--skip-codec | 不加载编解码器张量;仅输出 codes(调试用,可节省约 3.4 GB) |
普通 TTS
./build/moss-tts-cli \
--model weights/moss-tts-q8_0.gguf \
--text "The quick brown fox jumps over the lazy dog." \
--max-new-tokens 600 \
--output out.wav
语音克隆
通过 --reference 传入参考 WAV 文件。编解码器编码器将其转换为 32 码本的 codes,然后拼接到用户端音频块的聊天提示中,模型会以该语音继续生成。
./build/moss-tts-cli \
--model weights/moss-tts-q8_0.gguf \
--text "A different sentence in the cloned voice." \
--reference samples/alice.wav \
--max-new-tokens 600 \
--output cloned.wav
支持任意采样率 —— 内部会将 WAV 线性重采样为 24 kHz。通常几秒钟的清晰语音就足够了。
服务器用法
./build/moss-tts-server --model weights/moss-tts-q8_0.gguf --host 0.0.0.0 --port 8080
moss-tts-server 支持与 CLI 相同的 --main-gpu、--n-gpu-layers、--no-flash-attn 和 --skip-codec 参数。生成请求通过单个互斥锁串行化(libllama 状态不可重入);并发请求会优雅排队。
接口
GET /health— 健康检查,返回ok。GET /info— JSON 格式返回模型维度、编解码器状态和请求计数器。POST /tts— 输入 JSON,输出audio/wav(失败时输出text/plain并包含错误信息)。
POST /tts 请求体
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
text | string | 是 | 要合成的文本 |
instruction | string | 否 | 语音/风格描述(语音生成模式) |
language | string | 否 | 语言提示 |
tokens | int | 否 | 近似长度(1 秒 ≈ 12.5 tokens) |
max_new_tokens | int | 否 | 默认 4096 |
reference_wav_b64 | string | 否 | 用于语音克隆的 base64 编码 WAV 数据 |
sampling | object | 否 | 包含 text_temperature、text_top_p、text_top_k、audio_temperature、audio_top_p、audio_top_k、audio_repetition_penalty、seed |
响应头中会携带时间信息:X-MOSS-Audio-Frames、X-MOSS-Generate-Seconds、X-MOSS-Decode-Seconds。请求体大小限制为 64 MB,大约可容纳 base64 编码后的约 60 秒参考 WAV。
示例
# 普通 TTS
curl -s -X POST http://localhost:8080/tts \
-H 'Content-Type: application/json' \
-d '{"text":"Hello from the persistent server.","max_new_tokens":300}' \
-o out.wav
# 语音克隆
python3 -c "import base64,json,sys; \
print(json.dumps({'text': sys.argv[1], 'max_new_tokens': 600, \
'reference_wav_b64': base64.b64encode(open(sys.argv[2],'rb').read()).decode()}))" \
"A different sentence in the cloned voice." samples/alice.wav > req.json
curl -s -X POST http://localhost:8080/tts \
-H 'Content-Type: application/json' --data @req.json -o cloned.wav
GPU 分配
两个二进制文件都将完整模型 —— libllama 骨干网络 以及 辅助 GGML 后端(嵌入层、LM 头、编解码器) —— 通过 LLAMA_SPLIT_MODE_NONE 固定到单个设备上。如果未指定标志,程序在加载时会自动选择空闲显存最多的 GPU:
Model::load: pinning to GPU 1 (CUDA1, 15703/15850 MiB free)
可以通过 --main-gpu N 覆盖(N 是 ggml GPU 设备列表中的索引 —— 与 libllama 自身的 main_gpu 约定相同)。当前 不支持 将骨干网络拆分到多个 GPU,因为辅助后端仍必须落在同一个设备上,否则会与该设备上的骨干网络片段竞争显存。在 Q8_0 量化下(骨干网络约 9 GB + 辅助约 5 GB ≈ 14 GB),任何 ≥16 GB 的 GPU 都足以容纳。
架构
┌────────────────────────────────────────────┐
text ────► │ BPE tokenizer (Qwen3, 155 648 vocab) │
ref.wav ──► │ Codec encoder (audio → 32×T_a codes) │
│ │ — 语音克隆
└────────────────────────────────────────────┘
│
┌─────────▼──────────────────────────────────┐
│ Embedding stack: │
│ text emb + Σi audio_emb_i(code_i) │
│ (33 tables, 4096 dim) │
└─────────┬──────────────────────────────────┘
│
inputs_embeds (S, 4096) — fed via batch.embd
│
┌─────────▼──────────────────────────────────┐
│ Qwen3-8B backbone (libllama) │
│ 36 layers, hidden=4096, GQA 32/8 │
└─────────┬──────────────────────────────────┘
│
hidden_state (4096)
│
┌─────────▼──────────────────────────────────┐
│ 33 LM heads (1 text + 32 audio×1025) │
│ (GGML matmul, GPU) │
└─────────┬──────────────────────────────────┘
│
logits
│
┌─────────▼──────────────────────────────────┐
│ Delay-pattern state machine + sampling │
│ (CPU, deterministic) │
└─────────┬──────────────────────────────────┘
│
codes (32 × T_a)
│
┌─────────▼──────────────────────────────────┐
│ Codec decoder (4-stage pure transformer) │
│ (GGML) │
│ 12.5 Hz → 24 000 Hz (×1920 upsample) │
└─────────┬──────────────────────────────────┘
│
waveform (f32, 24 kHz) → 16-bit WAV
关于每个阶段的张量形状、调试过程中遇到的错误列表以及基准测试数据,请参阅 docs/STATUS.md。
仓库布局
| 路径 | 角色 |
|---|---|
scripts/convert_hf_to_gguf.py | HF → 骨干网络 GGUF + 辅助 GGUF |
src/model.cpp, src/aux_internal.h | 两文件加载器、辅助后端、嵌入/LM 头计算图 |
src/codec.cpp | RLFQ + 4 阶段 Transformer 编码器/解码器计算图 |
src/tokenizer.cpp | libllama BPE 封装 |
src/delay.cpp | DelayState + 采样(top-k/p, 重复惩罚) |
src/pipeline.cpp | 提示构建器 + 自回归循环 + 编解码器调度 |
src/wav.cpp | RIFF/WAVE 输入/输出(无需 libsndfile 依赖) |
src/cli/moss_tts_cli.cpp | CLI 入口点 |
src/server/moss_tts_server.cpp | HTTP 服务器 |
tests/ | 诊断:模型信息、计算图冒烟测试、编解码器往返测试 |
third_party/cpp-httplib/httplib.h | 内嵌的单头 HTTP 库 |
许可证
Apache-2.0,与上游 MOSS-TTS 一致。
相似文章
OpenMOSS-Team/MOSS-TTS-Nano-100M
MOSS-TTS-Nano是一个开源的多语言语音生成模型,仅0.1B参数,专为实时TTS设计,可直接在CPU上运行而无需GPU。由OpenMOSS团队和MOSI.AI发布,它支持简单的本地部署,用于Web服务和产品集成。
OpenMOSS-Team/MOSS-TTS-v1.5 · Hugging Face
MOSS-TTS v1.5是一个更新的开源文本转语音模型,具有改进的多语言合成(支持31种语言)、更稳定的零样本语音克隆以及显式的内联停顿控制。
@lmsysorg: SGLang-Omni 现已于第0天提供来自 @Open_MOSS 的 MOSS-TTS-Local Transformer v1.5!这是一个开源的 48 kHz 立体声 TTS 模式…
MOSS-TTS-Local Transformer v1.5 是一个开源的 48 kHz 立体声 TTS 模型,具有零样本语音克隆、原生流式传输,并支持31种语言,基于 Qwen3-4B 骨干网构建,通过 SGLang-Omni 提供。
@AdinaYakup: @Open_MOSS 发布 MOSS-VL 视觉模型:https://huggingface.co/collections/OpenMOSS-Team/moss-vl… 演示:https://hug…
Open_MOSS 开源 110 亿参数 Apache 2.0 视觉-语言模型 MOSS-VL,采用交叉注意力与 XRoPE,在 VSI-bench 上比 Qwen3-VL-8B 高 8.3 分。
openbmb/VoxCPM2
VoxCPM2 是一个开源的、无分词器的扩散自回归文本转语音模型,支持30种语言,拥有20亿参数,48kHz音频输出,并具备从自然语言描述进行语音设计、可控语音克隆以及实时流式处理等功能。