mlx-audio MOSS-TTS 实战指南:8B 多码本 TTS 的音色克隆、多说话人对话与流式合成
mlx-audio MOSS-TTS 实战指南:8B 多码本 TTS 的音色克隆、多说话人对话与流式合成
本篇基于 mlx-audio 仓库中 MOSS-TTS 模型模块的官方说明与配套源码,覆盖 5 个受支持检查点(8B MossTTSDelay v1.5/v1.0、MOSS-TTSD-v1.0 对话模型与两代 Local-Transformer 变体)的加载、Python API、CLI 调用、音色克隆、多说话人对话与流式合成的完整用法,并深入到 Qwen3 骨干、多码本(RVQ)延迟模式与 MOSS Audio Tokenizer 解码的工程实现细节。读完后你可以直接在 Apple Silicon 上运行 MOSS-TTS 系列模型,理解其采样参数、prompt 模板结构与流式分块机制,并按需调整生成行为。
支持的模型与选择
mlx-audio 中的 MOSS-TTS 实现位于 mlx_audio/tts/models/moss_tts/,官方说明见 mlx_audio/tts/models/moss_tts/README.md,文档站版本见 docs/models/tts/moss-tts.md。它覆盖 OpenMOSS 的 8B MossTTSDelay v1.5 与 v1.0 模型、MOSS-TTSD-v1.0 对话模型,以及两代 Local-Transformer 变体,全部使用 Qwen3 骨干与对应的多码本音频生成路径,并搭配完整版 MOSS Audio Tokenizer。主 README.md 的模型列表将该系列标注为支持 31 种语言、带音色克隆的 8B 级多语言 TTS。
仓库中受支持的检查点(Hugging Face 仓库 ID,可直接传给 load):
| 模型 ID | 说明 | 音频 Tokenizer |
|---|---|---|
OpenMOSS-Team/MOSS-TTS-v1.5 |
8B MossTTSDelay v1.5,延迟模式(delay pattern)生成 |
OpenMOSS-Team/MOSS-Audio-Tokenizer |
OpenMOSS-Team/MOSS-TTS |
8B MossTTSDelay v1.0 |
OpenMOSS-Team/MOSS-Audio-Tokenizer |
OpenMOSS-Team/MOSS-TTSD-v1.0 |
多说话人对话模型([S1]/[S2] 标记) |
OpenMOSS-Team/MOSS-Audio-Tokenizer |
OpenMOSS-Team/MOSS-TTS-Local-Transformer-v1.5 |
v1.5 本地 Transformer 变体,支持流式 | OpenMOSS-Team/MOSS-Audio-Tokenizer-v2(48 kHz 输出) |
OpenMOSS-Team/MOSS-TTS-Local-Transformer |
v1.0 本地 Transformer 变体(legacy 路径) | OpenMOSS-Team/MOSS-Audio-Tokenizer |
从源码结构看,检查点的差异由 config.py 中的 model_type 字段驱动:moss_tts_delay(默认)走延迟模式路径;model_type == "moss_tts_local" 或存在 gpt2_config 时判定为 v1.5 本地 Transformer(is_v15_local_transformer,见 config.py#L59-L73);同时给出 additional_mlp_ffn_hidden_size、local_ffn_hidden_size、local_hidden_size、local_num_layers 四个字段时判定为 legacy 本地 Transformer(is_legacy_local_transformer)。Tokenizer 仓库的默认值也在同一文件中定义:v1.5 本地变体缺省指向 OpenMOSS-Team/MOSS-Audio-Tokenizer-v2,其余指向 OpenMOSS-Team/MOSS-Audio-Tokenizer(见 config.py#L10-L11 与 config.py#L142-L150)。
快速开始:Python API
基本用法——加载模型后调用 generate,取首个 GenerationResult 并写盘:
from mlx_audio.audio_io import write as audio_write
from mlx_audio.tts import load
model = load("OpenMOSS-Team/MOSS-TTS-v1.5", lazy=True)
result = next(model.generate(
text="Hello, this is MOSS-TTS running on MLX.",
max_tokens=120,
))
audio_write("output.wav", result.audio, result.sample_rate)
说明:
lazy=True延迟加载权重,适合先构建管线再触发计算;generate是生成器,max_tokens限制最大新生成 token 数(源码默认上限为 4096,见下文参数详解);result.audio为波形mx.array,result.sample_rate为采样率(配置默认 24000 Hz,v1.5 本地变体为 48000 Hz),二者可直接配合mlx_audio.audio_io.write保存。
音色克隆
传入 ref_audio 即可完成参考音色克隆,参考音频在内部由 MOSS Audio Tokenizer 编码为多码本音频码,注入用户 prompt:
result = next(model.generate(
text="This is a short cloned voice sample.",
ref_audio="speaker.wav",
max_tokens=120,
))
audio_write("cloned.wav", result.audio, result.sample_rate)
CLI 调用
同样的能力可以通过命令行直接触发,入口是 mlx_audio/tts/generate.py 模块:
python -m mlx_audio.tts.generate \
--model OpenMOSS-Team/MOSS-TTS-v1.5 \
--text "Hello, this is MOSS-TTS running on MLX." \
--output_path outputs
多语言与语言提示
对 v1.5 的非英语多语言 prompt,已知语种时建议显式传入 language:
result = next(model.generate(
text="Bonjour, je voudrais essayer une voix francaise naturelle.",
language="French",
max_tokens=120,
))
language 会作为独立字段写入用户指令模板(见下文 prompt 模板一节)。此外,内联停顿标记(如 [pause 3.2s])会原样透传到 v1.5 prompt 中,可用于控制生成节奏。
generate() 参数详解
generate 的完整签名为 generate(text, ref_audio=None, ref_text=None, prompt_audio_codes=None, mode="generation", stream=False, max_tokens=None, **kwargs)(见 moss_tts.py#L1442-L1452)。除官方文档示例中的参数外,kwargs 还可接收一组采样与流式参数。不同模型分支的默认值不同,汇总如下(默认值取自源码中各生成分支的 kwargs.get 回退值):
| 参数 | 延迟模式(MossTTSDelay) |
v1.5 本地 Transformer | legacy 本地 Transformer |
|---|---|---|---|
max_tokens(max_new_tokens) |
默认 4096,可被检查点 generation_config.json 覆盖 |
4096 | 4096 |
text_temperature |
1.5(可被 generation_config.json 的 temperature 覆盖) |
1.0 | 1.5 |
text_top_p |
1.0 | 1.0 | 1.0 |
text_top_k |
50 | 50 | 50 |
audio_temperature(兼容别名 temperature) |
1.7 | 1.7 | 1.0 |
audio_top_p(兼容别名 top_p) |
0.8 | 0.8 | 0.95 |
audio_top_k(兼容别名 top_k) |
25 | 25 | 50 |
audio_repetition_penalty |
1.0 | 1.0 | 1.1 |
do_sample |
由温度是否为正隐式决定 | 默认 True | 由温度是否为正隐式决定 |
use_kv_cache |
—(默认启用 prompt cache) | True | —(默认启用) |
n_vq_for_inference |
可截断生效的 RVQ 通道数 | 必须等于模型配置的 12,否则报错 | 可截断生效通道数 |
对应的取参逻辑见 moss_tts.py#L1566-L1649。两点使用注意:
temperature/top_p/top_k这些通用别名会被路由到音频通道(audio_temperature优先,回退到temperature),文本通道始终使用text_*前缀参数;- 延迟模式分支还会读取检查点目录下的
generation_config.json(_load_generation_config,见 moss_tts.py#L348-L362),作为各采样参数的缺省来源,显式传入的 kwargs 优先。
mode 支持 generation(含音色克隆,voice_clone/direct 会被归一化为 generation)与 continuation(续写:给定一段参考音频继续生成,只接受单个参考音频与单条 ref_text,见 moss_tts.py#L1483-L1495)。
对话生成:MOSS-TTSD-v1.0
MOSS-TTSD-v1.0 支持在同一轮合成中按 [S1]、[S2] 标记切换说话人:
python -m mlx_audio.tts.generate \
--model OpenMOSS-Team/MOSS-TTSD-v1.0 \
--text "[S1] Hello. [S2] Hi, this is MOSS-TTSD running on MLX." \
--output_path outputs
为每个说话人绑定独立参考音色时,可以重复传入 --ref_audio / --ref_text(顺序对应 S1、S2):
python -m mlx_audio.tts.generate \
--model OpenMOSS-Team/MOSS-TTSD-v1.0 \
--text "[S1] This uses the first reference. [S2] This uses the second." \
--ref_audio speaker_1.wav \
--ref_text "Reference transcript for speaker one." \
--ref_audio speaker_2.wav \
--ref_text "Reference transcript for speaker two." \
--output_path outputs
其背后机制在 processor.py 的 UserMessage 中:参考列表按说话人下标渲染为 <a href="https://link.gitcode.com/i/6941e155a89d4fc5676251afd36ef8eb" target="_blank">S1]:、[S2]: 前缀加音频占位符 <|audio|>(见 [processor.py#L53-L68),无参考的说话人渲染为 [S{n}]: None。多个连续占位符会被 _merge_consecutive_audio_placeholders 合并,对应的音频码在时间轴上拼接,保证多段参考映射到同一段连续音频块。
v1.5 Local-Transformer 变体与流式合成
v1.5 本地 Transformer 检查点单独加载:
model = load("OpenMOSS-Team/MOSS-TTS-Local-Transformer-v1.5", lazy=True)
该变体的三个关键事实(官方说明 + 源码印证):
- 使用
OpenMOSS-Team/MOSS-Audio-Tokenizer-v2,输出 48 kHz 采样率; - 采用固定 12 码本的 RVQ 深度——
n_vq_for_inference若传入与 12 不同的值会直接抛错(_resolve_v15_fixed_nq,见 moss_tts.py#L581-L588),prompt 构建侧同样有校验(_assert_fixed_nq,processor.py#L692-L699); - 本地 Transformer 结构由 GPT-2 风格小 Transformer 实现(
local_transformer_layers默认 1,local_text_head_mode默认"full_vocab",use_static_local_kv_cache默认 True,见 config.py#L39-L44)。
流式生成
目前仅 MOSS-TTS-Local-Transformer-v1.5 支持流式,其余变体传入 stream=True 会抛出 NotImplementedError(见 moss_tts.py#L1528-L1532):
chunks = model.generate(
text="Hello, this is streamed MOSS local transformer audio.",
language="English",
stream=True,
streaming_interval=2.0,
)
for chunk in chunks:
play_or_buffer(chunk.audio, chunk.sample_rate)
流式行为的关键实现细节(_generate_v15_local_streaming_results,见 moss_tts.py#L1254-L1397):
- 音频 Tokenizer v2 的帧率为 12.5 帧/秒,每帧对应
采样率 / 12.5个采样点(48 kHz 下为 3840 个); - 首块默认在生成满 4 帧 RVQ 码后即解码输出(
first_chunk_frames,可通过streaming_first_chunk_frames调整),用于压低首包延迟; - 后续块以
streaming_interval(默认 2.0 秒,换算成interval × 12.5帧)为步进输出; - 默认开启
streaming_use_codec_session,MLX 路径为每次generate调用维护单流式 MOSS-Audio-Tokenizer-v2 解码器会话逐帧解码,无需上游流式 demo 依赖的 SGLang 服务器;关闭会话时回退到批量解码路径,并携带streaming_context_frames(默认 8 帧)上下文、解码后裁掉上下文部分; - 每个 chunk 是一个带
is_streaming_chunk/is_final_chunk标记的GenerationResult,最后一个 chunk 标记is_final_chunk=True。
源码级架构解析
三条并行的模型实现分支
Model.__init__ 根据配置分派三种结构(见 moss_tts.py#L213-L306):
- v1.5 本地 Transformer:
Qwen3Model全局骨干 + 每码本独立的audio_embeddings/audio_lm_heads+ GPT2 风格本地 Transformer(local_gpt2_config()会把n_positions/n_ctx设为n_vq + 1、n_layer设为local_transformer_layers)。前向时,全局骨干产出的隐状态与每个已采样码本的嵌入按位置堆叠,送入本地 Transformer 做码本间的自回归细化(_v15_local_forward,见 moss_tts.py#L590-L650); - legacy 本地 Transformer:
MosiTTSModel(Qwen3 骨干 + 每通道嵌入表)+ 可学习维度的MossTTSLocalTransformer,通过speech_embedding_to_local_mlp与每通道local_to_speech_embedding_mlps做维度桥接,每个通道各有一个 RMSNorm 与 LM head(_local_forward,见 moss_tts.py#L652-L707); - 延迟模式(
MossTTSDelay,默认):Qwen3 骨干 + 文本词表嵌入加n_vq个扩展音频嵌入(emb_ext),输出1 + n_vq个 LM head——第 0 个预测文本/控制 token,其余每个预测一个 RVQ 码本。嵌入方式为各通道嵌入相加(_build_inputs_embeds,见 moss_tts.py#L445-L458)。
所有分支共用 mx.array 形状 [batch, seq, n_vq + 1] 的多通道 token 表示:第 0 列是文本/控制 token 通道,其余各列是一个 RVQ 码本。
延迟模式(delay pattern)如何工作
延迟模式是该系列最核心的机制:RVQ 各码本通道在时间轴上错开 1 帧,使得“同一时间步先定文本控制位、再按通道顺序解码各码本”成为可能。
- 编码侧:
apply_delay_pattern将<a href="https://link.gitcode.com/i/99b3c277039ae6247708822de23c7914" target="_blank">frames, n_vq]的码表沿对角线展开为[frames + n_vq - 1, n_vq],各通道整体下移([processor.py#L117-L129); - 解码侧:生成结束后由
apply_de_delay_pattern还原(processor.py#L132-L145,在_decode_generated_audio中被调用,仅对非本地变体执行,见 moss_tts.py#L1183-L1229); - 生成循环:
generate_delay_pattern_ids(moss_tts.py#L730-L906)中,文本通道用一组专用控制 token 驱动状态机——audio_start(151652)进入音频段,assistant_gen_slot(151656)逐帧推进,delay_slot(151662)用于码本间的延迟填充,audio_end(151653)退出音频段;音频码本解码时,audio_pad_code(1024)的 logits 被置为-inf,并按audio_repetition_penalty对已生成 token 施加惩罚。所有控制 token ID 的默认值定义在 config.py#L20-L33; - 采样原语:
sample_token统一实现了 repetition penalty(对正 logits 除、负 logits 乘)、top-k、top-p 与温度缩放,基于mx.random.categorical采样(sampling.py#L67-L91)。
从源码结构看,生成循环对 batch_size != 1 会抛出 NotImplementedError,即当前实现为逐条串行生成。
Prompt 模板与文本预处理
v1.5 用户消息由结构化模板渲染(LocalV15UserMessage,processor.py#L573-L633),字段依次为 Reference(s)、Instruction、Tokens、Quality、Sound Event、Ambient Sound、Language、Text,未提供的字段渲染为 None;延迟模式模板(UserMessage)在 n_vq == 16 且非本地变体时还会附加 Scene 字段(见 processor.py#L172-L174)。因此除了 text、ref_audio、language 外,generate(**kwargs) 还可传入 instruction、tokens、quality、sound_event、ambient_sound、scene 等字段(moss_tts.py 中 user_kwargs 的构造见 moss_tts.py#L1498-L1509)。
进入模板前,文本会先经过 normalize_tts_text(text.py#L33-L46)做上游 v1.5 风格的清理:移除零宽与控制字符、去 Markdown 标记、保护 URL/邮箱/@提及/话题标签/点号 token/文件名等片段不被标点归一化破坏、压缩 CJK 与拉丁字符间的空格、合并重复标点(含 !? 混合折叠)。这解释了为什么 [pause 3.2s] 这类内联标记能安全透传——点号 token 与括号结构都被保护或规范化处理过。
加载钩子与量化策略
post_load_hook从模型目录加载AutoTokenizer(v1.5 本地变体会额外传fix_mistral_regex=True,并在旧版 transformers 不识别该参数时回退),同时加载generation_config.json(moss_tts.py#L324-L358);model_quant_predicate明确排除音频嵌入相关模块(audio_embeddings、emb_ext、model.embedding_list、audio_tokenizer)不参与量化(moss_tts.py#L371-L379)——从源码结构看,这是为避免多码本嵌入表量化损伤音色还原;- 音频 Tokenizer 通过
MossAudioTokenizer.from_model_dir懒加载,优先查找模型目录内嵌的 tokenizer 权重,找不到时回退到配置中的audio_tokenizer_pretrained_name_or_path(_ensure_audio_tokenizer,moss_tts.py#L389-L403)。
结果对象与注意事项
generate 产出的 GenerationResult 除 audio、sample_rate 外还携带诊断信息:audio_duration(时字符串)、real_time_factor(音频时长/处理耗时)、prompt 与音频采样吞吐、peak_memory_usage、流式标记(_build_generation_result,moss_tts.py#L1399-L1440),可直接用于监控实时率。
使用限制小结(均以当前仓库实现为准):
- v1.5 本地变体
n_vq_for_inference只能是 12,否则两处都会抛ValueError; - 流式合成目前仅
MOSS-TTS-Local-Transformer-v1.5可用,其余变体传stream=True报错; - 生成循环不支持 batch(
batch_size必须为 1); continuation模式要求提供ref_audio或prompt_audio_codes,且只接受单段参考;- 采样率取决于检查点:配置默认 24000 Hz,v1.5 本地变体经 Tokenizer v2 输出 48000 Hz,写盘时务必使用
result.sample_rate而非硬编码值。
相关入口与文件索引:模型实现 mlx_audio/tts/models/moss_tts/moss_tts.py、配置 mlx_audio/tts/models/moss_tts/config.py、prompt 处理 mlx_audio/tts/models/moss_tts/processor.py、采样 mlx_audio/tts/models/moss_tts/sampling.py、文本规范化 mlx_audio/tts/models/moss_tts/text.py、CLI mlx_audio/tts/generate.py、官方说明 mlx_audio/tts/models/moss_tts/README.md。