Higgs Audio v3 TTS:基于 Qwen3 与 MLX 的多码本对话式语音合成实战指南

原创2026-10-10 20:28:191,979 阅读
文章标签:语音音频人工智能本地部署模型推理服务

Higgs Audio v3 TTS:基于 Qwen3 与 MLX 的多码本对话式语音合成实战指南

Higgs Audio v3 TTS 是 mlx-audio 中一款基于 Qwen3 骨干网络的对话式语音合成(TTS)模型,核心能力包括融合多码本(fused multi-codebook)音频 token 生成、内联控制 token、多语言语音合成与零样本声音克隆。本文以 docs/models/tts/higgs_audio_v3.md 为骨架,结合仓库源码与测试,系统讲解 CLI / Python 两套调用方式、声音克隆(含预编码与批量复用)、内联控制 token,以及延迟模式采样与多码本融合等底层机制,读完即可在 Apple Silicon 上跑通完整链路并理解其工作原理。

模型概览与核心特性

Higgs Audio v3 TTS 是 bosonai/higgs-audio-v3-tts-4b 的 MLX 实现,具有以下关键特性:

  • Qwen3 骨干:语言与音频统一建模,文本 backbone 直接复用 Qwen3Model(见 model.py)。
  • 融合多码本音频 token:通过单一 multimodal_embedding 将 8 个码本(codebook)的音频 token 融合为隐藏向量,再经线性头直接输出多码本 logits。
  • 内联控制 token:情感(emotion)、韵律(prosody)、音效(sfx)等控制符可直接写入输入文本。
  • 多语言与零样本声音克隆:通过参考音频 + 转写文本(transcript)实现克隆,支持单参考与多参考。

从源码看模型结构

模型配置集中在 config.py:

配置项 默认值 含义
text_config.hidden_size 2560 Qwen3 backbone 隐藏维度
text_config.num_hidden_layers 36 层数
text_config.vocab_size 151936 文本词表大小
audio_num_codebooks 8 音频码本数量
audio_codebook_size 1026 单码本词表大小
audio_boc_token_id 1024 码本开始(begin-of-codebook)token
audio_eoc_token_id 1025 码本结束(end-of-codebook)token
use_delay_pattern True 是否使用延迟模式(delay pattern)
sample_rate 24000 输出采样率 24 kHz

模型加载时的识别线索在 init.py:上游权重中的 model_type: higgs_multimodal_qwen3 与路径模式 higgs_audio_v3 / higgs-audio-v3 都会被自动映射到本实现。

快速开始:CLI 一行合成

安装 mlx-audio 后,直接使用 TTS 生成入口 python -m mlx_audio.tts.generate:

python -m mlx_audio.tts.generate \
  --model bosonai/higgs-audio-v3-tts-4b \
  --text "Hello from Higgs Audio v3 on MLX."

默认在 outputs/ 目录下写出 WAV 文件(audio_000.wav 等)。常用参数如下(定义见 generate.py):

参数 默认值 说明
--model 必填 模型 repo id 或本地路径
--text 无 要合成的文本;不传则从 stdin 或交互输入读取
--output_path None 输出目录,不传则写当前目录
--file_prefix audio 输出文件名前缀
--audio_format wav 输出格式(如 wav、flac)
--temperature 0.7 采样温度
--top_p 0.9 核采样阈值
--top_k 50 顶层采样数量
--ref_audio / --ref_text 无 参考音频路径与转写文本,可重复传多个
--stt_model whisper-large-v3-turbo 若缺 ref_text,用于自动转写参考音频
--play / --stream / --save 关 播放 / 流式生成 / 保存流式音频
--verbose 关 打印时长、tokens-per-sec、实时率等统计

注意:CLI 层会通过 _model_accepts_ref_text 探测模型是否支持 ref_text 参数(generate.py)。若用户只给了 --ref_audio 而未给 --ref_text,框架会自动调用 STT 模型转写参考音频作为克隆所需的对齐文本,这也是 --stt_model 参数存在的意义。

Python API:加载、生成与结果字段

Python 侧推荐从 mlx_audio/tts/utils.py 的 load 入口加载模型(它会自动识别 higgs_multimodal_qwen3 类型并实例化 higgs_audio_v3 的 Model):

