首页
/ ChatTTS 对话场景语音合成实战:安装部署、两阶段推理与细粒度韵律控制

ChatTTS 对话场景语音合成实战:安装部署、两阶段推理与细粒度韵律控制

2026-09-05 14:39:35作者:魏侃纯Zoe

ChatTTS 是 2noise 团队开源的面向日常对话(LLM 助手等对话场景)的生成式语音合成模型。本文基于仓库 README 的完整脉络展开,并结合 ChatTTS/core.pyChatTTS/config/config.pyexamples/cmd/ 下的真实实现,讲清它的安装部署方式、基础与进阶 API 用法、流式推理机制,以及口语化控制 token(笑声、停顿、插话)背后的两阶段推理原理,帮助读者可复制地跑通并完成音色与韵律的精细控制。

一、项目定位:为对话而生,而非通用朗读

README 对 ChatTTS 的核心定位是:"a text-to-speech model designed specifically for dialogue scenarios such as LLM assistant",即专为 LLM 助手这类对话场景优化的 TTS 模型。它当前支持的语种为英语和中文(README 中其他语种标注为 "Coming Soon")。

三个核心亮点(对应 README 的 Highlights 一节):

  1. 对话式 TTS(Conversational TTS):面向对话任务优化,支持多说话人(multi speakers),可进行交互式对话合成;
  2. 细粒度控制(Fine-grained Control):模型可预测并控制细粒度韵律特征,包括笑声(laughter)、停顿(pauses)、语气词/插话(interjections);
  3. 更好的韵律(Better Prosody):官方表述其在韵律上超越了多数开源 TTS 模型,并提供预训练模型供后续研究。

数据与许可方面需要特别注意(README 的 Dataset & Model / Licenses / Disclaimer 三节):

  • 主模型使用 100,000+ 小时的中英文音频数据训练;
  • 开源的 HuggingFace 版本(2Noise/ChatTTS)是 40,000 小时的预训练模型,未经 SFT
  • 代码许可为 AGPLv3+模型权重许可为 CC BY-NC 4.0,仅限教育与研究用途,不得用于商业或非法目的;
  • 官方在 40k 小时模型的训练过程中加入了少量高频噪声,并用 MP3 格式尽可能压缩音频质量,以防止恶意滥用;同时作者计划开源一个内部训练的"检测模型"。

Roadmap 中已完成项包括:开源 40k 小时基础模型与 spk_stats 文件、流式音频生成、开源 DVAE 编码器与 zero-shot 推理代码;未完成项包括多情感控制和 ChatTTS.cpp(C++ 移植)。

二、环境准备与安装

2.1 依赖清单

仓库根目录的 requirements.txt 列出了核心依赖:

numpy<3.0.0
numba
torch>=2.1.0
torchaudio
tqdm
vector_quantize_pytorch
transformers>=4.41.1
vocos
IPython
gradio
pybase16384
pynini==2.1.5; sys_platform == 'linux'
WeTextProcessing; sys_platform == 'linux'
nemo_text_processing; sys_platform == 'linux'
av
pydub
requests

其中 pybase16384 用于音色嵌入字符串的编解码(见后文 ChatTTS/model/speaker.py);pynini/WeTextProcessing/nemo_text_processing 仅在 Linux 上安装,是文本正则化(text normalization)的可选组件,缺少时 examples/cmd/run.py 会给出警告但不影响基础功能。

2.2 安装方式

方式一:克隆仓库 + 安装依赖(开发/示例运行)

git clone https://github.com/2noise/ChatTTS
cd ChatTTS
pip install --upgrade -r requirements.txt

或者使用 conda 环境(官方示例使用 Python 3.11):

conda create -n chattts python=3.11
conda activate chattts
pip install -r requirements.txt

方式二:直接安装发布包(推荐生产使用)

# 1. PyPI 稳定版
pip install ChatTTS

# 2. GitHub 最新版
pip install git+https://github.com/2noise/ChatTTS

# 3. 本地目录开发模式
pip install -e .

可选组件(Linux)

# vLLM 加速(README 标注 Linux only)
pip install safetensors vllm==0.2.7 torchaudio

