- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
本篇技术指南围绕 ESPnet2 仓库中的 egs2/jtubespeech/tts1/README.md 展开,完整讲解如何基于 JTubeSpeech 语料构建日语多说话人 TTS 系统:从自动下载约 20GB 的单说话人子集、用 CTC-score 阈值对低质量语音进行数据剪枝,到通过 tts.sh 与各模型配置(Tacotron2 / FastSpeech2 + GST + X-vector)完成训练与解码。读者读完即可复现该 recipe 的全流程,并掌握调整数据剪枝阈值、切换文本前端与模型架构的具体方法。
JTubeSpeech 语料与 recipe 概览
egs2/jtubespeech/tts1 是 ESPnet2 中面向 JTubeSpeech 语料库的日语多说话人 TTS recipe。JTubeSpeech 是一个大规模日语语音语料库,其语音来自 YouTube 等渠道,语料中包含多人发音的语音与对应文本。该 recipe 的核心特点是:
- 自动下载数据:脚本会自动下载并使用一个约20GB 的单说话人子集(single-speaker split),无需手动准备语料;
- 基于 CTC 分数的数据剪枝:因为 YouTube 自动字幕中可能存在识别错误或噪声,recipe 使用预先计算的 CTC 分数对语音进行过滤,默认阈值为-0.1,可通过
local/data.sh的参数调整; - 多说话人建模:训练时默认启用 speaker embedding(x-vector),支持 GST + X-vector 等多说话人扩展;
- 多种模型可切换:默认配置为 Tacotron2,也可通过 tuning 配置切换为 FastSpeech2(Conformer 编码器)等。
该 recipe 的完整运行方式、各模型的训练指南均继承自 ESPnet2 的 TTS 模板文档 egs2/TEMPLATE/tts1/README.md,本文会逐条给出对应的仓库内链接。
数据准备流水线:从下载到 Kaldi 风格数据目录
recipe 的run.sh会依次执行数据下载、预处理、切分、静音去除与数据子集划分。其中数据准备部分由 local/data.sh 驱动,分为 4 个阶段:
| 阶段 | 说明 | 调用的脚本 |
|---|---|---|
| stage -1 | 数据下载 | local/download.sh |
| stage 0 | 初始数据规范化(切分 + 剪枝) | local/data_prep.sh |
| stage 1 | 静音去除(trim silence) | scripts/audio/trim_silence.sh |
| stage 2 | 训练/开发/测试集划分 | utils/subset_data_dir.sh |
自动下载:download.sh
local/download.sh 使用gdown从 Google Drive 下载jtuberaw.tar.gz(Google Drive 文件 ID 为1X_harC0e1tjMX1FtCldD67XOysQuq_Ib),下载后解压到downloads/jtuberaw目录。若目录已存在则自动跳过,保证脚本可重复执行。依赖db.sh中的JTUBESPEECH变量指定存放位置:
# egs2/jtubespeech/tts1/db.sh JTUBESPEECH=downloadslocal/data.sh在启动时会检查该变量:
if [ -z "${JTUBESPEECH}" ]; then log "Fill the value of 'JTUBESPEECH' of db.sh" exit 1 fi db_root=${JTUBESPEECH}切分与剪枝:split.py + prune.py
下载得到的原始数据为整段 YouTube 音频及其字幕文本,需要先按句子边界切分成句级片段,再用 CTC 分数过滤掉低质量片段。local/data_prep.sh 依次调用两个 Python 脚本:
# 切分 wav 文件 python local/split.py --db_raw ${dbr} --db_split ${dbs} # 基于预计算的 ctcscore 剪枝 python local/prune.py --score_thresh ${scorethresh} --db_raw ${dbr} --db_split ${dbs}切分(split.py):读取原始目录下的txt/<speaker>/*.txt字幕文件,其中每行是起始时间\t结束时间\t文本格式。脚本按时间段从原始 16kHz 波形中截取片段,输出为jtubesplit/wav16k/<stem>/<stem>_<idx>.wav,同时生成transcript_raw.txt(格式为片段ID 文本)。片段 ID 由原始文件名加 4 位序号组成,如stem_0000。
剪枝(prune.py):JTubeSpeech 提供了预先计算的 CTC 分数文件ctcscore.txt。prune.py 将该文件中每个片段 ID 的 CTC 分数与阈值--score_thresh比较,仅保留分数大于阈值的片段,写出transcript_prune.txt。核心逻辑见 local/prune.py:
d_ctcscore = dict() with open(ctcscore_path, "r") as fr: for line in fr: line_list = line.strip().split(" ", 5) d_ctcscore[line_list[0]] = float(line_list[4]) with open(raw_transcript_path, "r") as fr: for line in fr: line_list = line.strip().split(" ", 1) stem = line_list[0] try: if d_ctcscore[stem] > thresh_ctc: with open(pruned_transcript_path, "a") as fa: fa.write(line) except KeyError: pass从源码可见:剪枝阈值越高,保留的语音越“干净”(要求更高的 CTC 置信度),保留的数据量也越小;阈值越低则保留更多数据,但可能混入更多识别错误或噪声片段。recipe 默认在local/data.sh中设置ctcscore_pruning_threshold=-0.1:
ctcscore_pruning_threshold=-0.1调整阈值的方法:直接以参数形式覆盖默认值即可,例如保留更干净的数据:
./local/data.sh --ctcscore_pruning_threshold 0.0或放宽筛选、保留更多数据:
./local/data.sh --ctcscore_pruning_threshold -0.5注意该参数通过utils/parse_options.sh解析,而prune.py自身的默认阈值是-0.5,两者以local/data.sh的传入值为准。
生成 Kaldi 风格数据目录
剪枝完成后,local/data_prep.sh 遍历transcript_prune.txt生成标准数据文件:
text:片段ID 文本;wav.scp:片段ID 绝对路径(通过find定位 wav16k 目录下的文件);utt2spk:说话人 ID 取自文件名的前 11 个字符(spkr=${filename:0:11});spk2utt:由utils/utt2spk_to_spk2utt.pl从utt2spk反向生成。
随后local/data.sh的 stage 1 调用scripts/audio/trim_silence.sh去除静音(--fs 16000 --win_length 1024 --shift_length 256 --threshold 35,并行度nj=8);stage 2 用utils/subset_data_dir.sh划分出dev(250 条)、test(250 条)验证/测试集,剩余数据构成训练集tr_no_dev,并最终产出data/all、data/devtest、data/dev、data/test、data/tr_no_dev等目录。
run.sh:训练入口与日语文本前端
完成数据准备后,egs2/jtubespeech/tts1/run.sh 调用通用的 tts.sh 执行后续的特征提取、token 列表生成、统计量收集、训练与解码。其关键参数如下:
| 参数 | 值 | 说明 |
|---|---|---|
--lang jp | 日语 | 语言设置 |
--feats_type raw | raw | 直接使用 16kHz 波形(fs=16000) |
--fs 16000 | 16000 | 采样率;16000 时强制--audio_format wav |
--n_fft 1024 | 1024 | FFT 点数 |
--n_shift 256 | 256 | 帧移 |
--win_length 1024 | 1024 | 窗长 |
--use_spk_embed true | true | 启用说话人嵌入(多说话人建模) |
--spk_embed_tool kaldi | kaldi | 说话人嵌入工具(需编译 Kaldi,自动使用 xvector) |
--spk_embed_tag xvector | xvector | 嵌入类型 |
--token_type phn | phn | 音素级 token |
--cleaner jaconv | jaconv | 文本清理器(日语假名/汉字转换) |
--g2p pyopenjtalk | pyopenjtalk | 文本到音素转换 |
--train_set tr_no_dev/--valid_set dev/--test_sets "dev test" | — | 数据集划分 |
--train_config conf/train.yaml | — | 训练配置(默认 Tacotron2) |
--inference_config conf/decode.yaml | — | 解码配置 |
日语文本前端(g2p)是日语 TTS 的关键环节。run.sh 中注释给出了四种可选方案(输入示例こ、こんにちは):
- Phoneme + Pause(默认,
g2p=pyopenjtalk):k o pau k o N n i ch i w a——音素加停顿符号,适合常规训练; - Kana + Symbol(
g2p=pyopenjtalk_kana):コ 、 コ ン ニ チ ワ——假名加标点符号; - Phoneme + Accent(
g2p=pyopenjtalk_accent):k 1 0 o 1 0 k 5 -4 ...——音素级声调(accent)标记,可提升韵律; - Phoneme + Accent + Pause(
g2p=pyopenjtalk_accent_with_pause):k 1 0 o 1 0 pau k 5 -4 ...——同时包含声调与停顿。
启用声调标注的方案(3、4)需要在训练与解码配置中配套使用use_phone_accent等选项,可根据目标音色表现与韵律质量自行切换。
模型配置解析:Tacotron2 默认配置与 FastSpeech2 调优配置
默认配置:Tacotron2 + GST + X-vector(conf/train.yaml)
conf/train.yaml 中默认训练 Tacotron2,并同时启用GST(Global Style Tokens)与X-vector 说话人嵌入,同时使用 guided attention loss 加速对角注意力学习。文件头注释说明:在 V100 上约需 4 天完成训练。关键配置项:
| 配置项 | 值 | 说明 |
|---|---|---|
tts: tacotron2 | — | 模型架构 |
embed_dim: 512 | 512 | 字符/音素嵌入维度 |
elayers: 1/eunits: 512 | — | 编码器 BLSTM 层数与单元数 |
econv_layers: 3/econv_chans: 512/econv_filts: 5 | — | 编码器卷积层配置 |
atype: location | — | location-based attention |
adim: 512 | 512 | 注意力维度 |
dlayers: 2/dunits: 1024 | — | 解码器 LSTM 层数与单元数 |
prenet_layers: 2/prenet_units: 256 | — | prenet 配置 |
postnet_layers: 5/postnet_chans: 512/postnet_filts: 5 | — | postnet 配置 |
spk_embed_dim: 512 | 512 | 说话人嵌入维度 |
spk_embed_integration_type: add | add | 说话人嵌入融合方式 |
use_gst: true/gst_heads: 4/gst_tokens: 16 | — | GST 多头注意力与全局风格 token 数 |
dropout_rate: 0.5/zoneout_rate: 0.1 | — | dropout 与 zoneout |
reduction_factor: 1 | 1 | 解码 reduction factor |
use_guided_attn_loss: true | — | 启用 guided attention loss |
guided_attn_loss_sigma: 0.4/lambda: 1.0 | — | guided attention loss 参数 |
optim: adam/lr: 1.0e-03 | — | 优化器与学习率 |
num_iters_per_epoch: 500/max_epoch: 500 | — | 每轮迭代数与最大轮数 |
batch_bins: 3750000/batch_type: numel | — | 按元素数打包 batch(feats_type=raw) |
keep_nbest_models: 5 | 5 | 保留的最优模型数 |
调优配置:Conformer FastSpeech2 + GST + X-vector
tuning/train_gst+xvector_conformer_fastspeech2.yaml 提供了 FastSpeech2 方案:Conformer 编码器/解码器 + GST + X-vector,注释说明需要 4 张 32GB 显存的 GPU,在 V100 上约 3 天完成训练。与原始 FastSpeech2 论文相比,该配置使用 token 平均的 pitch 与 energy(与 FastPitch 一致),且不做量化。由于 FastSpeech2 需要显式提取 pitch 与 energy,必须配合feats_type=raw使用。核心差异点:
| 配置项 | 值 | 说明 |
|---|---|---|
tts: fastspeech2 | — | 非自回归模型 |
adim: 384/aheads: 2 | — | 注意力维度与头数 |
elayers: 4/eunits: 1536/dlayers: 4/dunits: 1536 | — | 编解码器层数与 FFN 单元数 |
encoder_type: conformer/decoder_type: conformer | — | Conformer 编解码器 |
positionwise_layer_type: conv1d/kernel_size: 3 | — | 位置前馈层 |
duration_predictor_layers: 2/chans: 256/kernel_size: 3 | — | 时长预测器 |
pitch_predictor_layers: 5/energy_predictor_layers: 2 | — | 韵律预测器 |
pitch_extract: dio/pitch_normalize: global_mvn | — | 基频提取与归一化 |
energy_extract: energy/energy_normalize: global_mvn | — | 能量提取与归一化 |
scheduler: noamlr/warmup_steps: 4000 | — | Noam 学习率调度 |
batch_bins: 18000000 | — | 更大的 batch 容量(raw 特征) |
该目录下还提供了其他组合配置,如train_gst_fastspeech2.yaml、train_xvector_tacotron2.yaml、train_gst+xvector_transformer.yaml等,可通过--train_config参数自由切换:
./run.sh --train_config conf/tuning/train_gst+xvector_conformer_fastspeech2.yaml训练、解码与评估:继承模板文档的完整流程
recipe 的执行方式、训练各类模型的具体命令、解码与评估等,均以 ESPnet2 TTS 模板文档 egs2/TEMPLATE/tts1/README.md 为准。该文档按 11 个 stage 组织流程:数据准备 → wav dump / 嵌入提取 → 说话人嵌入提取 → 长/短数据过滤(--min_wav_duration/--max_wav_duration)→ token 列表生成(--token_type char|phn)→ TTS 统计量收集 → 训练(--train_config/--train_args)→ 解码(--inference_config/--inference_args)→ 基于 VERSA 的评估 → 打包 → 上传 Hugging Face。
与本 recipe 直接相关的训练/使用入口如下(均为仓库内相对链接):
- 如何运行 recipe:
cd进入 recipe 目录、按需修改db.sh与cmd.sh、直接执行./run.sh完成全部阶段;也推荐首次运行时用--stage/--stop-stage逐步执行以理解各阶段产物。 - FastSpeech 训练:需先训练教师模型(Tacotron2 / Transformer-TTS),用
--tts_exp指定教师模型并以--test_sets "tr_no_dev dev eval1"对所有数据解码生成durations,再通过--teacher_dumpdir训练 FastSpeech。 - FastSpeech2 训练:FastSpeech2 是自回归无关的非自回归模型,可直接使用上文 tuning 配置训练。
- 多说话人模型(X-vector)训练:本 recipe 的
run.sh已默认开启--use_spk_embed true --spk_embed_tool kaldi,训练时会自动提取 x-vector 作为说话人嵌入。 - 多说话人模型(Speaker ID)训练:若希望改用说话人 ID 嵌入,需在数据准备阶段保证
utt2spk正确,并切换--use_sid true等相关选项。 - VITS 训练:VITS 为端到端 text2wav 模型,可直接生成波形,无需额外声码器。
- 联合 text2wav 训练:训练可同时输出声学特征与波形的联合模型。
- FAQ:涵盖 ESPnet1 模型兼容性、minibatch 调整、新 recipe 创建、g2p/cleaner 扩展、预训练模型加载与微调、任意文本测试、vocoder 训练等常见问题。
运行./run.sh后,recipe 目录会生成data/(Kaldi 风格数据目录)、dump/(特征与 token_list)、exp/(tts_stats_*统计量、tts_train_*模型与decode_*解码结果,其中wav/为通过 Griffin-Lim 重建的波形)。解码阶段默认使用 Griffin-Lim 生成波形;如需更高质量的神经声码器,可参照模板文档通过--inference_args "--vocoder_tag ..."或--vocoder_file接入 ParallelWaveGAN 等模型。
结语
JTubeSpeech TTS recipe 是 ESPnet2 中一个典型的大规模互联网语料 + 自动质量筛选的实战范例:约 20GB 的原始语音只需一次命令即可自动下载,配合预计算的 CTC 分数完成数据剪枝,再经由标准的 tts.sh 流水线训练出带 X-vector 说话人嵌入的日语多说话人 TTS 模型。其数据剪枝阈值(ctcscore_pruning_threshold)、文本前端(pyopenjtalk 系列 g2p)与模型配置(Tacotron2 / FastSpeech2 + GST + X-vector)均可灵活调整,为研究者在自有日语语料上构建多说话人 TTS 提供了可直接复用的完整流程。
- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
相关推荐
Vitest Mocking Globals 全局变量模拟实战:stubGlobal 与 unstubGlobals 完全指南
Vitest Mocking Globals 全局变量模拟实战:stubGlobal 与 unstubGlobals 完全指南 在 jsdom 或 node 环
人工智能语音音频深度学习NLPSymPy Docstring 风格指南:从 Single-Sentence Summary 到 Sphinx 交叉引用的完整写作规范
SymPy Docstring 风格指南:从 Single Sentence Summary 到 Sphinx 交叉引用的完整写作规范 本文基于 SymPy 官
人工智能语音音频深度学习NLPESPnet2 J-KAC 日语单说话人 TTS 配方实战指南:从语料准备到模型训练与调优
ESPnet2 J KAC 日语单说话人 TTS 配方实战指南:从语料准备到模型训练与调优 本篇技术指南以 egs2/jkac/tts1/README.md h
人工智能语音音频深度学习NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考