from mlx_audio.tts.utils import load
from mlx_audio.audio_io import write as audio_write

model = load("bosonai/higgs-audio-v3-tts-4b")

for result in model.generate(
    text="Hello from Higgs Audio v3 on MLX.",
    ref_audio="reference.wav",
    ref_text="Reference transcript.",
    temperature=1.0,
    max_new_tokens=2048,
):
    audio_write("output.wav", result.audio, result.sample_rate)

generate 是生成器,每个 result 为 GenerationResult,字段包括:

  • audio / sample_rate:MLX 音频数组(24 kHz)与采样率;
  • audio_duration:格式化时长(HH:MM:SS.mmm);
  • token_count:生成的延迟行(delayed rows)数量;
  • real_time_factor:实时率(合成耗时 / 音频时长);
  • prompt:tokens、completion_tokens、tokens-per-sec;
  • audio_samples:samples、samples-per-sec;
  • processing_time_seconds 与 peak_memory_usage(峰值显存,GB)。

generate 参数速查

依据 model.py 中 generate 签名:

参数 默认值 说明
text 必填 目标文本
ref_audio / ref_text None 参考音频(路径或数组)及其转写文本
ref_audio_codes / ref_audio_codes_list None 预编码的参考音频码,跳过重新编码
references None ReferenceCodes 或 {"codes"/"audio", "text"} 字典列表
max_new_tokens / max_new_frames / max_tokens 2048 生成上限,按优先级取第一个非空值
temperature 1.0 采样温度
top_p / top_k None 核采样 / 顶层采样,None 表示不启用
seed None 随机种子(设置后调用 mx.random.seed)
fade_in_ms / fade_out_ms 30.0 / 15.0 首尾淡入淡出时长,用于抑制首帧瞬态
stream False 流式标记(本模型当前不实现流式)

一个使用细节:ref_audio 与 ref_audio_codes 互斥,同时传入会抛 ValueError: Use either ref_audio or ref_audio_codes, not both(model.py);ref_text 的数量必须与参考音频一一对应。

零样本声音克隆

克隆分为三步:准备参考音频 → 编码为音频码 → 生成。

1. CLI 方式(单参考 / 多参考)

单参考:

python -m mlx_audio.tts.generate \
  --model bosonai/higgs-audio-v3-tts-4b \
  --text "Have a nice day and enjoy the sunshine." \
  --ref_audio reference.wav \
  --ref_text "Reference transcript."

多参考时重复 --ref_audio / --ref_text 即可(action="append",见 generate.py):

python -m mlx_audio.tts.generate \
  --model bosonai/higgs-audio-v3-tts-4b \
  --text "Let's keep the same voice across this line." \
  --ref_audio speaker_1.wav \
  --ref_text "First reference transcript." \
  --ref_audio speaker_2.wav \
  --ref_text "Second reference transcript."

若多个 ref_text 但缺少 ref_audio,CLI 会报错要求成对提供(generate.py)。

2. Python 方式:encode 一次,复用多次

同一参考音色要在多个生成任务中复用时,可先用 encode_reference_audio 编码一次,之后把预编码码直接传给 ref_audio_codes,完全跳过参考音频编码环节:

reference_codes = model.encode_reference_audio("reference.wav")

for result in model.generate(
    text="This skips reference audio encoding.",
    ref_audio_codes=reference_codes,
    ref_text="Reference transcript.",
    temperature=1.0,
):
    audio_write("output.wav", result.audio, result.sample_rate)

从源码看,encode_reference_audio 的流程是(model.py):

  1. 将参考音频统一重采样到模型采样率(24 kHz)、转单声道并归一化,短于 1 秒会右端补零到 1 秒;
  2. 调用 Higgs 声学 tokenizer 的 encode 得到原始码本码(raw codes);
  3. 通过 apply_delay_pattern 套用延迟模式,填充 BOC/EOC 标记,返回可直接拼接进 prompt 的延迟码。

配套测试 test_higgs_audio_v3.py 验证了「编码结果 == 原始码 + 延迟模式」,并断言传入 ref_audio_codes 时 codec 的 encode 不会被再次调用(L262-L276)。

