VCTK 多说话人语音合成实战:基于 fairseq S² 工具包的 Transformer TTS 全流程指南
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
VCTK 是 open 的多说话人英语语音语料库,本指南基于 fairseq S²(Speech Synthesis)工具包,完整讲解从 VCTK 原始音频到 Transformer TTS 模型训练、推理与自动评估的端到端流程。读完本文你将掌握:音频 manifest 生成、基于信号处理的去噪与 VAD 清洗、基于 ASR 的 CER 样本过滤、log-Mel 特征提取与配置生成,以及 MCD/CER 等指标驱动的模型开发闭环。本文是 VCTK 示例文档 的深度扩展,与之配套的 LJSpeech 单说话人示例 与 Common Voice 示例 分别覆盖了单说话人与其他多说话人场景,可相互参照。
1. 任务概览:在 VCTK 上构建多说话人 TTS
VCTK(CSTR VCTK Corpus)是爱丁堡大学发布的 open 英语语音语料库,包含超过 100 位不同口音说话人的朗读语音,因此天然适合训练多说话人语音合成模型。fairseq S² 工具包(论文 arXiv:2109.06912,参见 speech_synthesis 总览)提供了完整的语音合成流水线:
- 自回归(Transformer TTS)与非自回归(FastSpeech 2)模型;
- 面向多说话人合成的 speaker embedding 支持;
- 面向低质量控制数据(如众包语料)的去噪、VAD 等音频预处理;
- 用于模型迭代的自动评估指标(ASR 的 WER/CER、信号级的 MCD/MSD、韵律相关的 F0 指标);
- 与 S2T(语音到文本)一致的轻量数据配置格式(
config.yaml+ TSV manifest)。
VCTK 示例的整体流水线如下,本文按此顺序展开:
VCTK 原始音频 │ get_vctk_audio_manifest ▼ 音频 manifest(train/dev/test 切分) │ denoise_and_vad_audio(可选清洗) ▼ 处理后的音频 manifest(含 SNR 列) │ ASR CER 过滤(可选,eval_asr) ▼ 保留的低 CER 样本 │ get_feature_manifest(--ipa-vocab --use-g2p) ▼ 特征 manifest + config.yaml + vocab.txt + speakers.txt │ fairseq-train --task text_to_speech ▼ Transformer TTS 模型 → 推理波形 → 自动评估(MCD / CER / F0)2. 数据准备
2.1 下载数据、切分并生成音频 manifest
首先下载 VCTK 数据集,创建数据切分并生成音频 manifest:
python -m examples.speech_synthesis.preprocessing.get_vctk_audio_manifest \ --output-data-root ${AUDIO_DATA_ROOT} \ --output-manifest-root ${AUDIO_MANIFEST_ROOT}这一步由 get_vctk_audio_manifest.py 实现,其内部逻辑可以从源码确认:
- 基于
torchaudio.datasets.VCTK读取数据集,--output-data-root(即-d)指向数据存放目录,--output-manifest-root(即-m)指向 manifest 输出目录; - 固定切分策略:全部样本先以
--seed 1234(默认)打乱,然后划出--n-dev 50个 dev 样本与--n-test 100个 test 样本,其余全部归入 train,三个切分分别输出${split}.audio.tsv(SPLITS = ["train", "dev", "test"]); - 每个样本的 manifest 记录五列:
id、audio(wav 绝对路径,按说话人目录组织)、n_frames、tgt_text、speaker、src_text; - 文本会经过
normalize_text清洗:re.sub(r"[^a-zA-Z.?!,'\- ]", '', text),即仅保留英文字母、空格与常见标点,剔除多余字符。
提示:若需自定义切分规模,可调整
--n-dev、--n-test与--seed;默认的 50/100 划分与文档中的结果表(Test MCD 3.4)对应。
2.2 使用信号处理去噪与 VAD 清洗音频
VCTK 作为多说话人语料,部分录音可能存在环境噪声或首尾静音。fairseq S² 提供基于信号处理(而非深度学习语音增强)的去噪 + VAD(语音活动检测)预处理脚本:
for SPLIT in dev test train; do python -m examples.speech_synthesis.preprocessing.denoise_and_vad_audio \ --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ --output-dir ${PROCESSED_DATA_ROOT} \ --denoise --vad --vad-agg-level 3 done该命令对应 denoise_and_vad_audio.py,运行后会:
- 在
${PROCESSED_DATA_ROOT}下新建after_denoise/与after_vad/两个子目录分别存放两阶段的产物; - 加载预训练语音增强模型
master64()(来自preprocessing/denoiser,即 Demucs 系列模型)对音频去噪,并通过--dry-wet 0.01(默认)控制干湿信号线性插值比例,即保留 1% 原始信号以防止过度增强; - 使用 WebRTC VAD(依赖
webrtcvad,需要pip install webrtcvad)裁剪首尾与长段静音,--vad-agg-level取值范围为 0–3,数值越大过滤越激进(文档示例用 3); - VAD 后会重新计算
n_frames,并计算增强前后信号的 SNR 写入 manifest 新增的snr列;如果某样本 VAD 后长度小于MIN_T = 0.05秒(即不足 50ms 有效语音),会被直接跳过并打印 WARNING——这类"几乎无语音"的样本不应进入训练集; - 最终在
${PROCESSED_DATA_ROOT}下生成与输入同名的新音频 TSV,其audio列指向处理后的文件路径,并新增一列 SNR(未做 VAD 处理的样本为 -1)。
需要说明的是,--device默认是cpu,去噪模型支持cpu | cuda;如果样本量较大,建议显式传--device cuda加速。
2.3 使用 CER 进行样本过滤
VCTK 语料中个别样本可能发音与标注文本不一致(噪声、口误、字幕错误等),会显著拉低 TTS 质量。文档给出的策略是用 ASR 的字符错误率(CER)做过滤,具体做法复用 LJSpeech 示例 的自动评估流程:
- 对参考(reference)音频跑 wav2vec 2.0 ASR,需要在
get_eval_manifest中加--eval-target,使其评估对象是参考音频而非模型合成音频; - 在
eval_asr中加--err-unit char,把默认的 WER(词错误率)换成 CER(字符错误率)——由 eval_asr.py 源码可见,--err-unit支持word与char两种单位,char模式下逐字符计算编辑距离; - 示例级 CER 会保存为
${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv——从源码看该文件含三列id、audio、uer,其中uer即 utterance error rate,取值保留 4 位小数。
# 先按 ljspeech_example.md 生成评估 manifest(eval-target 指向参考音频) python -m examples.speech_synthesis.evaluation.get_eval_manifest \ --generation-root ... --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ --output-path ${EVAL_OUTPUT_ROOT}/eval_cer_${SPLIT}.tsv \ --eval-target --vocoder griffin_lim --sample-rate 22050 --audio-format flac # 计算字符级错误率 python -m examples.speech_synthesis.evaluation.eval_asr \ --audio-header syn --text-header text --err-unit char --split ${SPLIT} \ --w2v-ckpt ${WAV2VEC2_CHECKPOINT_PATH} --w2v-dict-dir ${WAV2VEC2_DICT_DIR} \ --raw-manifest ${EVAL_OUTPUT_ROOT}/eval_cer_${SPLIT}.tsv \ --asr-dir ${EVAL_OUTPUT_ROOT}/asr_cer注意:ASR 模型通常在 16kHz 下工作,若原音频采样率不是 16kHz,需先在特征/波形阶段重采样(参见下文推理与评估章节的 16kHz 说明),否则
eval_asr会在prepare_w2v_data中断言sr == sample_rate。
2.4 提取 log-Mel 特征并生成数据配置
完成清洗与过滤后,提取 log-Mel 频谱特征、生成特征 manifest 与数据配置 YAML:
python -m examples.speech_synthesis.preprocessing.get_feature_manifest \ --audio-manifest-root ${PROCESSED_DATA_ROOT} \ --output-root ${FEATURE_MANIFEST_ROOT} \ --ipa-vocab --use-g2p \ --snr-threshold 15 \ --cer-threshold 0.1 --cer-tsv-path ${EVAL_OUTPUT_ROOT}/uer_cer.${SPLIT}.tsv其中使用了音素输入(--ipa-vocab --use-g2p),即先把文本转成 IPA 音素序列再进入模型;同时按文档设定进行样本过滤:SNR 阈值 15、CER 阈值 10%。这条命令对应 get_feature_manifest.py,其内部行为可从源码确认:
- 特征提取:对每个样本做
convert_waveform重采样(默认--sample-rate 22050,可加--normalize-volume做响度归一),然后提取 80 维 log-Mel 谱(logmelspec80),默认--win-length 1024、--hop-length 256、--n-fft 1024、--n-mels 80、--f-min 20、--f-max 8000;特征打包为logmelspec80.zip,同时计算全局 CMVN 统计量gcmvn_stats.npz用于特征归一化; - 样本过滤:
--snr-threshold 15表示丢弃snr低于 15 的样本;--cer-threshold 0.1结合--cer-tsv-path丢弃 CER 高于 10% 的样本(源码会从 CER TSV 读入每个样本的uer并与阈值比较); - 文本归一化:在 IPA 模式下,
normalized_utt = ipa_phonemize(normalized_utt, lang="en-us", use_g2p=True),即通过 g2p 工具把英文文本转成 IPA 音素串(默认--lang en-us); - 产物:为每个 split 生成
${split}.tsv特征 manifest(含id/audio/n_frames/tgt_text/speaker/src_text列)、vocab.txt(按词频排序的音素词典)、speakers.txt(说话人列表,多说话人时 config 中自动写入speaker_set_filename)、以及config.yaml(内含sample_rate与features块的完整声学参数,如n_mels、n_fft、window_fn: hann、win_len_t/hop_len_t等,CMVN 类型为global)。
说明:
--cer-threshold仅在--cer-tsv-path存在且文件有效时才生效;若无需 CER 过滤可省略这两个参数。另外,若样本不足导致过滤后 train split 为空,get_feature_manifest会断言失败(assert "train" in args.splits与后续基于 train 生成词典的逻辑),因此阈值不宜过严。
3. 训练 Transformer TTS 模型
VCTK 示例的训练、推理与自动评估步骤与 LJSpeech 示例 完全一致,仅数据目录与特征配置不同。以自回归 Transformer TTS 为例:
fairseq-train ${FEATURE_MANIFEST_ROOT} --save-dir ${SAVE_DIR} \ --config-yaml config.yaml --train-subset train --valid-subset dev \ --num-workers 4 --max-tokens 30000 --max-update 200000 \ --task text_to_speech --criterion tacotron2 --arch tts_transformer \ --clip-norm 5.0 --n-frames-per-step 4 --bce-pos-weight 5.0 \ --dropout 0.1 --attention-dropout 0.1 --activation-dropout 0.1 \ --encoder-normalize-before --decoder-normalize-before \ --optimizer adam --lr 2e-3 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ --seed 1 --update-freq 8 --eval-inference --best-checkpoint-metric mcd_loss关键点解读:
--task text_to_speech是 S² 工具包的核心 TTS 任务,数据格式与 S2T 保持一致(config.yaml+ TSV manifest),训练时读config.yaml获取声学特征参数与说话人列表;--criterion tacotron2+--arch tts_transformer组合对应 VCTK 结果表中的tts_transformer架构(54M 参数);--n-frames-per-step 4表示解码器每步预测 4 帧,--bce-pos-weight 5.0是停止符位置的 BCE 权重,二者是 Tacotron2 风格自回归解码的典型配置;--update-freq 8表示以 8 个 mini-batch 累积一次梯度更新,用于在单卡上模拟 8 卡训练;文档明确提示多卡时需相应调整该值;--eval-inference在验证时额外执行解码推理,--best-checkpoint-metric mcd_loss指定以验证集 MCD 损失作为选优指标,说明从训练一开始就按"合成质量"(而非单纯 loss)选 checkpoint。
训练收敛后,${SAVE_DIR}下会保存一系列checkpoint_*.pt,供下一步平均与推理使用。
4. 推理:平均 checkpoint 并合成波形
自回归 TTS 在解码质量上对 checkpoint 选择较敏感,官方推荐先平均最后 5 个 epoch 的 checkpoint,再用默认的 Griffin-Lim 声码器合成波形:
SPLIT=test CHECKPOINT_NAME=avg_last_5 CHECKPOINT_PATH=${SAVE_DIR}/checkpoint_${CHECKPOINT_NAME}.pt python scripts/average_checkpoints.py --inputs ${SAVE_DIR} \ --num-epoch-checkpoints 5 \ --output ${CHECKPOINT_PATH} python -m examples.speech_synthesis.generate_waveform ${FEATURE_MANIFEST_ROOT} \ --config-yaml config.yaml --gen-subset ${SPLIT} --task text_to_speech \ --path ${CHECKPOINT_PATH} --max-tokens 50000 --spec-bwd-max-iter 32 \ --dump-waveforms运行细节(对应 generate_waveform.py 与 LJSpeech 文档说明):
- 推理入口直接以特征 manifest 根目录为数据目录,
--gen-subset test指定合成测试集; --spec-bwd-max-iter 32控制 Griffin-Lim 相位恢复的最大迭代次数,32 是文档示例值,可视为合成质量与速度的折中;--dump-waveforms会导出波形文件,同时输出特征、注意力图(attention plot)等可视化产物,全部落在${SAVE_DIR}/generate-${CHECKPOINT_NAME}-${SPLIT}目录下;- 若需要为自动评估重合成目标音频(即把参考音频也过一遍 vocoder,消除声码器带来的系统性失真),需加
--dump-target; - 当后续 WER/CER 评估使用 16kHz 的 ASR 模型时,可在
generate_waveform.py上增加--output-sample-rate 16000直接输出 16kHz 波形,避免评估前再次重采样。
5. 自动评估
合成完成后,通过 S² 的评估子模块得到客观指标。评估的第一步是生成统一格式的评估清单(eval spec)——由 get_eval_manifest.py 实现,其输出的 TSV 包含id/syn/ref/text/speaker五列,其中syn指向合成音频,ref指向参考音频,后续所有指标脚本都消费这一文件:
python -m examples.speech_synthesis.evaluation.get_eval_manifest \ --generation-root ${SAVE_DIR}/generate-${CHECKPOINT_NAME}-${SPLIT} \ --audio-manifest ${AUDIO_MANIFEST_ROOT}/${SPLIT}.audio.tsv \ --output-path ${EVAL_OUTPUT_ROOT}/eval.tsv \ --vocoder griffin_lim --sample-rate 22050 --audio-format flac \ --use-resynthesized-target参数含义(可从源码确认):--generation-root指向推理输出目录;--audio-manifest提供样本 id 与文本;--use-resynthesized-target表示用重合成的参考音频(*_tgt目录)作为 ref,而非原始录音,从而隔离声码器影响、纯粹衡量模型本身的声学预测误差;--vocoder griffin_lim、--sample-rate 22050、--audio-format flac决定目录命名flac_22050hz_griffin_lim下的文件查找路径。若使用 16kHz 的 ASR 模型做 WER/CER,这里应传--sample-rate 16000并对 eval 清单另存(如eval_16khz.tsv)。
5.1 WER/CER 指标(ASR 方案)
以 wav2vec 2.0 ASR 模型为例(模型与词典需按 wav2vec 示例自行准备):
python -m examples.speech_synthesis.evaluation.eval_asr \ --audio-header syn --text-header text --err-unit char --split ${SPLIT} \ --w2v-ckpt ${WAV2VEC2_CHECKPOINT_PATH} --w2v-dict-dir ${WAV2VEC2_DICT_DIR} \ --raw-manifest ${EVAL_OUTPUT_ROOT}/eval_16khz.tsv --asr-dir ${EVAL_OUTPUT_ROOT}/asr该脚本(eval_asr.py)的工作流程:把 eval 清单转成 wav2vec 2.0 微调(audio_finetuning+ CTC)所需的 data 目录(含dict.ltr.txt、${split}.tsv、${split}.ltr),调用examples.speech_recognition.infer做识别,最后基于编辑距离计算逐样本错误率并输出uer_${err_unit}.${split}.tsv。文档在 VCTK 流程中使用--err-unit char(CER);若想按词评估可省略或显式传--err-unit word(WER)。需要留意:--audio-header syn与--text-header text对应 eval 清单中的合成音频与文本列,而 CER 过滤流程中评估的是参考音频(--eval-target时syn列被替换为参考音频路径,参见 get_eval_manifest 源码)。
5.2 MCD / MSD 指标(信号级)
python -m examples.speech_synthesis.evaluation.eval_sp \ ${EVAL_OUTPUT_ROOT}/eval.tsv --mcd --msdeval_sp.py 基于波形做动态时间规整(DTW)对齐后计算 Mel 倒谱失真(MCD)与 Mel 谱失真(MSD),并额外报告插入/删除帧比例;--show-bin可按参考时长分段(0–200/200–400/.../2000–4000 帧)输出分桶统计,便于定位长句短句的质量差异。VCTK 结果表中的 Test MCD 3.4 即来自该脚本。
5.3 F0 韵律指标
python -m examples.speech_synthesis.evaluation.eval_f0 \ ${EVAL_OUTPUT_ROOT}/eval.tsv --gpe --vde --ffeeval_f0.py 提供基频(F0)层面的韵律评估:--gpe(基频生成错误率)、--vde(浊音判定错误率)、--ffe(F0 帧错误率),用于衡量合成语音的音高曲线与参考的吻合程度。
6. 复现结果与调参建议
VCTK 示例文档给出的官方复现结果为:
| --arch | Params | Test MCD | Model |
|---|---|---|---|
| tts_transformer | 54M | 3.4 | 见原文档结果表下载链接 |
对比 LJSpeech 结果表(同架构 54M、Test MCD 3.8),VCTK 多说话人设置下 MCD 反而更低(3.4),说明该 Transformer TTS 对多说话人语料的声学拟合同样有效。若要复现该数字,需完整执行本文的流水线:
- 按 2.1 生成默认切分(50 dev / 100 test)的 manifest;
- 按 2.2 做去噪 + VAD(
--vad-agg-level 3); - 按 2.3 用 ASR 计算 CER 并保存
uer_cer.*.tsv; - 按 2.4 以
--ipa-vocab --use-g2p --snr-threshold 15 --cer-threshold 0.1提取特征(这组过滤阈值与结果表严格对应); - 按第 3 节训练至 20 万步(单卡配
--update-freq 8),按第 4 节平均最后 5 个 checkpoint 并合成 test 集; - 按第 5 节用
--use-resynthesized-target的 eval 清单计算 MCD。
实际复现时的常见调参点:VAD 激进等级(0–3)决定清洗强度,过高会裁掉短样本(触发MIN_T跳过警告),过低则残留静音;SNR/CER 阈值需结合语料质量权衡,阈值过严会显著减少训练样本;--update-freq需按 GPU 数量反比调整以保持等效 batch size;多说话人场景下确保config.yaml含speaker_set_filename(特征提取脚本在说话人数量 >1 时自动写入),训练与推理阶段均会据此区分说话人。
7. 小结
围绕 VCTK 多说话人 TTS,fairseq S² 提供了一条完整、可复现且指标可追踪的开发链路:get_vctk_audio_manifest负责数据切分,denoise_and_vad_audio负责粗质量音频清洗,eval_asr提供 CER 级样本过滤,get_feature_manifest输出音素 + log-Mel 特征及配置,fairseq-train训练 Transformer TTS,generate_waveform完成推理,eval_asr/eval_sp/eval_f0从 ASR、信号、韵律三个维度量化合成质量。对于想迁移到其他多说话人语料的读者,Common Voice 示例 提供了面向更大规模、更低质量众包语料的扩展思路,可直接对照本文流水线复用。
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考