- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
导读
本文围绕 ESPnet 仓库中 egs2/libritts/asr1 这一音素级 ASR(Automatic Speech Recognition)实验配方展开,讲解如何基于 LibriTTS 语料构建一个输出为 IPA(国际音标)音素序列并保留标点的识别系统。该系统的核心设计目标是产出"可直接作为基于音素的 TTS(Phone-based TTS)输入端"的转写结果,从而将文本(grapheme)到音素(phoneme)的转换负担从 TTS 前端迁移到 ASR 后端。读完本文,你将掌握:音素化数据准备流程、espeak_ng_english_us_vits这一 g2p(grapheme-to-phoneme)方案的底层实现原理、E-Branchformer 训练配置的完整参数含义,以及该系统的 WER/CER/TER 量化表现。
一、系统目标:为什么需要"音素+标点"的 ASR 输出
该配方在 egs2/libritts/asr1/README.md 中开宗明义:本系统的目的是产生适合作为基于音素 TTS 直接输入的输出。这与常规的字素级(grapheme)ASR 有本质区别:
- 常规 ASR 输出自然语言文本(单词、字词),供人阅读或作为语音识别评测基准;
- 本配方输出音素序列(IPA 符号)与标点,语义上等价于"语音 → 音素转写",可直接喂给音素级 TTS 前端,避免 TTS 端再做一轮 g2p 转换。
从数据流角度看,这正是把 TTS 流水线中的 g2p 环节前置到 ASR 中联合解决:ASR 学习"声学特征 → 音素串(含标点)"的映射,而音素串本身就是 TTS 可直接消费的中间表示。因此该模型可视为语音转写(speech-to-phoneme transcription)专用系统,其评测指标(WER/CER/TER)也全部基于音素序列计算。
二、实验环境与依赖
原文档记录了该配方的实测环境(详见 egs2/libritts/asr1/README.md):
| 项目 | 版本 |
|---|---|
| Python | 3.10.8(GCC 11.3.1) |
| ESPnet | espnet 202308 |
| PyTorch | 2.0.1+cu118 |
| 训练硬件 | A6000(48 GB)× 2 GPU |
需要特别说明:由于本配方依赖 eSpeak NG 进行音素化,必须安装相应的 g2p 依赖。从源码看,espeak_ng_english_us_vits走的是phonemizer库的espeak后端(见下文源码解析小节),因此复现前需要确保环境中安装了phonemizer及其 espeak-ng 后端。
三、数据处理:从 LibriTTS 到"音素化"训练集
3.1 数据下载与目录组织
数据准备脚本为 local/data.sh,它通过 db.sh 读取LIBRITTS环境变量指定的数据根目录,并从www.openslr.org/resources/60下载 LibriTTS 的七个子集:
dev-clean、dev-other、test-clean、test-othertrain-clean-100、train-clean-360、train-other-500
下载完成后在$db_root/LibriTTS/.complete打上标记以避免重复下载。随后:
- stage 0:对每个子集调用 local/data_prep.sh 生成 Kaldi 风格数据目录(
wav.scp、text、utt2spk、spk2gender、spk2utt),再用utils/fix_data_dir.sh修复,最后调用local/phonemize_dir.py做音素化; - stage 1:用
utils/combine_data.sh合并数据——dev由dev-clean+dev-other合并,train-960由三个训练子集合并(合计约 960 小时)。
local/data_prep.sh 沿用了 LibriTTS 的标准做法:以"reader_chapter"作为说话人粒度(utt2spk按章节划分,便于按章节计算 CMVN),转写文本取自每个 wav 对应的.normalized.txt文件。
3.2 音素化核心脚本:phonemize_dir.py
音素化由 local/phonemize_dir.py 完成,其逻辑非常简洁清晰:
from espnet2.text.phoneme_tokenizer import PhonemeTokenizer tokenizer = PhonemeTokenizer("espeak_ng_english_us_vits") with ( open(f"{idir}/text", encoding="utf-8") as itext, open(f"{idir}/text.phn", "w", encoding="utf-8") as otext, ): for line in itext: utt, text = line.strip("\n").split(" ", maxsplit=1) tokens = tokenizer.text2tokens(text) text_phn = "".join(tokens).replace("<space>", " ") otext.write(f"{utt} {text_phn}\n") os.replace(f"{idir}/text", f"{idir}/text.orig") os.replace(f"{idir}/text.phn", f"{idir}/text")要点拆解:
- 使用
PhonemeTokenizer("espeak_ng_english_us_vits")将每句英文文本转为音素 token 序列; - token 序列用
"".join()拼回字符串,再统一把<space>占位符替换为真实空格,从而把词边界还原为空格分隔; - 处理完成后原文本备份为
text.orig,音素文本正式覆盖text,因此训练集、验证集、测试集的text文件都是音素序列,ASR 模型学到的是"声学特征 → 音素+标点"的映射。
3.3 底层 g2p:espeak_ng_english_us_vits 的实现
PhonemeTokenizer定义于 espnet2/text/phoneme_tokenizer.py,espeak_ng_english_us_vits分支位于该文件约 L598-L610:
elif g2p_type == "espeak_ng_english_us_vits": # VITS official implementation-like processing # Reference: https://github.com/jaywalnut310/vits self.g2p = Phonemizer( language="en-us", backend="espeak", with_stress=True, preserve_punctuation=True, strip=True, word_separator=" ", phone_separator="", split_by_single_token=True, )从源码结构看,该 g2p 方案的关键参数决定了音素化结果的质量:
backend="espeak":调用phonemizer库的 eSpeak NG 后端(Phonemizer类是对 bootphon/phonemizer 的封装,见 espnet2/text/phoneme_tokenizer.py L384-L437,内部通过phonemizer.backend.BACKENDS[backend]实例化);language="en-us":使用美式英语发音规则;with_stress=True:保留重音符号——IPA 音素中的主/次重音(如 ˈ 与 ˌ)对 TTS 韵律至关重要;preserve_punctuation=True:保留标点——这正是"IPA + 标点"系统中标点来源,标点会被当作独立 token 输出;word_separator=" "、phone_separator=""、split_by_single_token=True:采用 VITS 官方实现类似的处理方式——词边界用空格分隔、音素间不加分隔符、按单 token 拆分(拆分时Phonemizer.__call__会把空格替换为<space>占位符,再由phonemize_dir.py统一还原)。
此外,espnet2/text/phoneme_tokenizer.py 的g2p_choices列表(L25-L56 附近)还提供了g2p_en、pyopenjtalk(日语)、pypinyin_g2p(中文)、g2pk(韩语)、espeak_ng_*(多语种)等众多方案,本配方选用的espeak_ng_english_us_vits正是为英文音素级 TTS 量身定制的一档。
四、训练配置详解
4.1 入口脚本 run.sh
训练入口为 run.sh,通过./asr.sh以参数方式注入全部超参数:
train_set="train-960" valid_set="dev" test_sets="test-clean test-other dev-clean dev-other" asr_config=conf/train_asr.yaml inference_config=conf/decode_asr.yaml ./asr.sh \ --lang en \ --ngpu 2 \ --nbpe 100 \ --max_wav_duration 30 \ --speed_perturb_factors "0.9 1.0 1.1" \ --audio_format "flac.ark" \ --feats_type raw \ --use_lm false \ --asr_config "${asr_config}" \ --inference_config "${inference_config}" \ --train_set "${train_set}" \ --valid_set "${valid_set}" \ --test_sets "${test_sets}" \ --lm_train_text "data/${train_set}/text" \ --bpe_train_text "data/${train_set}/text" "$@"参数语义如下:
| 参数 | 取值 | 作用 |
|---|---|---|
--lang en | en | 目标语言为英语 |
--ngpu 2 | 2 | 双 GPU 分布式训练 |
--nbpe 100 | 100 | BPE 词表大小 100——由于输出是音素序列,词表天然很小,100 个 BPE 单元足够覆盖音素+标点组合 |
--max_wav_duration 30 | 30(秒) | 过滤超过 30 秒的长音频 |
--speed_perturb_factors | "0.9 1.0 1.1" | 三倍速扰动(0.9×/1.0×/1.1×)做数据增强 |
--audio_format "flac.ark" | flac.ark | 音频以 FLAC 编码的 ark 格式存储 |
--feats_type raw | raw | 不预提取特征,直接在训练中计算前端特征 |
--use_lm false | false | 不使用外部语言模型(音素序列无需 LM 建模) |
--asr_config | conf/train_asr.yaml | 训练配置 |
--inference_config | conf/decode_asr.yaml | 解码配置 |
--bpe_train_text | data/train-960/text | 在音素化后的训练文本上训练 BPE 模型 |
值得注意的是run.sh末尾的"$@"允许命令行追加参数覆盖默认值,这与 ESPnet 所有配方的习惯一致(如覆盖--asr_config指向 conf/tuning/train_asr_e_branchformer.yaml)。
4.2 模型结构:E-Branchformer 编码器 + Transformer 解码器
训练配置 conf/tuning/train_asr_e_branchformer.yaml(与 conf/train_asr.yaml 内容一致)定义了完整的模型与训练方案:
编码器(E-Branchformer)——约 1.41 亿参数中的主体:
encoder: e_branchformer encoder_conf: output_size: 512 attention_heads: 8 attention_layer_type: rel_selfattn pos_enc_layer_type: rel_pos rel_pos_type: latest cgmlp_linear_units: 3072 cgmlp_conv_kernel: 31 use_linear_after_conv: false gate_activation: identity num_blocks: 17 dropout_rate: 0.1 positional_dropout_rate: 0.1 attention_dropout_rate: 0.1 input_layer: conv2d layer_drop_rate: 0.1 linear_units: 1024 positionwise_layer_type: linear macaron_ffn: true use_ffn: true merge_conv_kernel: 31关键参数解读:
num_blocks: 17、output_size: 512、attention_heads: 8:17 层、512 维、8 头注意力;attention_layer_type: rel_selfattn+pos_enc_layer_type: rel_pos+rel_pos_type: latest:使用相对位置编码的 self-attention;cgmlp_linear_units: 3072、cgmlp_conv_kernel: 31、merge_conv_kernel: 31:E-Branchformer 特有的卷积门控 MLP(Convolution-augmented gMLP)分支配置;macaron_ffn: true、use_ffn: true:启用 Macaron 结构与 FFN 分支;input_layer: conv2d:输入为 Conv2D 下采样(配合下方frontend_conf的 512 点 FFT);layer_drop_rate: 0.1:层级丢弃正则化。
解码器(Transformer):
decoder: transformer decoder_conf: attention_heads: 8 linear_units: 2048 num_blocks: 6 dropout_rate: 0.1 positional_dropout_rate: 0.1 self_attention_dropout_rate: 0.1 src_attention_dropout_rate: 0.1 layer_drop_rate: 0.2训练损失与优化:
model_conf: ctc_weight: 0.6 lsm_weight: 0.1 length_normalized_loss: false frontend_conf: n_fft: 512 hop_length: 160ctc_weight: 0.6:CTC 与 attention 的混合训练权重(CTC 占 0.6);lsm_weight: 0.1:标签平滑系数 0.1;frontend_conf:在线提取 512 点 FFT、hop 160 的滤波器组特征(对应 16 kHz 采样率下 10 ms 帧移)。
训练调度:
batch_type: numel batch_bins: 10000000 accum_grad: 8 max_epoch: 70 patience: none init: none best_model_criterion: - - valid - acc - max keep_nbest_models: 10 use_amp: true unused_parameters: true optim: adam optim_conf: lr: 0.005 weight_decay: 0.000001 scheduler: warmuplr scheduler_conf: warmup_steps: 40000 specaug: specaug specaug_conf: apply_time_warp: true time_warp_window: 5 time_warp_mode: bicubic apply_freq_mask: true freq_mask_width_range: [0, 27] num_freq_mask: 2 apply_time_mask: true time_mask_width_ratio_range: [0.0, 0.05] num_time_mask: 10batch_type: numel+batch_bins: 10000000:按元素数(numel)动态批大小,单 batch 不超过 1000 万元素;accum_grad: 8:梯度累积 8 步等效放大批大小;max_epoch: 70:最多训练 70 个 epoch(原注释显示在 A6000 × 2 上每 epoch 约 90 分钟);best_model_criterion:按验证集 accuracy 最大化选择最优模型,保留 10 个 n-best;use_amp: true:启用自动混合精度;- 优化器 Adam(lr 0.005)+ WarmupLR(40000 步预热);
- SpecAugment 时间/频率掩蔽增强:频率掩蔽宽度 0-27、共 2 个;时间掩蔽宽度比例为 0-0.05、共 10 个。
4.3 模型规模
该配方训练出的模型参数量为141.39M(约 1.41 亿),实验目录名为exp/asr_train_asr_raw_en_bpe100_sp,其中:
raw:raw 特征(在线前端);en_bpe100:英语、BPE 词表 100;sp:speed perturbation(三倍速扰动)。
五、解码配置
解码配置见 conf/decode_asr.yaml:
beam_size: 15 ctc_weight: 0.2 lm_weight: 0.0 maxlenratio: 0.0 minlenratio: 0.0 penalty: 0.0beam_size: 15:beam 搜索宽度 15;ctc_weight: 0.2:解码时 CTC 与 attention 得分的加权比例(与训练权重 0.6 不同,解码阶段更依赖 attention);lm_weight: 0.0:不集成语言模型(与--use_lm false对应);maxlenratio/minlenratio: 0.0:不限制输出长度比例;penalty: 0.0:无长度惩罚。
最终用于评测的模型为decode_asr_asr_model_valid.acc.ave,即验证集 accuracy 最优模型的平均权重(average checkpoints)。
六、评测结果:WER / CER / TER
音素序列的评测标准覆盖三种错误率:WER(词错率,按空格分隔的"音素词"计)、CER(字符错误率,按音素符号计)、TER(token 错误率,按词表 token 计)。以下数据均来自原文档 egs2/libritts/asr1/README.md,评测模型为decode_asr_asr_model_valid.acc.ave。
6.1 WER(词错误率)
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev-clean | 5736 | 95872 | 91.7 | 8.0 | 0.4 | 0.8 | 9.1 | 67.0 |
| dev-other | 4613 | 69577 | 88.5 | 10.9 | 0.6 | 1.2 | 12.7 | 74.2 |
| test-clean | 4837 | 87078 | 91.4 | 8.2 | 0.4 | 0.8 | 9.4 | 70.4 |
| test-other | 5120 | 72541 | 87.0 | 12.2 | 0.8 | 1.1 | 14.1 | 77.1 |
6.2 CER(字符错误率)
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev-clean | 5736 | 570710 | 98.4 | 0.8 | 0.9 | 0.6 | 2.2 | 67.1 |
| dev-other | 4613 | 414781 | 97.2 | 1.6 | 1.2 | 1.0 | 3.8 | 74.2 |
| test-clean | 4837 | 530647 | 98.5 | 0.7 | 0.8 | 0.6 | 2.2 | 70.5 |
| test-other | 5120 | 429463 | 96.7 | 1.7 | 1.6 | 1.0 | 4.3 | 77.1 |
6.3 TER(Token 错误率)
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev-clean | 5736 | 433548 | 97.6 | 1.4 | 1.0 | 0.6 | 3.0 | 67.1 |
| dev-other | 4613 | 316550 | 96.1 | 2.5 | 1.4 | 1.0 | 5.0 | 74.2 |
| test-clean | 4837 | 404031 | 97.7 | 1.4 | 0.9 | 0.7 | 2.9 | 70.5 |
| test-other | 5120 | 327248 | 95.4 | 2.8 | 1.8 | 1.1 | 5.7 | 77.1 |
结果解读:
- CER(2.2%~4.3%)远低于 WER(9.1%~14.1%),说明错误主要集中于个别音素符号的替换,整体音素序列质量很高;
*-clean与*-other的差距(clean vs 噪声/重口音)符合 LibriTTS 的难度梯度设定;- S.Err(句子错误率)约 67%~77%,意味着约三分之一的句子中存在至少一个音素错误——对音素级 TTS 前端而言,剩余的错误可通过 TTS 的容错性(音素序列已包含重音和标点信息)部分消化。
该模型对应预训练权重发布在 Hugging Face 的espnet/akreal_libritts_asr_phn模型仓库中,可直接加载用于推理或微调(可通过 ESPnet 标准模型下载机制espnet_model_zoo/pretrained拉取)。
七、从源码看该配方的可复用性
7.1 g2p 方案可替换
espnet2/text/phoneme_tokenizer.py 的g2p_choices列出全部可用 g2p 类型。若想迁移到其他语言,只需把 local/phonemize_dir.py 中的PhonemeTokenizer("espeak_ng_english_us_vits")替换为espeak_ng_german、espeak_ng_french、espeak_ng_spanish等(多语言 eSpeak NG 后端),或替换为g2pk(韩语)、pyopenjtalk(日语)、pypinyin_g2p(中文)等专用方案,即可构造"任意语言 → 音素级 ASR"的配方。
7.2 与 TTS 配方的衔接
该配方的输出格式(空格分隔的 IPA 音素串、含标点与重音)与 ESPnet 的 TTS 音素输入约定一致。TTS 侧可通过PhonemeTokenizer完成同样的文本→音素转换(见 espnet2/text/build_tokenizer.py L76-L77 对PhonemeTokenizer的构建逻辑),实现"ASR 输出的音素串 → TTS 输入"的无缝对接。这正是 egs2/libritts 同时提供 asr1(音素 ASR)与 tts1 等配方的深层关联所在。
八、复现步骤速览
- 准备数据:在 db.sh 中填写
LIBRITTS数据根目录,运行./run.sh --stage -1 --stop_stage 1完成下载、Kaldi 数据目录生成与音素化; - 训练:
./run.sh --stage 2 --stop_stage 4(按asr.sh默认阶段划分,依次为特征/BPE 准备、训练),或直接./run.sh走完全流程;训练默认使用 conf/train_asr.yaml,如需复现文档中的 E-Branchformer 配置可追加--asr_config conf/tuning/train_asr_e_branchformer.yaml; - 解码与评分:解码阶段生成
decode_asr_*目录,使用 ESPnet 标准show_asr_result.sh汇总 WER/CER/TER 结果(脚本见 egs2/libritts/asr1/scripts/utils/show_asr_result.sh); - 加载预训练模型:通过模型名
espnet/akreal_libritts_asr_phn从模型库拉取权重,直接对任意英文音频做 IPA+标点转写。
小结
本配方是"音素级语音处理"思路的完整落地:数据侧用 eSpeak NG(espeak_ng_english_us_vits,保留重音与标点、VITS 兼容格式)把 LibriTTS 文本音素化;模型侧用 17 层 E-Branchformer + 6 层 Transformer(CTC 0.6 + 标签平滑 0.1 + SpecAugment)在 960 小时音素监督下训练 1.41 亿参数模型;评测侧以 WER/CER/TER 三重视角确认了音素序列的高保真度(CER 最低 2.2%)。该输出可作为音素级 TTS 的直接前端输入,也可推广到任意语言的音素转写任务。
- 人工智能
- 语音
- 音频
- 深度学习
- NLP
【免费下载链接】espnet
End-to-End Speech Processing Toolkit
相关推荐
ESPnet ASR2 实战:基于自监督离散 token 与 E-Branchformer 的高效端到端 ASR(LibriSpeech960)
ESPnet ASR2 实战:基于自监督离散 token 与 E Branchformer 的高效端到端 ASR(LibriSpeech960) 本技术指南以
人工智能语音音频深度学习NLPESPnet 离散 Token ASR2 实战:Libriheavy small 上基于 WavLM + K-Means + E-Branchformer 的带大小写与标点识别
ESPnet 离散 Token ASR2 实战:Libriheavy small 上基于 WavLM + K Means + E Branchformer 的带
人工智能语音音频深度学习NLPESPnet CHiME4 ASR2 Recipe 实战:基于 WavLM 离散 Token 与 E-Branchformer 的端到端语音识别
ESPnet CHiME4 ASR2 Recipe 实战:基于 WavLM 离散 Token 与 E Branchformer 的端到端语音识别 本篇技术指南聚
人工智能语音音频深度学习NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考