3. 批量生成复用同一参考

batch_generate 支持一个预编码参考服务多条文本,结果通过 sequence_idx 区分:

reference_codes = model.encode_reference_audio("reference.wav")
texts = [
    "The first line uses the cloned voice.",
    "The second line is generated in the same batch.",
]

for result in model.batch_generate(
    texts=texts,
    ref_audio_codes=reference_codes,
    ref_text="Reference transcript.",
    temperature=1.0,
):
    audio_write(f"output_{result.sequence_idx}.wav", result.audio, result.sample_rate)

batch_generate 返回 BatchGenerationResult,除 sequence_idx 外同样携带 token_count、audio_duration、processing_time_seconds 等统计。实现上会把多条 prompt 左侧 padding 对齐后一次前向(model.py),并复用 BatchKVCache;测试 test_batch_generate_reuses_shared_reference_audio 验证共享参考时 codec 只编码一次,且批量结果与串行结果在 token_count、samples 上完全一致(L407-L439)。

注意事项:

  • 参考音频建议选用 5~15 秒的干净人声(仓库示例脚本 examples/higgs_audio_clone_demo.py 的文档注释同样建议该时长范围),ref_text 必须是参考片段逐字转写文本,否则克隆对齐会不稳定;
  • 语音、速度、音调类参数在本模型中不可用:supports_tts_batch 规定 stream、voice、instruct、speed≠1.0、pitch≠1.0、gender≠male 均不支持(model.py),批量 API 中传入会直接抛 ValueError。

内联控制 token

上游模型支持把控制 token 直接写进输入文本,例如:

<|emotion:amusement|><|prosody:expressive_high|>That was unexpected. <|sfx:laughter|>Hehe.

用法要点:

  • emotion(情感)、prosody(韵律)、sfx(音效)等 token 由上游 tokenizer 提供,必须与模型支持的取值一致;
  • 对音效标签,需按上游指引在标签后附带对应的文字拟声词(如示例中的 Hehe),便于模型对齐生成;
  • 这些 token 会被 tokenizer 直接编码进文本序列。从 prompt.py 可以看到,prompt 由 <|tts|> 起始,参考段以 <|ref_text|> / <|ref_audio|> 组织,随后 <|text|> 包裹目标文本,最后以 <|audio|> 收尾——控制 token 属于 <|text|> 段的一部分,随文本一起编码。

批量 / 连续批处理机制

除一次性 batch_generate 外,模型还通过 continuous_batching.py 的 HiggsAudioV3BatchSession 支持持续入队的批处理会话:

  • 事件模型:TTSBatchOptions(含 max_batch_size、max_tokens、temperature、top_p、top_k 等,见 continuous.py)配置会话,TTSBatchItem 入队,step() 推进一个解码步并产出 TTSBatchEvent;
  • 动态调度:available_slots 决定能接纳多少新请求,每个 step() 先推进活跃请求、再吸纳待处理请求,且每 50 步执行一次 mx.clear_cache() 控制显存;
  • 优雅终止:请求解码完毕或达到 max_tokens 即产出 done=True 的事件;cancel(sequence_id) 支持按序列号移除请求并同步裁剪 KV cache(continuous_batching.py)。

测试 test_continuous_batch_session_matches_serial 验证了连续批处理输出与串行生成逐 token、逐样本一致。

生成机制与源码剖析

融合多码本嵌入与线性头