README 还给出两个不推荐安装的可选项,并明确警告 "DO NOT INSTALL":

  • TransformerEngine:对 NVIDIA GPU 的适配仍在开发中,目前无法正常运行,安装过程很慢,仅限开发目的;
  • FlashAttention-2:按官方引用的 transformers issue,当前 FA2 反而会拖慢生成速度,同样仅限开发目的。

三、模型组成:从 config.py 看清架构参数

chat.load() 之后,Chat 实例内部持有六个模块。从 ChatTTS/config/config.py 可以看出各资产的默认路径与关键超参:

资产文件(config.Path 作用 关键配置
asset/Vocos.safetensors 预训练声码器 采样率 24000 Hz,n_mels=100n_fft=1024hop_length=256,8 层 VocosBackbone + ISTFTHead
asset/DVAE.safetensors 音频 tokenizer(VQ-VAE 变体) 4 层 VQ,levels=(5,5,5,5)dim=1024,编/解码器各 12 层
asset/gpt 自回归主模型 20 层、12 头、hidden_size=768max_position_embeddings=4096,音频词表 626、文本词表 21178、num_vq=4,说话人嵌入维度 spk_emb_dim=192
asset/Decoder.safetensors 高音质解码器(替代 DVAE 解码路径) 12 层,idim/odim=384
asset/tokenizer BertTokenizerFast 词表 特殊 token 如 [spk_emb][break_0][Ebreak]
asset/Embed.safetensors 文本/音频统一嵌入层 768 维

ChatTTS/core.py_load() 流程看,加载顺序是:Vocos → DVAE → Embed → GPT → Speaker → Decoder → Tokenizer,并在 has_loaded() 中校验模块是否齐全。加载参数还有几个值得注意的实现细节:

  • compile=True 仅当设备为 CUDA 时生效(gpt.prepare(compile=compile and "cuda" in str(device)));
  • MPS 设备上 GPT 会被回退到 CPU(device_gpt),Vocos 也运行在 CPU 以避免 MPS 崩溃;NPU 设备上 Vocos 与 DVAE 的 Mel 谱计算回退 CPU;
  • use_vllm=True 时 GPT 内部走 vLLM 引擎(对应 ChatTTS/model/velocity/ 目录下的实现),use_flash_attn 则启用 FA2(如前所述,README 不推荐)。
# Chat.load() 的完整签名(摘自 ChatTTS/core.py)
load(
    source="local",            # "huggingface" | "local" | "custom"
    force_redownload=False,
    compile=False,
    custom_path=None,          # source="custom" 时指向本地资产目录
    device=None,               # 默认由 select_device() 自动选择
    coef=None,                 # DVAE 解码的量化系数,通常无需手动指定
    use_flash_attn=False,
    use_vllm=False,
    experimental=False,
    enable_cache=True,
)

source 三选一:local 默认在当前工作目录寻找/下载资产;huggingface 通过 snapshot_download(repo_id="2Noise/ChatTTS") 拉取;custom 直接加载指定目录。模型完整性由 ChatTTS/res/sha256_map.json 校验。

四、快速上手:WebUI 与命令行

以下命令需在项目根目录下执行(README 原话)。

4.1 启动 WebUI

python examples/web/webui.py

WebUI(examples/web/webui.py)基于 Gradio,提供文本输入、Sample Audio / Sample Audio Code(zero-shot 参考音频音色提取)、Refine text 开关、Audio Temperature / top_P / top_K 滑杆、Timbre 下拉框、Audio Seed 与 Text Seed 随机按钮,以及 Speaker Embedding 字符串编辑框等控件,适合交互式验证音色与韵律效果。

4.2 命令行推理

python examples/cmd/run.py "Your text 1." "Your text 2."

生成的音频会保存为 ./output_audio_n.mp3n 从 0 递增)。examples/cmd/run.py 的完整 CLI 参数为:

