☰
PaddleSpeech 粤语 FastSpeech2 语音合成实战:从数据集预处理到端到端推理
2026/9/25 2:17:31 网站建设 项目流程
  • 人工智能
  • 语音
  • 音频
  • NLP
  • 媒体生成

【免费下载链接】PaddleSpeech

Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.

项目地址:https://gitcode.com/paddlepaddle/PaddleSpeech
点击查看免费下载

本文以 PaddleSpeech 仓库中的 examples/canton/tts3 为骨架,完整讲解基于 FastSpeech2 声学模型构建粤语(Cantonese)语音合成系统的全流程:包括 MagicData 粤语数据集下载与合并、MFA 音素时长对齐、特征预处理、模型训练、端到端语音合成,以及静态模型 / ONNX 模型的导出与跨平台推理。读完本文,你将能够独立复现一个多说话人粤语 TTS 训练管线,并理解其底层 G2P(字音转换)与特征提取实现。

1. 示例概览:为什么需要专门的粤语 TTS 示例

examples/canton/tts3是 PaddleSpeech 中针对粤语(Cantonese)语言专门适配的 FastSpeech2 训练示例。粤语与普通话在音系上有显著差异:粤语使用约 40 个声母/韵母组合(见 canton_frontend.py 中的INITIALS列表),声调系统也不同于普通话,因此需要独立的 G2P 前端与专属的数据预处理流程。

该示例的整体链路与其他语言示例(如 examples/aishell3/tts3)保持一致,但在数据读取、前端音素映射、训练配置等多个环节加入了粤语专属处理,是理解 PaddleSpeech 多语言 TTS 扩展方式的最佳入门样例之一。

FastSpeech2 是本文示例所用的声学模型,其核心思想是通过时长、音高(pitch)与能量(energy)三个预测器实现非自回归、并行可控的语音合成。

2. 数据集准备:下载、合并与 MFA 对齐

2.1 下载两个粤语语料并合并

示例使用 MagicData 发布的两个粤语脚本语音语料:

  • Guangzhou_Cantonese_Scripted_Speech_Corpus_Daily_Use_Sentence(广州粤语日常用语脚本语音语料)
  • Guangzhou_Cantonese_Scripted_Speech_Corpus_in_Vehicle(广州粤语车载场景脚本语音语料)

需要将两个数据集下载并解压到~/datasets/下。为了获得更好的训练效果,示例建议将两个数据集合并为单一目录canton_all:

