C16 Text-to-Speech
16.1 Overview
/assets/c16-figure-16-1-valle-overview.png)
VALL-E 是一个 personalized TTS 系统,用来说明现代 zero-shot TTS 的基本思路:用少量目标说话人的语音作为 prompt,让模型生成同一声音风格下的新文本语音。
VALL-E 的训练数据规模很大:约 60K 小时英文语音,来自 7000+ 个不同说话人。
系统主要有两个组件:
- Audio tokenizer:通常基于 audio codec。codec 包含 encoder、quantizer、decoder 三部分:
- encoder:把 speech 转成 embedding vectors
- quantizer:把 embeddings 离散化成 discrete tokens
- decoder:把 discrete tokens 还原成 speech
- Two-stage conditional language model:根据 text prompt 和 enrolled speech prompt 生成对应目标文本的 audio tokens。
VALL-E 的训练与推理
VALL-E 的任务形式很像 in-context learning for speech:给模型一小段目标说话人的语音 prompt,再给它要合成的新文本,让它生成同一个声音风格下的新语音。
但这里更准确的说法是 zero-shot TTS,不是 few-shot fine-tuning:
Summary
zero-shot 指的是:目标说话人在训练中可以没出现过,推理时只给一小段 enrolled recording,模型参数不针对这个人更新。
训练阶段,VALL-E 学的是一个通用条件生成问题:
也就是说,模型在大量说话人、大量语音上学习:
这里的 prompt speech 不是用来“重新训练这个人的模型”,而是作为条件输入,告诉模型目标声音的 speaker identity、音色、韵律等信息。
推理阶段:
所以可以这样理解:
| 阶段 | 做什么 | 是否更新模型参数 |
|---|---|---|
| Training | 用大量说话人的数据学习“文本 + 语音 prompt → 目标语音 tokens”的条件生成规律 | 是 |
| Inference | 给一个新说话人的短音频 prompt 和新文本,生成该说话人声音的新语音 | 否 |
一句话:
Summary
VALL-E 不是为每个新说话人重新训练;它是在训练时学会“如何利用 prompt speech 控制声音”,在推理时用 3 秒 enrolled recording 作为条件来做 zero-shot voice cloning / personalized TTS。
codec / tokenizer:
16 kHz 采样率、16-bit 格式的语音,可以看作每个采样点从 个可能符号里取一个值,并且每秒有 16,000 个采样点。
问题是原始 waveform 序列太长了。如果直接把每个采样点当作 token,语言模型每秒就要处理 16,000 个 token,建模成本太高。
所以现代 TTS / speech LM 希望用更短的离散表示:把语音压缩成每秒大约几百个 audio tokens,而不是每秒 16,000 个 waveform samples。
Codec 压缩链条
codec 的核心 pipeline:
其中 x 是原始 waveform 序列,z 是 encoder 输出的连续 latent embeddings,q 是 quantizer 选出的 discrete codebook ids,z_q 是查表或求和后的量化 latent 表示,x_hat 是 decoder 重建出的 waveform。
关键区分:
75 Hz 指的是 codec latent frame rate:1 秒音频经过 encoder 后变成 75 个 latent embeddings。
下采样倍率:
也就是每个 latent 时间步大约覆盖 320 个原始采样点。在 24 kHz 下:
可以理解为:encoder 把原始波形压成每 13.3 ms 一个 latent vector。
但 75 个 embedding 不等于 75 个 id。encoder 输出的是连续向量:
每个 z_t 是 D 维 continuous embedding,整体形状类似:
真正的离散 token 化发生在 quantizer:
如果是单 codebook,可以近似看成:
但 EnCodec 这类 codec 通常用 RVQ,也就是多 codebook。每个 latent frame 会对应多个 codebook ids:
所以最终 audio tokens/sec 更准确地写成:
例如每帧 8 个 codebooks:
这就对应前面说的 “a few hundred tokens a second”。
完整链条:
最短记法:
Summary
24 kHz 是 waveform 采样率:每秒 24000 个点。75 Hz 是 codec latent 帧率:每秒 75 个向量。最终 audio tokens/sec 通常是 。
Vector Quantization (VQ)
VQ 的核心目标:
在早期语音压缩里,VQ 用来降低传输或存储的比特率:不传一大串浮点向量,而是传一个整数 index;接收端再根据这个 index 查回对应向量。
在现代 TTS / speech LM 里,VQ 的意义是把 speech representation 变成离散 audio tokens,因为语言模型天然适合建模离散 token 序列。
最短 shape:
也就是:encoder 输出连续向量 v,VQ 在 codebook 中找最近的 codeword,并输出这个 codeword 的 index;这个 index 就是离散 audio token。
例如 codebook 里有 1024 个候选向量:
如果 v 离 codeword 3 最近:
对应到前面的 codec pipeline:
一句话:
Summary
VQ 就是“连续向量找最近码字,输出码字编号”。
VQ 训练:k-means 视角
VQ 有两个阶段:训练阶段和推理阶段。基础 VQ 的训练通常可以用 k-means 来理解。
训练时,大量 speech waveform 先经过 encoder,得到 N 个连续向量。然后把这 N 个向量聚成 k 个 clusters,其中:
k 是设计者设置的 codebook size,也就是希望有多少个离散符号。
k-means 反复执行两个步骤:
- Assignment step:给定当前
k个 centroids,把每个向量分配到最近的 cluster,距离通常用平方欧氏距离。 - Re-estimation step:对每个 cluster,重新计算其中所有向量的平均值,并把这个平均值作为新的 centroid。
聚类结束后:
推理时,一个新的 encoder 向量进来,只需要和 codebook 中所有 codewords 比较,找到最近的 codeword,并输出它的 index。
Codebook 更新:EMA 视角
普通 k-means 要看完整数据集;神经网络训练通常只能一小批一小批看数据。EMA 是用 minibatch 近似全数据均值的一种稳定办法。
普通 k-means 中,如果某个 codeword 负责一组 encoder 向量:
那这个 codeword 应该更新成这些向量的平均值:
但训练 EnCodec / VQ-VAE 这类模型时,每一步只看到一个 minibatch。如果直接用当前 batch 的均值更新 codeword,codebook 会很抖。
EMA 的思想:
Note
新的 codeword 不完全相信当前 batch,而是大部分保留过去的累计估计,只少量吸收当前 batch 的信息。
公式:
例如 decay = 0.99:
放到 VQ 里:
也就是:
VQ 里的硬选择:
这个 argmin 是离散操作,不方便直接求梯度。VQ-VAE 通常用 straight-through estimator 让 encoder 能训练;codebook 本身可以用梯度更新,也可以用 EMA 更新。
两种更新方式的区别:
| 更新方式 | 直觉 |
|---|---|
| 梯度更新 | 把 codebook 当普通参数,用 loss 推 |
| EMA 更新 | 把 codebook 当聚类中心,用被分配到它的 z 的均值推 |
在 audio codec 里,EMA 常常更稳,因为它明确让每个 codeword 代表一簇 encoder latent。
最短句:
Summary
EMA 用在 VQ codebook 更新里,是为了在 minibatch 训练中稳定地估计每个 codeword 的聚类中心;它相当于在线 k-means,避免 codebook 被单个 batch 的噪声带着乱跑。
VALL-E: Generating audio with 2-stage LM
Missing image: Pasted image 20260430202607.png
任务
speech 应用可以先按任务形态粗分:
| 大类 | 问题 |
|---|---|
| ASR | 语音 → 文本 |
| TTS | 文本 → 语音 |
| Audio Chat / Spoken Dialogue | 语音 ↔ 语音 / 文本,多轮交互 |
| Speaker Diarization | 谁在什么时候说话 |
| Speaker Recognition | 这个人是谁 / 是不是某个人 |
| Language Identification | 这段语音是什么语言 |
| Wake Word Detection | 有没有说出唤醒词 |
其中现在最前沿、也最接近我关心的,是 Audio Chat / Spoken Dialogue。它不只是简单的 ASR + LLM + TTS pipeline,而是在往更端到端的方向走:
Speaker Recognition又可细分以下两个子任务:
| 子任务 | 判断形式 | 例子 |
|---|---|---|
| Speaker verification | 二分类:这个人是不是指定说话人 X? | 电话访问个人信息时的身份验证 |
| Speaker identification | N 选 1:把当前说话人的声音和数据库中的多个说话人匹配 | 从候选说话人库中识别身份 |
Summary
Diarization 关心“谁在什么时候说话”;speaker recognition 关心“这个人是谁”;language identification 关心“说的是什么语言”;wake word detection 关心“有没有说出触发短语”。