音频码不走独立 embedding 表,而是把 8 个码本平铺成一个超大嵌入表:multimodal_embedding 尺寸为 audio_num_codebooks * audio_codebook_size × hidden_size。编码时对每个码本施加 codebook_idx * audio_codebook_size 的偏移后取嵌入并求和(model.py),解码 logits 则由同一个嵌入表转成线性头后 reshape 为 <a href="https://link.gitcode.com/i/47d01120a9941368227ec47de085a701" target="_blank">num_codebooks, codebook_size]([L152-L158)。测试 test_fused_embedding_and_head_shapes 直接验证了该融合求和逻辑。

延迟模式:ramp-in 与 wind-down

多码本音频解码采用 SGLang 兼容的延迟模式(delayed pattern),核心在 generation.py:

  • apply_delay_pattern:把原始码 <a href="https://link.gitcode.com/i/c0c0b0e9b129316336a337623080849c" target="_blank">T, N] 展开为延迟行 [T+N-1, N],第 k 个码本整体右移 k 步,左侧缺口用 BOC token 填充([L24-L39);
  • reverse_delay_pattern:解码完成后逆向还原为原始码(L42-L56),测试 test_delay_pattern_round_trip 保证两者可无损往返;
  • 采样状态机 HiggsSamplerState:delay_count 控制前 N 步的码本逐个“点亮”(后续码本强制输出 BOC);首个码本命中 EOC 后进入 eoc_countdown = N-2 的收尾倒计时,保证各码本同步结束(step),对应测试 test_ramp_in_forces_later_codebooks_to_boc 与 test_eoc_wind_down。

采样策略

sample_independent / sample_batch(generation.py)在每个解码步对全部码本独立采样:先按温度缩放 logits,再依次施加 top-k 与 top-p 裁剪,最后 mx.random.categorical 采样;当 temperature <= 1e-5 或 top_k == 1 时退化为贪心 argmax。

解码与后处理

生成结束后,_decode_audio(model.py)将收集到的延迟行 stack、reverse_delay_pattern 还原、经 HiggsAudioTokenizer.decode 直接得到波形(<a href="https://link.gitcode.com/i/92d1ba8a56302b4703dae77b51663e98" target="_blank">T, 8] → 约 T*960 个样本,见 [higgs_audio.py),随后按 fade_in_ms=30 / fade_out_ms=15 施加首尾线性淡入淡出以抑制瞬态(L353-L367)。

模型转换、量化与加载细节

如需把上游 PyTorch 权重转为 MLX 格式或做量化,可使用仓库的转换入口 mlx_audio.convert(参数见 convert.py):

python -m mlx_audio.convert \
  --hf-path bosonai/higgs-audio-v3-tts-4b \
  --mlx-path mlx_model \
  --quantize \
  --q-bits 4

要点:

  • --hf-path 接受 HuggingFace repo id,--mlx-path 指定输出目录(默认 mlx_model),--quantize / --q-bits / --q-group-size / --q-mode 控制量化;
  • 模型自带的 model_quant_predicate(model.py)会跳过 multimodal_embedding,只量化 nn.Linear 与 nn.Embedding 权重,避免损伤音频嵌入精度;
  • 权重重命名逻辑在 sanitize(L112-L135):上游的 tied.embedding.text_embedding.*、body.layers.*、body.norm.* 映射到 MLX 的 backbone.*,tied.embedding.modality_embeddings.0.embedding.* 映射到 multimodal_embedding.*,音频头相关权重会被剔除,对应测试 test_sanitize_maps_source_keys;
  • 类型识别测试 test_loader_remapping 与 test_higgs_v3_upstream_model_type_resolves_to_local_implementation 确认 higgs_multimodal_qwen3 会稳定解析到 higgs_audio_v3 实现。

加载模型时,post_load_hook(model.py)会自动装配三件套:文本 tokenizer(读取 tokenizer.json)、HiggsAudioV3PromptBuilder、以及 Higgs 声学 codec——若模型目录下存在 audio_tokenizer/ 子目录则走 from_pretrained,否则直接从主 TTS 检查点中按 tied.embedding.modality_embeddings.0.model.* 前缀抽取 codec 权重(higgs_audio.py)。因此克隆用的参考音频编码完全在 MLX 侧完成,不依赖任何外部框架。

许可与使用限制

  • 上游模型采用 Boson Higgs Audio v3 Research and Non-Commercial License,仅供研究与非商业用途,商用前请查阅原模型卡与许可证文件确认合规要求;
  • 本实现依赖 Apple Silicon(MLX 框架),不支持 CPU 之外的通用 GPU 环境;
  • 当前版本 stream=True 的批量流式未实现(batch_generate 会抛 NotImplementedError),且 voice / instruct / speed / pitch 等通用 TTS 参数在本模型上不可用,克隆音色统一走 ref_audio + ref_text 路径。
登录后查看全文
mlx-audio