ChatTTS 对话式 TTS 模型实战:从安装部署到细粒度韵律控制的完整指南
【免费下载链接】ChatTTSA generative speech model for daily dialogue.项目地址: https://gitcode.com/GitHub_Trending/ch/ChatTTS
本文基于 ChatTTS 仓库的官方韩语文档(docs/kr/README.md)并结合仓库源码,系统讲解这个面向日常对话场景的生成式语音模型的定位、能力边界、完整的安装部署流程,以及最核心的多说话人采样、RefineTextParams/InferCodeParams参数控制、句级与词级韵律标记([laugh]、[uv_break]、[lbreak]等)和流式音频生成的实战用法。读完本文,你可以独立完成从克隆仓库到产出可控韵律音频的全链路操作,并理解每个控制参数在源码中的实际作用。
项目定位:为对话任务设计的 TTS 模型
ChatTTS 是一个为对话类任务(例如 LLM 助手语音交互)而设计的文本转语音(TTS)模型,其设计目标是输出自然、富表现力的对话语音。根据官方文档,该项目当前:
- 支持语言:英语、中文(持续扩展中,英文仍处于实验阶段);
- 核心特点:
- 对话式 TTS:针对对话场景优化,支持多说话人,可用于交互式对话;
- 细粒度控制:可预测并控制笑声、停顿、插入语等韵律细节;
- 增强韵律:在韵律表现上优于多数开源 TTS 模型,并提供预训练权重支持二次研究。
数据与模型规模方面,官方说明如下(适用前提:当前仓库所公开的权重):
- 主模型使用100,000+ 小时的中英文音频数据训练;
- 公开下载的是40,000 小时预训练模型,且未应用 SFT(监督微调),因此稳定性与最终效果存在差距;
- 公开模型仅限学术用途。
路线图(截至文档版本):40,000 小时模型与 spk_stats 文件已开源、流式音频生成已实现、DVAE 编码器与零样本推理代码已开源;多情感控制与 ChatTTS.cpp(C++ 推理后端)仍待完成。
许可证与反滥用机制
使用前必须了解两个层面的限制,这在源码与文档中均被强调:
| 对象 | 许可证 | 说明 |
|---|---|---|
| 代码 | AGPLv3+ | 见 LICENSE |
| 模型权重 | CC BY-NC 4.0 | 仅教育与研究用途,禁止商业或非法使用 |
面免责/反滥用设计:为防止技术被恶意滥用,官方在 40,000 小时模型训练末期加入了少量高频率噪声,并将音频质量尽量压缩后以MP3 格式提供;团队同时训练了内部检测模型,计划后续开源。理解这一点有助于解释为何输出音质带有一定的"压缩感"。
环境准备与依赖安装
1. 克隆仓库
git clone https://gitcode.com/GitHub_Trending/ch/ChatTTS cd ChatTTS2. 安装依赖
方式一:直接安装
pip install --upgrade -r requirements.txt方式二:Conda 环境(推荐隔离)
conda create -n chattts conda activate chattts pip install -r requirements.txt对照 requirements.txt 可以看到核心依赖包括:numpy<3.0.0、numba(规范化器中 JIT 加速)、torch>=2.1.0、torchaudio、transformers>=4.41.1(BertTokenizerFast)、vocos(声码器)、gradio(WebUI)、pybase16384(说话人编码)、pydub/av(音频处理)等。其中pynini==2.1.5、WeTextProcessing、nemo_text_processing仅在Linux 平台(sys_platform == 'linux')引入,它们对应命令行示例中的中英文文本规范化器(见后文 examples/cmd/run.py 的load_normalizer)。
可选:vLLM(仅 Linux)
pip install safetensors vllm==0.2.7 torchaudiovLLM 路径对应源码中Chat._load(..., use_vllm=True)分支:当gpt.is_vllm为真时,推理会走 ChatTTS/model/velocity 目录下的引擎(llm_engine.py、model_runner.py、sampler.py等,结构上仿照 vLLM 的调度器/块管理器实现),而 ChatTTS/core.py 中_infer_code对 vLLM 与非 vLLM 有两条独立的生成路径。
不推荐的两个选项(官方文档明确给出警告,原样保留结论):
- TransformerEngine(NVIDIA GPU,仅 Linux):不要安装!适配工作尚处于开发中,目前无法正常工作,仅限开发目的。相关 issue 为 #672 与 #676。
- FlashAttention-2(主要面向 NVIDIA GPU):不要安装!据上游 transformers 仓库 issue #26990,FlashAttention-2 在当前场景下会降低生成速度。
这两个警告与源码相互印证:ChatTTS/core.py 的load()暴露了use_flash_attn参数,而 ChatTTS/model/cuda/patch.py 与te_llama.py正是 TransformerEngine/FlashAttention 的适配层——从源码结构看,这部分仍是实验性代码路径。
三种安装方式
# 1. 从 PyPI 安装稳定版 pip install ChatTTS # 2. 从 GitHub 源安装最新版 pip install git+https://gitcode.com/GitHub_Trending/ch/ChatTTS # 3. 本地目录开发模式安装 pip install -e .开发模式安装的打包逻辑见 setup.py。
快速开始:WebUI 与命令行
以下命令必须在项目根目录执行。
运行 WebUI(基于 Gradio)
python examples/web/webui.py命令行推理
python examples/cmd/run.py "Your text 1." "Your text 2."生成的音频会保存为当前目录下的./output_audio_n.mp3(n 为序号)。
结合 examples/cmd/run.py 的argparse定义,该脚本支持完整参数如下:
| 参数 | 类型/默认值 | 作用 |
|---|---|---|
texts | 位置参数,argparse.REMAINDER | 待合成的文本列表 |
--spk | Optional[str],默认None | 指定说话人编码字符串;缺省时调用chat.sample_random_speaker()随机采样 |
--stream | 布尔开关 | 启用流式模式(逐块输出并分别保存,再拼接总文件) |
--source | local/huggingface/custom,默认local | 模型来源 |
--custom_path | 默认空 | 自定义模型资产目录(配合--source custom) |
从 examples/cmd/run.py 可以看到,命令行推理本质上是chat.infer(texts, stream, params_infer_code=ChatTTS.Chat.InferCodeParams(spk_emb=spk))的一层封装:先加载模型,采样/取用说话人,再按InferCodeParams(spk_emb=spk)固定音色进行合成,音频经pcm_arr_to_mp3_view转 MP3 落盘。
Python API 基础用法与加载参数
最小可用示例
import ChatTTS import torch import torchaudio chat = ChatTTS.Chat() chat.load(compile=False) # 性能导向可设为 True texts = ["PUT YOUR 1st TEXT HERE", "PUT YOUR 2nd TEXT HERE"] wavs = chat.infer(texts) for i in range(len(wavs)): """ 视 torchaudio 版本差异,第一行或第二行可能生效。 """ 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.py 的FeatureExtractorInitArgs中,Vocos 特征提取器即配置为sample_rate=24000, n_fft=1024, hop_length=256, n_mels=100,声码器输出即该采样率的波形。
load()的完整参数(源码级)
文档示例只展示了chat.load(compile=False),而 ChatTTS/core.py 中load()的完整签名还包括多个实战有用选项:
chat.load( source="local", # "huggingface" / "local" / "custom" force_redownload=False, # 强制重新下载模型资产 compile=False, # torch.compile 加速,仅对 cuda 设备生效 custom_path=None, # source="custom" 时的本地资产目录 device=None, # 指定设备,默认自动选择 coef=None, # DVAE 的 codec 系数字符串(一般不填) use_flash_attn=False, # 官方警告:目前不建议开启 use_vllm=False, # 需要安装 vllm,走 velocity 推理引擎 experimental=False, enable_cache=True, )几个值得注意的实现细节(均以 ChatTTS/core.py 为准):
- 模型资产与校验:
download_models按source分为三条路径——local(当前工作目录,按 ChatTTS/res/sha256_map.json 逐个校验 sha256,缺失才下载)、huggingface(snapshot_download拉取2Noise/ChatTTS,允许*.yaml/*.json/*.safetensors)、custom(仅校验不下载)。资产路径模板定义在 ChatTTS/config/config.py 的Path:asset/Vocos.safetensors、asset/DVAE.safetensors、asset/gpt、asset/Decoder.safetensors、asset/tokenizer、asset/Embed.safetensors; compile的实际生效条件:gpt.prepare(compile=compile and "cuda" in str(device)),即只有 CUDA 设备下compile=True才真正编译;- 设备回退:
device_gpt在 MPS 设备下强制回退 CPU,Vocos 在 mps/npu 下也回退 CPU 执行,这是 Apple Silicon 用户能跑通的原因之一; unload():提供显式卸载接口,删除vocos/gpt/decoder/dvae/tokenizer/embed六个模块后重置内部状态。
infer()的完整参数(源码级)
ChatTTS/core.py 中infer()的签名比文档示例丰富得多,各参数默认值如下:
chat.infer( text, stream=False, # 流式生成,返回 generator lang=None, # "zh" / "en",None 时自动检测 skip_refine_text=False, # 跳过"文本润色"阶段(词级控制必须开启) refine_text_only=False, # 只输出润色后的文本 use_decoder=True, # True 用独立 Decoder,False 用 DVAE 解码 do_text_normalization=True,# 文本规范化(数字、标点等) do_homophone_replacement=True, # 同音字纠错替换 split_text=True, # 按 。 或 .(后跟空白)切分长句 max_split_batch=4, # 每批最多句数 params_refine_text=RefineTextParams(), params_infer_code=InferCodeParams(), )其中split_text的切分逻辑在源码中是re.split(r"(?<=。)|(?<=\.\s)", text)(见 ChatTTS/core.py),即按中文句号或英文"句点+空格"做 lookbehind 切分;多句输入时,系统会先合成第一句,再用sample_audio_speaker从第一句波形中编码出spk_smp(说话人提示)供后续句子复用,从而保证长文本内音色一致——这正是 ChatTTS/core.py 中spk_smp is None分支的作用。
文本规范化:为什么"错字"会被自动纠正
do_homophone_replacement背后的实现是 ChatTTS/norm.py 的Normalizer类,其处理流水线为:
- 语言检测:统计中文字符与英文单词数量,取多者(
_detect_language); - 按语言规范化:
[标签]会被_split_tags单独抽出保护起来,避免被规范化器破坏,再拼回(_combine_tags); - 无效字符清理:
reject_pattern仅保留中日韩汉字、英文字母与,。、,. 空格,其余字符被替换/剔除; - 半角转全角(中文场景)与标点统一(
:→,、!→。等映射表); - 同音字纠错:基于 ChatTTS/res/homophones_map.json 的映射表,用 numba JIT 的
_fast_replace以 utf-16 编码快速逐字替换。该映射表据源码注释由 1200 万词条语料清洗后约 180 万条、结合约 18 万误读词统计构建。
这意味着送入模型前的文本会先经过一轮"发音安全"处理,特殊韵律标签([laugh]等)在此过程中被显式保护,这是后文词级控制能生效的前提。
高级用法:说话人采样与两级推理参数
1. 采样说话人
################################### # 从高斯分布采样一个说话人。 rand_spk = chat.sample_random_speaker() print(rand_spk) # 保存该字符串,用于日后恢复同一音色rand_spk是一个自包含的字符串编码,可以随时打印、保存、复用以恢复音色。其实现链路在 ChatTTS/model/speaker.py:
- 配置类
GPT中spk_emb_dim = 192(见 ChatTTS/config/config.py),即说话人向量是 192 维; _sample_random执行randn(dim) * std + mean,均值/标准差来自Config.spk_stat中用 base16384 编码的预训练统计量,因此采样结果落在训练分布内;_encode将 float16 向量经LZMA 极限压缩 + base16384 编码变成字符串,所以打印出来是一大串"乱码"字符——这不是哈希,而是可逆的压缩表示;- 合成时,
Speaker.apply(ChatTTS/model/speaker.py)会反解字符串、做 L2 归一化,然后把所有[spk_emb]位置的嵌入直接替换为该说话人向量(torch.where条件替换),从而在解码前就锁定音色。
此外还有一个反向操作:chat.sample_audio_speaker(wav)可从一段波形(经 DVAE 编码)反推说话人编码,用于零样本复刻参考音频的音色。
2. 句级控制:RefineTextParams与InferCodeParams
ChatTTS 的推理是两阶段的:第一阶段_refine_text让 GPT 把输入文本"润色"成带韵律标记的文本(对应RefineTextParams),第二阶段_infer_code再生成音频 token(对应InferCodeParams)。文档示例如下:
################################### # 句级手动控制。 # 使用 oral_(0-9), laugh_(0-2), break_(0-7) # 在文本中生成特殊韵律 token。 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, )prompt会被 ChatTTS/model/speaker.py 的decorate_text_prompts包装成[Sbreak]{文本}[Pbreak]{prompt}送入润色阶段,引导模型在输出中插入对应强度(0~9 / 0~2 / 0~7)的口语化程度、笑声、停顿标记。润色后的 token 会先被过滤到break_0_ids以下再解码为文本(ChatTTS/core.py),这些标记随文本进入第二阶段。
两个参数类的完整默认值(摘自 ChatTTS/core.py 的数据类定义,ChatTTS/core.py):
RefineTextParams(文本润色阶段)
| 字段 | 默认值 | 说明 |
|---|---|---|
prompt | "" | 韵律引导,如'[oral_2][laugh_0][break_6]' |
top_P | 0.7 | top-p 采样 |
top_K | 20 | top-k 采样 |
temperature | 0.7 | 温度 |
repetition_penalty | 1.0 | 重复惩罚 |
max_new_token | 384 | 最大新 token 数 |
min_new_token | 0 | 最小新 token 数 |
show_tqdm | True | 进度条 |
ensure_non_empty | True | 保证输出非空(空输出重采样) |
manual_seed | None | 手动随机种子 |
InferCodeParams(音频 token 生成阶段,继承自上表)
| 字段 | 默认值 | 说明 |
|---|---|---|
prompt | "[speed_5]" | 默认引导语速等级 |
spk_emb | None | 说话人编码字符串(如sample_random_speaker()返回值) |
spk_smp | None | 由参考音频编码的说话人 prompt(多句自动填充) |
txt_smp | None | 参考文本 prompt |
temperature | 0.3 | 注意比润色阶段低,音频解码更保守 |
repetition_penalty | 1.05 | 略高于 1,抑制 token 循环 |
max_new_token | 2048 | 每句音频 token 上限 |
stream_batch | 24 | 流式模式下每批 token 数 |
stream_speed | 12000 | 流式切片步长(采样点数) |
pass_first_n_batches | 2 | 流式模式丢弃前 N 个 batch(预热) |
temperature在代码层面还支持传列表(按 4 个 VQ 层级分别设置,见 ChatTTS/core.py),num_vq=4来自配置中 4 层向量量化(levels=(5,5,5,5),音频词表 626 个 token、文本词表 21178 个,见 ChatTTS/config/config.py 的GPT/Embed定义)。
3. 词级控制:skip_refine_text与文本内嵌标签
句级控制是"引导模型去加标记",而词级控制是把韵律标签直接写进文本,并跳过润色阶段让模型严格照读:
################################### # 词级手动控制。 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) 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)文档 FAQ 中明确:当前公开模型可控制的 token 为[laugh]、[uv_break]、[lbreak](词级),以及润色阶段的oral_(0-9)、laugh_(0-2)、break_(0-7)(句级);更多情感控制留待后续版本开源。
skip_refine_text=True的必要性可以从 ChatTTS/core.py 印证:若不跳过,_refine_text会重写文本,你手工放置的标签位置就无法保证;跳过之后,文本经规范化(标签被_split_tags保护)直接进入_infer_code。另外,ChatTTS/model/speaker.py 的decorate_code_prompts会在送入编码前把文本中的[Stts]、[spk_emb]、[empty_spk]占位符剥离,避免与内部特殊 token 冲突(对应上游 issue #459 的修复)。
4. 官方示例:带韵律标记的自我介绍
文档附带了一个英文示例(英文输出仍为实验性),完整保留:
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', '') 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)流式音频生成
文档将"流式音频生成"列为已完成路线项,对应infer(stream=True)。从源码看其机制(ChatTTS/core.py):
- 生成按
stream_batch=24个 token 一批推进,每个 batch 完成即解码出一段波形; - 前
pass_first_n_batches=2个 batch 被直接丢弃(continue),用于跳过不稳定预热段; - 之后按
stream_speed=12000个采样点的步长切片yield,最后一段按能量阈值(1e-5)裁掉静音列。
仓库提供了完整的流式消费者示例 examples/cmd/stream.py:其ChatStreamer类负责把生成器输出缓冲、按 8000 点基础块累积,转为PCM16 字节流(float_to_int16+<i2小端),并以 24000 Hz 单声道 16 位通过 PyAudio 播放(play(streamchat, wait=5),先预缓冲 5 秒再开播,适配 CPU 等慢速设备)。命令行版本则可用:
python examples/cmd/run.py --stream "第一段文本" "第二段文本"流式输出会分别保存每个块文件,再拼接出完整output_audio_n.mp3。
常见问题(FAQ)
Q1:需要多少显存?推理速度如何?
官方文档给出的数字:生成约 30 秒音频片段最少需要4GB 显存;在 4090 GPU 上约每秒生成 7 个语义 token 对应的音频,RTF 约 0.3。这些是文档口径的参考值,实际受use_vllm、compile、批次与序列长度影响。
Q2:模型偶发不稳定,多说话人场景下音色/音质波动?
官方解释:这是自回归模型(bark、valle 等)的固有难题,当前最佳实践是多次采样、择优保留。这也解释了infer默认ensure_non_empty=True(空输出自动重试)与manual_seed参数的存在。
Q3:除了笑声还能控制其他情感吗?
当前公开模型可控制的 token 仅[laugh]、[uv_break]、[lbreak](以及句级的oral_/laugh_/break_强度档位);更多情感控制计划在后续版本中开源(见路线图中的"多情感控制功能"未勾选项)。
延伸阅读与仓库内相关路径
- 韩语原文档:docs/kr/README.md(并排提供 英文、简体中文、日文、俄文、西班牙文、法文 版本;官方提示韩语文档可能滞后于英文主文档,以英文版为最新基准)
- 核心 API 与两阶段推理:ChatTTS/core.py
- 模型结构与词表配置:ChatTTS/config/config.py
- 说话人采样/编码:ChatTTS/model/speaker.py
- 文本规范化与同音字纠错:ChatTTS/norm.py、ChatTTS/res/homophones_map.json
- 分词器(
BertTokenizerFast、[spk_emb]/[break_0]/[Ebreak]特殊 token):ChatTTS/model/tokenizer.py - vLLM 推理引擎(velocity 目录):ChatTTS/model/velocity
- 示例:WebUI examples/web/webui.py、命令行 examples/cmd/run.py、流式 examples/cmd/stream.py、ONNX 导出 examples/onnx/exporter.py
- 依赖清单:requirements.txt、打包:setup.py、协议:LICENSE
使用提醒:公开权重仅限学术与研究方向,音频输出自带训练期注入的高频噪声与 MP3 压缩特性,属于官方反滥用设计的一部分;集成到自己的 LLM 助手前请先在本地充分验证稳定性,并遵守 CC BY-NC 4.0 对模型权重的使用限制。
【免费下载链接】ChatTTSA generative speech model for daily dialogue.项目地址: https://gitcode.com/GitHub_Trending/ch/ChatTTS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考