参数 说明 默认值
texts(位置参数,可多个) 待合成文本
--spk 指定说话人嵌入字符串,留空则随机采样一个 None
--stream 启用流式模式,逐段生成并保存
--source 模型来源:huggingface / local / custom local
--custom_path 自定义模型资产目录(配合 --source custom

例如加载本地已有资产:python examples/cmd/run.py --source custom --custom_path ../../models/2Noise/ChatTTS 你好喲 ":)"。脚本内部会自动尝试注册中文(WeTextProcessing)与英文(nemo_text_processing)正则化器,注册失败仅记录警告。

五、API 基础用法

最小可用示例(README Basic Usage 原样保留):

import ChatTTS
import torch
import torchaudio

chat = ChatTTS.Chat()
chat.load(compile=False) # Set to True for better performance

texts = ["PUT YOUR 1st TEXT HERE", "PUT YOUR 2nd TEXT HERE"]

wavs = chat.infer(texts)

for i in range(len(wavs)):
    """
    In some versions of torchaudio, the first line works but in other versions, so does the second line.
    """
    try:
        torchaudio.save(f"basic_output{i}.wav", torch.from_numpy(wavs[i]).unsqueeze(0), 24000)
    except:
        torchaudio.save(f"basic_output{i}.wav", torch.from_numpy(wavs[i]), 24000)

注意两点:采样率固定 24000 Hz(与 ChatTTS/config/config.pyFeatureExtractorInitArgs.sample_rate = 24000 一致);README 保留了双行 torchaudio.save 的兼容写法,以适配不同版本 torchaudio 对输入维度的差异要求。

六、进阶用法:音色采样与两级控制

6.1 说话人(音色)的采样与复用

# Sample a speaker from Gaussian.
rand_spk = chat.sample_random_speaker()
print(rand_spk) # save it for later timbre recovery

sample_random_speaker() 返回一个字符串形式的音色编码,保存下来即可在后续调用中精确复现同一音色(timbre recovery)。其实现见 ChatTTS/model/speaker.py

  • Speaker 在初始化时从配置中的 spk_stat 大字符串(base16384 编码)解码出两组 float16 张量 stdmean(对应 GPT 配置中 spk_emb_dim=192 维);
  • _sample_random() 执行 randn(dim).mul_(std).add_(mean),即在预训练得到的均值/方差上做高斯采样,每个样本都是一个新的音色;
  • 该向量经 LZMA 压缩 + base16384 编码后成为可打印、可持久化的字符串;apply() 时再把字符串解码回来,对嵌入张量做 L2 归一化后替换 [spk_emb] 位置。

zero-shot 场景下则用 chat.sample_audio_speaker(wav):传入一段参考音频(np.ndarraytorch.Tensor),经 DVAE 编码后得到音色 prompt 字符串,供 InferCodeParams.spk_smp 使用。

6.2 句子级控制:RefineTextParams

README Advanced Usage 原样示例:

params_infer_code = ChatTTS.Chat.InferCodeParams(
    spk_emb = rand_spk, # add sampled speaker
    temperature = .3,   # using custom temperature
    top_P = 0.7,        # top P decode
    top_K = 20,         # top K decode
)

# For sentence level manual control.
# use oral_(0-9), laugh_(0-2), break_(0-7)
# to generate special token in text to synthesize.
params_refine_text = ChatTTS.Chat.RefineTextParams(
    prompt='[oral_2][laugh_0][break_6]',
)

wavs = chat.infer(
    texts,
    params_refine_text=params_refine_text,
    params_infer_code=params_infer_code,
)

这两个 dataclass 定义在 ChatTTS/core.py 中,默认值如下(README 示例中未覆盖的参数在此补齐):

Chat.RefineTextParams(第一阶段:文本润色)

参数 默认值 说明
prompt "" 前置控制提示,可写 [oral_2][laugh_0][break_6] 这类 token 组合
top_P / top_K / temperature 0.7 / 20 / 0.7 解码采样策略
repetition_penalty 1.0 重复惩罚
max_new_token / min_new_token 384 / 0 生成长度上下限
show_tqdm / ensure_non_empty True / True 进度条;确保非空输出
manual_seed None 随机种子,复现文本级随机性

oral_(0-9)laugh_(0-2)break_(0-7) 表示口语感、笑声强度、停顿强度三档控制,数值越大强度越高。这一阶段由 GPT 以 infer_text=True 的方式生成"润色后的文本"(可能插入 [uv_break][laugh] 等特殊 token),即 _refine_text()

Chat.InferCodeParams(继承自 RefineTextParams,第二阶段:声学码本生成)

参数 默认值 说明
prompt "[speed_5]" 生成音频 token 前的提示
spk_emb None 音色嵌入字符串(高斯采样或外部指定)
spk_smp None zero-shot 参考音频得到的音色 prompt(代码中自动从第一段音频提取)
txt_smp None 参考文本(与 spk_smp 配套,代码中自动取首段文本)
temperature 0.3 音频 token 采样温度,可传长度为 4 的列表分别控制 4 层 VQ
repetition_penalty 1.05 重复惩罚
max_new_token 2048 最大生成 token 数
stream_batch 24 流式模式下每累积多少个 token 产出一次音频块
stream_speed 12000 流式模式下每个音频块的目标采样点数(约 0.5 秒 @24kHz)
pass_first_n_batches 2 流式模式跳过的首批块数(用于预热/缓冲)

6.3 词级控制:跳过 refine 直接写 token

# For word level manual control.
text = 'What is [uv_break]your favorite english food?[laugh][lbreak]'
wavs = chat.infer(text, skip_refine_text=True, params_refine_text=params_refine_text,  params_infer_code=params_infer_code)
"""
In some versions of torchaudio, the first line works but in other versions, so does the second line.
"""
try:
    torchaudio.save("word_level_output.wav", torch.from_numpy(wavs[0]).unsqueeze(0), 24000)
except:
    torchaudio.save("word_level_output.wav", torch.from_numpy(wavs[0]), 24000)

关键在 skip_refine_text=True:此时不经过第一阶段的文本润色,由用户在文本中手工插入控制 token。README FAQ 确认:当前发布模型中 token 级可控单元仅有三个——[laugh](笑声)、[uv_break](微停顿/换气感)、[lbreak](较长停顿),更细的情感控制(multi-emotion)在 Roadmap 中尚未完成。

README 还给出一个英文自我介绍的完整例子,展示了多 token 混排:

inputs_en = """
chat T T S is a text to speech model designed for dialogue applications.
[uv_break]it supports mixed language input [uv_break]and offers multi speaker
capabilities with precise control over prosodic elements like
[uv_break]laughter[uv_break][laugh], [uv_break]pauses, [uv_break]and intonation.
[uv_break]it delivers natural and expressive speech,[uv_break]so please
[uv_break] use the project responsibly at your own risk.[uv_break]
""".replace('\n', '') # English is still experimental.

params_refine_text = ChatTTS.Chat.RefineTextParams(
    prompt='[oral_2][laugh_0][break_4]',
)

audio_array_en = chat.infer(inputs_en, params_refine_text=params_refine_text)
torchaudio.save("self_introduction_output.wav", torch.from_numpy(audio_array_en[0]), 24000)

官方同时提醒:英文仍是实验性状态,效果以中文为主。

七、流式推理:低延迟音频输出

README 的 Roadmap 已勾选 "Streaming audio generation"。infer() 传入 stream=True 时返回的是生成器,而不是完整波形列表。ChatTTS/core.py_infer_code()stream_batch 传给 GPT 的 generate()(生成循环中每累积 stream_batch 个 token 触发一次中间产出),_infer() 再按 stream_speed 切片,并跳过前 pass_first_n_batches 个块,从而形成稳定的块状音频流。

examples/cmd/stream.py 给出了完整消费端实现——ChatStreamer 类:

  • base_block_size=8000 为阈值缓冲小块数据,避免过短的音频块;
  • 输出格式支持 PCM16_byte / PCM16 / 原始浮点;
  • play() 方法通过 pyaudio 以 24000 Hz / 16 位 / 单声道打开输出流,并先预缓冲 wait 秒(示例中 5 秒,适配 CPU 慢速生成的场景)再开始播放:
chat = ChatTTS.Chat()
chat.load(compile=False)
rand_spk = chat.sample_random_speaker()
params_infer_code = ChatTTS.Chat.InferCodeParams(
    spk_emb=rand_spk, temperature=0.3, top_P=0.7, top_K=20,
)
streamchat = chat.infer(
    ["总结一下,AI Agent是大模型功能的扩展……", "你太聪明啦。", "举个例子,……"],
    skip_refine_text=True,
    stream=True,
    params_infer_code=params_infer_code,
)
ChatStreamer().play(streamchat, wait=5)

命令行等价用法是 python examples/cmd/run.py --stream "text 1" "text 2",逐块 mp3 会分别落盘。

八、两阶段推理与文本预处理:源码级原理

ChatTTS/core.pyinfer()_infer()_refine_text() / _infer_code() 调用链看,ChatTTS 采用文本 LLM + 音频 LLM 的两阶段自回归架构

阶段一:文本润色(refine_text)_refine_text() 将原文包装为 [Sbreak]原文[Pbreak]prompt(见 Speaker.decorate_text_prompts),让 GPT 在文本词表上生成润色文本;随后 text_tokens = [i[i.less(break_0_ids)] ...] 会把生成的 token 截断到 [break_0] 之前,只保留"文本类"token 再解码。这一阶段负责把用户文本"口语化",并按 prompt 提示决定插入多少 [uv_break]/[laugh]

阶段二:声学码本生成(infer_code)_infer_code() 中,Speaker.decorate_code_prompts() 把每条文本包装成 [Stts][spk_emb]参考文本原文[Ptts](无指定音色时为 [empty_spk]);Tokenizer.encode()(基于 BertTokenizerFast,见 ChatTTS/model/tokenizer.py)完成左填充批处理,并把 spk_smp 解码出的 4 层 VQ prompt 拼接到序列末尾;若提供了 spk_emb 字符串,Speaker.apply() 会在每个序列的 [spk_emb] 位置写入归一化音色向量;最终 GPT 在 4 个 VQ 层(num_vq=4,对应 DVAE 的 4 级码本)上并行自回归采样,产出隐藏状态后交给 Decoder(或 DVAE)→ Vocos 还原成 24 kHz 波形。

长文本切分infer() 默认 split_text=True,按 。\s\n 切句(re.split(r"(?<=。)|(?<=\.\s)", text)),每批 max_split_batch=4 句批量推理;当输入多句且未指定 spk_smp 时,代码会先用首句推理一次,从中提取音色(sample_audio_speaker)回填到 params_infer_code.spk_smp,保证整段长文音色一致。

文本正则化与同音字替换ChatTTS/norm.py 中的 Normalizer 在推理前做:语言检测(中文字符数 vs 英文单词数)、半角转全角(中文)、标点简化、非法字符剔除,以及基于 ChatTTS/res/homophones_map.json同音字替换——用 numba JIT 加速的逐字替换表,把模型容易读错的字换成同音正确字(注释中说明该映射来自 1.8 百万词条语料上约 18 万读错词的统计结果)。infer()do_text_normalization / do_homophone_replacement 参数可分别关闭这两类处理。

零填充裁剪:非流式返回前,infer() 会对每段波形做 wav[np.abs(wav) > 1e-5] 的首尾静音裁剪,并在 split_text 时拼接成单段返回。

九、资源需求与 FAQ(README 原文)

1. 显存需求与推理速度? README 给出的官方数据:合成 30 秒音频至少需要 4 GB 显存;RTX 4090 上生成速度约为 7 个语义 token/秒,实时因子(RTF)约 0.3。注意这是官方 FAQ 的表述,实际取决于设备、batch 与是否启用 vLLM/compile。

2. 模型稳定性不足(多说话人串音、音质差)怎么办? 官方解释这是自回归模型(与 bark、valle 类似)的通病,较难完全避免,建议多次采样挑选满意的结果(调低 temperature、换 manual_seed 是常用手段)。

3. 除笑声外还能控制什么?能控制其他情绪吗? 当前发布模型中 token 级控制单元只有 [laugh][uv_break][lbreak];更多情绪控制能力官方表示"未来版本可能开源"(与 Roadmap 的 "Multi-emotion controlling" 未完成项对应)。

十、小结

ChatTTS 以 20 层、768 维的自回归 GPT 为核心,配合 4 层 VQ 音频 tokenizer 与 Vocos 声码器,通过"文本润色 → 声学码本生成"的两阶段流程实现口语化、可细粒度控制的对话语音合成。上手路径非常清晰:pip install ChatTTS 或克隆仓库安装依赖后,一条 python examples/web/webui.py / python examples/cmd/run.py 即可出音;进阶控制则集中在 RefineTextParams.promptoral_/laugh_/break_ 三组 token、InferCodeParams 的音色字符串与采样参数,以及 skip_refine_text 下的词级 [laugh]/[uv_break]/[lbreak] 手工标记。需要强调的是:模型权重为 CC BY-NC 4.0(非商用),代码为 AGPLv3+,且官方在 40k 小时开源权重中刻意加入了高频噪声与 MP3 压缩以限制滥用,使用时应遵循相应许可并负责任地应用该能力。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384