mkdir -p ~/datasets/canton_all/WAV cp -r ~/datasets/Guangzhou_Cantonese_Scripted_Speech_Corpus_Daily_Use_Sentence/WAV/* ~/datasets/canton_all/WAV cp -r ~/datasets/Guangzhou_Cantonese_Scripted_Speech_Corpus_in_Vehicle/WAV/* ~/datasets/canton_all/WAV

合并完成后目录结构应如下:

~/datasets/canton_all │ └── WAV │ └──G0001 │ └──G0002 │ ... │ └──G0071 │ └──G0072

2.2 从 MFA 对齐结果生成时长文件

FastSpeech2 训练需要逐音素的时长标注,示例使用蒙特利尔强制对齐工具(MFA)获取时长。你可以参照仓库中的 examples/other/mfa 示例自行训练 MFA 模型(当前使用 MFA1.x);同时,示例作者也直接提供了这两个数据集的 MFA 对齐结果canton_alignment.zip(官方 CDN 分发,文件名见原 README),解压后得到目录./canton_alignment。

时长文件由预处理脚本根据 MFA 的 TextGrid 结果生成,对应脚本为仓库中的 utils/gen_duration_from_textgrid.py,在 local/preprocess.sh 的 stage 0 中被调用:

python3 ${MAIN_ROOT}/utils/gen_duration_from_textgrid.py \ --inputdir=./canton_alignment \ --output durations.txt \ --config=${config_path}

3. 一键启动:run.sh 的阶段化训练管线

examples/canton/tts3目录下的 run.sh 是整个示例的入口。运行前先执行source path.sh加载环境变量(MAIN_ROOT、BIN_DIR等),随后按阶段依次执行预处理、训练、合成与模型导出:

./run.sh

run.sh 定义了 7 个阶段(stage),可通过--stage与--stop-stage参数自由控制执行范围。例如下面命令只执行数据预处理:

./run.sh --stage 0 --stop-stage 0

各阶段的含义汇总如下:

stage执行脚本功能说明
0local/preprocess.sh数据预处理:生成时长文件、提取特征、统计并归一化
1local/train.sh训练 FastSpeech2 模型,checkpoint 保存在exp/default/checkpoints/
2local/synthesize.sh从metadata.jsonl合成波形(声码器默认 pwgan,stage 参数为 0;设为 1 使用 hifigan)
3local/synthesize_e2e.sh端到端合成:直接从文本文件合成波形
4local/inference.sh使用 Paddle Inference 静态模型推理
5paddle2onnx 转换将静态模型导出为 ONNX(调用 examples/csmsc/tts3/local/paddle2onnx.sh)
6local/ort_predict.sh使用 ONNX Runtime 在 CPU 上推理

run.sh中的默认参数为:GPU 使用gpus=0,1,配置文件conf/default.yaml,训练输出目录exp/default,默认使用名为snapshot_iter_140000.pdz的 checkpoint。

4. 数据预处理:dump 目录与特征统计

4.1 预处理的三步流程

local/preprocess.sh 内部同样以阶段化方式完成三步工作:

  1. 生成时长文件:从 MFA 的 TextGrid 结果生成durations.txt(stage 0);
  2. 提取特征:调用 paddlespeech/t2s/exps/fastspeech2/preprocess.py 提取 log-mel 频谱、pitch(基频)与 energy(能量)特征:
python3 ${BIN_DIR}/preprocess.py \ --dataset=canton \ --rootdir=~/datasets/canton_all \ --dumpdir=dump \ --dur-file=durations.txt \ --config=${config_path} \ --num-cpu=20 \ --cut-sil=True
  1. 统计与归一化:先用 utils/compute_statistics.py 基于dump/train/raw/metadata.jsonl分别计算speech、pitch、energy三个字段的均值/方差,再用 paddlespeech/t2s/exps/fastspeech2/normalize.py 对 train / dev / test 三部分做归一化,并将音素与说话人映射为 ID。

4.2 dump 目录结构

预处理完成后,当前目录下会生成dump文件夹:

dump ├── dev │ ├── norm │ └── raw ├── phone_id_map.txt ├── speaker_id_map.txt ├── test │ ├── norm │ └── raw └── train ├── energy_stats.npy ├── norm ├── pitch_stats.npy ├── raw └── speech_stats.npy
  • 数据集被划分为train、dev、test三部分,每部分下含raw(原始特征)与norm(归一化后特征)两个子目录;
  • 归一化所用的统计量来自训练集,存放于dump/train/*_stats.npy;
  • 每个子目录中还有一份metadata.jsonl,它是类似表格的记录文件,逐条包含:phones(音素序列)、text_lengths(文本长度)、speech_lengths(语音帧数)、durations(逐音素时长)、speech/pitch/energy 特征路径、speaker(说话人)以及utt_id(话语 ID)。

4.3 源码中的粤语专属处理

从 preprocess.py 的实现可以看到几处粤语专属逻辑:

  • 立体声处理:粤语数据集的部分音频为双声道,读取时使用mono=False并取第一个声道,同时要求数据集必须放在~/datasets/canton_all,否则路径判断会出问题;
  • 静音裁剪:--cut-sil=True时,会裁剪首尾的sil静音音素及其对应波形,减少无效帧对训练的影响;
  • 数据切分规则:canton分支下按说话人目录遍历 WAV 文件,每个说话人超过 100 条音频时才划分出末尾 5 条作为 dev、再往前 5 条作为 test,否则全部划入训练集;
  • 特征提取参数:LogMelFBank、Pitch、Energy三个提取器的参数全部来自配置文件,包括f0min/f0max、n_mels、fmin/fmax等。

5. 核心配置文件 conf/default.yaml 全参数解析

conf/default.yaml 是训练与特征提取的唯一配置入口,按功能区分为特征、数据、模型、优化器等模块。下面结合源码逐一解读关键参数。

5.1 特征提取设置

参数默认值说明
fs24000采样率(Hz)
n_fft2048FFT 点数
n_shift300帧移(Hop size),对应 12.5ms
win_length1200窗长,对应 50ms;若为 null 则等于n_fft
window"hann"窗函数类型
fmin/fmax80 / 7600Mel 滤波器组的最低/最高频率
n_mels80Mel 滤波器组数量
f0min/f0max110 / 400基频提取的上下限(仅用于使用 pitch 特征的模型)

其中f0min是粤语示例的一个关键调优点。配置注释明确指出:粤语数据集与 Databaker、LJSpeech 等其他语料不同,将其设为 110 以避免过多的零基频(zero-pitch)问题(参考了 Python-Wrapper-for-World-Vocoder 的相关 issue)。这一设置在 preprocess.py 中被传递给Pitch提取器,直接影响训练数据的质量。

5.2 数据与模型设置

batch_size: 32 num_workers: 2 model: adim: 384 # attention 维度 aheads: 2 # attention head 数 elayers: 4 # encoder 层数 eunits: 1536 # encoder 前馈单元数 dlayers: 4 # decoder 层数 dunits: 1536 # decoder 前馈单元数 positionwise_layer_type: conv1d positionwise_conv_kernel_size: 3 duration_predictor_layers: 2 duration_predictor_chans: 256 duration_predictor_kernel_size: 3 postnet_layers: 5 postnet_filts: 5 postnet_chans: 256 use_scaled_pos_enc: True encoder_normalize_before: True decoder_normalize_before: True reduction_factor: 1 init_type: xavier_uniform ... spk_embed_dim: 256 # 说话人嵌入维度 spk_embed_integration_type: concat # 说话人嵌入融合方式

其余还有pitch_predictor_*(5 层、256 通道、卷积核 5、dropout 0.5)、energy_predictor_*(2 层、256 通道、卷积核 3、dropout 0.5)两组预测器参数,以及transformer_enc/dec_*_dropout_rate(统一 0.2)等正则化参数。spk_embed_dim: 256与spk_embed_integration_type: concat表明这是一个多说话人模型,说话人 ID 经嵌入层后以拼接方式注入网络,这正是推理时需要指定--spk_id的原因。

5.3 训练与优化设置

updater: use_masking: True # 损失计算时对 padding 部分做掩码 optimizer: optim: adam learning_rate: 0.001 max_epoch: 1000 num_snapshots: 5 seed: 10086

6. 模型训练

local/train.sh 调用 paddlespeech/t2s/exps/fastspeech2/train.py 启动训练:

python3 ${BIN_DIR}/train.py \ --train-metadata=dump/train/norm/metadata.jsonl \ --dev-metadata=dump/dev/norm/metadata.jsonl \ --config=${config_path} \ --output-dir=${train_output_path} \ --ngpu=2 \ --phones-dict=dump/phone_id_map.txt \ --speaker-dict=dump/speaker_id_map.txt
  • 训练使用归一化后的特征(norm/metadata.jsonl),验证集为dev;
  • --ngpu=2表示双卡训练;若设为 0 则使用 CPU/XPU;
  • checkpoint 统一输出到exp/default/checkpoints/,默认命名snapshot_iter_140000.pdz(由 run.sh 的ckpt_name指定,.pdz同时包含模型参数与优化器状态)。

7. 语音合成:两条路径

示例提供两条合成路径,分别对应 run.sh 的 stage 2 与 stage 3。

7.1 从 metadata.jsonl 合成(stage 2)

local/synthesize.sh 调用 paddlespeech/t2s/exps/synthesize.py,从dump/test/norm/metadata.jsonl读取测试集特征并逐句合成,适用于评估模型在测试集上的表现。脚本中同时给出了 pwgan(默认)与 hifigan 两种声码器配置:

python3 ${BIN_DIR}/../synthesize.py \ --am=fastspeech2_aishell3 \ --am_config=${config_path} \ --am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \ --am_stat=dump/train/speech_stats.npy \ --voc=pwgan_aishell3 \ --voc_config=pwg_aishell3_ckpt_0.5/default.yaml \ --voc_ckpt=pwg_aishell3_ckpt_0.5/snapshot_iter_1000000.pdz \ --voc_stat=pwg_aishell3_ckpt_0.5/feats_stats.npy \ --test_metadata=dump/test/norm/metadata.jsonl \ --output_dir=${train_output_path}/test \ --phones_dict=dump/phone_id_map.txt \ --speaker_dict=dump/speaker_id_map.txt

7.2 从文本文件端到端合成(stage 3)

local/synthesize_e2e.sh 调用 paddlespeech/t2s/exps/synthesize_e2e.py,直接从文本合成语音,输入文本为仓库自带的粤语测试句 paddlespeech/t2s/assets/sentences_canton.txt,包含 21 句地道的粤语口语示例(如“白云山爬过一次嘅,好远啊”、“一蚊一斤鸡,一蚊一斤龟,究竟係鸡贵定係龟贵”等绕口令与俗语)。

FLAGS_allocator_strategy=naive_best_fit \ FLAGS_fraction_of_gpu_memory_to_use=0.01 \ python3 ${BIN_DIR}/../synthesize_e2e.py \ --am=fastspeech2_canton \ --am_config=${config_path} \ --am_ckpt=${train_output_path}/checkpoints/${ckpt_name} \ --am_stat=dump/train/speech_stats.npy \ --voc=pwgan_aishell3 \ --voc_config=pwg_aishell3_ckpt_0.5/default.yaml \ --voc_ckpt=pwg_aishell3_ckpt_0.5/snapshot_iter_1000000.pdz \ --voc_stat=pwg_aishell3_ckpt_0.5/feats_stats.npy \ --lang=canton \ --text=${BIN_DIR}/../../assets/sentences_canton.txt \ --output_dir=${train_output_path}/test_e2e \ --phones_dict=dump/phone_id_map.txt \ --speaker_dict=dump/speaker_id_map.txt \ --spk_id=10 \ --inference_dir=${train_output_path}/inference

关键参数说明(以 synthesize_e2e.py 的 argparse 定义为准):

  • --am:声学模型,可选fastspeech2_aishell3/fastspeech2_canton等;
  • --voc:声码器,支持pwgan_aishell3、hifigan_aishell3、mb_melgan_csmsc、wavernn_csmsc等十余种;--stage为 0 时用 pwgan,为 1 时用 hifigan;
  • --lang:语言,合法取值为['zh', 'en', 'mix', 'canton', 'sing'],粤语必须传canton,前端将据此选择对应的 G2P 处理;
  • --spk_id:多说话人模型下的说话人 ID,示例统一使用10;
  • --inference_dir:指定后会在合成的同时导出可供 Paddle Inference 使用的静态模型目录,供 stage 4 使用。

8. 预训练模型与快速推理

8.1 预训练模型清单

示例提供训练好的 FastSpeech2 粤语模型(去除了音频边缘静音):

  • fastspeech2_canton_ckpt_1.4.0.zip:动态图 checkpoint;
  • fastspeech2_canton_static_1.4.0.zip:静态图模型;
  • fastspeech2_canton_onnx_1.4.0.zip:ONNX 模型。

三者均由官方 CDN 分发(paddlespeech.cdn.bcebos.com/Parakeet/released_models/fastspeech2/目录),下载文件名与路径以 README.md 为准。

checkpoint 解压后的目录结构如下:

fastspeech2_canton_ckpt_1.4.0 ├── default.yaml # 训练 fastspeech2 所用的默认配置 ├── energy_stats.npy # 训练时归一化 energy 的统计量 ├── phone_id_map.txt # 训练时的音素词表 ├── pitch_stats.npy # 训练时归一化 pitch 的统计量 ├── snapshot_iter_140000.pdz # 模型参数与优化器状态 ├── speaker_id_map.txt # 多说话人模型的说话人 ID 映射 └── speech_stats.npy # 训练时归一化频谱的统计量

8.2 神经声码器

示例使用 Parallel WaveGAN(并行 WaveGAN)作为神经声码器。下载官方预训练模型pwg_aishell3_ckpt_0.5.zip并解压:

unzip pwg_aishell3_ckpt_0.5.zip

8.3 使用预训练模型直接合成

结合预训练的 fastspeech2 与 parallel wavegan,可用以下命令对 sentences_canton.txt 直接合成:

source path.sh FLAGS_allocator_strategy=naive_best_fit \ FLAGS_fraction_of_gpu_memory_to_use=0.01 \ python3 ${BIN_DIR}/../synthesize_e2e.py \ --am=fastspeech2_aishell3 \ --am_config=fastspeech2_canton_ckpt_1.4.0/default.yaml \ --am_ckpt=fastspeech2_canton_ckpt_1.4.0/snapshot_iter_140000.pdz \ --am_stat=fastspeech2_canton_ckpt_1.4.0/speech_stats.npy \ --voc=pwgan_aishell3 \ --voc_config=pwg_aishell3_ckpt_0.5/default.yaml \ --voc_ckpt=pwg_aishell3_ckpt_0.5/snapshot_iter_1000000.pdz \ --voc_stat=pwg_aishell3_ckpt_0.5/feats_stats.npy \ --lang=canton \ --text=${BIN_DIR}/../../assets/sentences_canton.txt \ --output_dir=exp/default/test_e2e \ --phones_dict=fastspeech2_canton_ckpt_1.4.0/phone_id_map.txt \ --speaker_dict=fastspeech2_canton_ckpt_1.4.0/speaker_id_map.txt \ --spk_id=10 \ --inference_dir=exp/default/inference

注意:--phones_dict与--speaker_dict必须指向预训练 checkpoint 自带的词表文件,--am_stat使用speech_stats.npy,三者共同保证输入音素 ID 与模型训练时的统计口径一致。

9. 源码纵深:粤语文本前端 CantonFrontend

粤语合成的核心差异在于文本前端。仓库中的 paddlespeech/t2s/frontend/canton_frontend.py 实现了CantonFrontend类,其 G2P 流程为:

  1. 文本正则化(TN):调用TextNormalizer对输入文本做规范化与分句;
  2. 粤拼转换(Jyutping):使用ToJyutping库将中文文本转为粤语拼音(Jyutping),例如gam3 ngaam1 lou5 sai3 jiu1 kau4 ...;
  3. 音素切分:jyuping_to_phonemes依据INITIALS列表(包含aa、aai、aak等 40 个粤语韵母/声母组合,以及sp、spl、spn、sil四个特殊标记)将粤拼拆分为声母+韵母的音素序列;
  4. 音素到 ID:_p2id将音素映射为词表 ID,未登录音素(OOV)统一替换为sp,避免推理崩溃。

该前端通过--lang=canton被 synthesize_e2e.py 与 inference.py 选用,是整条粤语合成链路中“语言适配”的核心枢纽。

10. 模型导出与跨平台部署

10.1 导出静态模型与 ONNX

run.sh 的 stage 4~5 在完成合成后自动导出推理模型:stage 4 通过 local/inference.sh 使用 Paddle Inference 验证静态模型(同样支持pwgan_aishell3、mb_melgan_csmsc、hifigan_csmsc、wavernn_csmsc等声码器);stage 5 则安装paddle2onnx并把静态模型转为 ONNX:

pip install paddle2onnx --upgrade ../../csmsc/tts3/local/paddle2onnx.sh ${train_output_path} inference inference_onnx fastspeech2_canton ../../csmsc/tts3/local/paddle2onnx.sh ${train_output_path} inference inference_onnx pwgan_aishell3

底层 examples/csmsc/tts3/local/paddle2onnx.sh 会调用paddle2onnx,将*.pdmodel/*.pdiparams导出为*.onnx(--opset_version 11)。

10.2 ONNX Runtime CPU 推理

stage 6 通过 local/ort_predict.sh 调用 paddlespeech/t2s/exps/ort_predict_e2e.py,使用 ONNX Runtime 在 CPU 上完成端到端合成:

python3 ${BIN_DIR}/../ort_predict_e2e.py \ --inference_dir=${train_output_path}/inference_onnx \ --am=fastspeech2_canton \ --voc=pwgan_aishell3 \ --spk_id=10 \ --output_dir=${train_output_path}/onnx_infer_out_e2e \ --text=${BIN_DIR}/../../assets/sentences_canton.txt \ --phones_dict=dump/phone_id_map.txt \ --speaker_dict=dump/speaker_id_map.txt \ --lang=canton \ --device=cpu \ --cpu_threads=2

该阶段同样支持mb_melgan_csmsc、hifigan_csmsc等声码器组合,--device=cpu与--cpu_threads=2用于控制 CPU 推理线程数,方便在无 GPU 的服务器或边缘设备上部署。

11. 训练细节与扩展参考

本文示例的训练细节与 examples/aishell3/tts3 保持一致(多说话人 FastSpeech2 的通用流程)。若需将本示例迁移到其他语料,建议关注以下扩展点:

  • 新增语言前端:参考 paddlespeech/t2s/frontend/canton_frontend.py 实现对应的 G2P 类,并在 synthesize_e2e.py 的--lang选项中注册;
  • 数据读取适配:参考 preprocess.py 中canton分支,按数据集的目录结构补充切分与声道处理逻辑;
  • 声码器替换:只需更换--voc、--voc_config、--voc_ckpt、--voc_stat四个参数即可在 pwgan / hifigan / mb_melgan 等声码器之间切换,无需改动声学模型部分。

综上所述,examples/canton/tts3覆盖了从多说话人粤语数据预处理、FastSpeech2 训练,到端到端合成与 ONNX 部署的完整闭环,是研究 PaddleSpeech 多语言 TTS 扩展机制与实际落地的直接参考。

  • 人工智能
  • 语音
  • 音频
  • NLP
  • 媒体生成

【免费下载链接】PaddleSpeech

Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.

项目地址:https://gitcode.com/paddlepaddle/PaddleSpeech
点击查看免费下载

相关推荐

上一篇:Uvicorn性能监控指标:关键指标定义与阈值设置
下一篇:如何永久保存微信聊天记录?WeChatMsg让你的数字记忆永不丢失

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询