ESPnet 中文普通话 ASR 实战:在 aidatatang_200zh 上复现 E-Branchformer 与 Conformer 实验
ESPnet 中文普通话 ASR 实战:在 aidatatang_200zh 上复现 E-Branchformer 与 Conformer 实验
本指南围绕 ESPnet 仓库中 egs2/aidatatang_200zh/asr1 的中文普通话(Mandarin)语音识别实验,完整解读其中 E-Branchformer(12 层与 16 层两个版本)和 Conformer 三种编码器架构的配置文件、训练参数、语言模型与解码策略,并结合源码说明 E-Branchformer 的双分支结构原理。读者读完后,可以独立复现该数据集的 CER 评测结果,掌握如何在 ESPnet 的 egs2 配方框架下调整编码器深度、批大小、学习率与 SpecAugment 策略。
实验概述与数据集背景
aidatatang_200zh 是 AISHELL 团队发布的开源中文普通话语料库,原始数据托管于 OpenSLR(编号 62,www.openslr.org/resources/62),包含约 200 小时的标注语音,划分出 train、dev、test 三个子集。在 local/data.sh 中可以看到其下载与预处理逻辑:
- 通过
data_url=www.openslr.org/resources/62下载并解压aidatatang_200zh压缩包,目标目录由db.sh中的AIDATATANG_200ZH变量指定; - 调用
local/download_and_untar.sh与local/data_prep.sh生成 Kaldi 风格的data/{train,dev,test}数据目录; - 预处理脚本对标注文本做了去空格归一化:
paste -d " " <(cut -f 1 -d" " text.org) <(cut -f 2- -d" " text.org | tr -d " "),将转写中的空格删除,使中文文本以连续字符序列进入训练管线。
本实验以字符(char)为建模单元(--token_type char)、原始波形(raw waveform)为输入特征(--feats_type raw),是 ESPnet2 标准的中文 ASR 配置形态。
三种模型的配置与评测结果
该 README 记录了同一数据集上的三组实验:E-Branchformer(16 层)、E-Branchformer(12 层)与Conformer(12 层),三者共享 Transformer 解码器、相同的混合 CTC/Attention 训练框架与同一 Transformer 语言模型。原始 README 给出的环境与结果如下,必须原样继承:
环境信息(原文记录)
- E-Branchformer 16 层实验:espnet
202301、pytorch1.13.1、Python3.9.15,Git hash232a317a66eda6c5caee094db4b714bc912dce95(2023-02-22); - E-Branchformer 12 层实验:espnet
202211、pytorch1.12.1、Python3.9.15,Git hash7a203d55543df02f0369d5608cd6f3033119a135(2022-12-23); - Conformer 实验:espnet
0.10.5a1、pytorch1.7.1、Python3.8.5,Git hasha5bacd349a47889aef795f999563018cf201ae64(2021-12-22)。
注意:上述环境记录于各自实验完成时的版本快照,直接复现时建议使用当前仓库版本并自行验证兼容性。
模型配置与参数量
| 实验 | 编码器配置 | 参数量 | 语言模型配置 |
|---|---|---|---|
| E-Branchformer 16 层 | conf/tuning/train_asr_e_branchformer_e16_linear1024_lr1e-3.yaml | 45.43M | conf/train_lm_transformer.yaml |
| E-Branchformer 12 层 | conf/tuning/train_asr_e_branchformer_linear1024.yaml | 37.66M | 同上 |
| Conformer 12 层 | conf/train_asr_conformer.yaml | 45.98M | 同上 |
可以看出:16 层 E-Branchformer(45.43M)与 12 层 Conformer(45.98M)参数量相当,是同一参数量级下的公平对比;12 层 E-Branchformer 参数最少(37.66M)。
CER 评测结果(原文表格,逐字保留)
评价指标为字符错误率 CER(Char Error Rate),评测时使用 LM(解码目录 decode_asr_lm_lm_train_lm_transformer_zh_char_valid.loss.ave_asr_model_valid.acc.ave),模型选择策略为 ASR 取 valid acc 最优(.acc.ave 为最佳平均模型),LM 取 valid loss 最优。
E-Branchformer 16 层 + LM:
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev | 24216 | 234524 | 96.7 | 2.9 | 0.4 | 0.2 | 3.4 | 17.6 |
| test | 48144 | 468933 | 96.1 | 3.5 | 0.4 | 0.2 | 4.1 | 20.1 |
E-Branchformer 12 层 + LM:
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev | 24216 | 234524 | 96.6 | 3.0 | 0.4 | 0.1 | 3.6 | 18.4 |
| test | 48144 | 468933 | 95.9 | 3.6 | 0.4 | 0.2 | 4.2 | 20.8 |
Conformer 12 层 + LM:
| dataset | Snt | Wrd | Corr | Sub | Del | Ins | Err | S.Err |
|---|---|---|---|---|---|---|---|---|
| dev | 24216 | 234524 | 96.6 | 3.0 | 0.5 | 0.1 | 3.6 | 18.5 |
| test | 48144 | 468933 | 95.9 | 3.6 | 0.4 | 0.2 | 4.3 | 21.0 |
从 CER 看,16 层 E-Branchformer 在 dev/test 上取得最低错误率(3.4% / 4.1%),12 层 E-Branchformer 与 12 层 Conformer 表现基本持平(test 均为 4.2% / 4.3% 量级)。需要说明:各实验的数据划分、解码设置基本一致,但训练环境与超参不同(见下文配置对比),以上数字仅用于说明当前仓库记录的实验现象。
编码器架构配置详解
E-Branchformer 16 层(主实验配置)
conf/tuning/train_asr_e_branchformer_e16_linear1024_lr1e-3.yaml 是 README 标题对应的核心配置,其编码器关键项:
encoder: e_branchformer
encoder_conf:
output_size: 256 # 模型维度
attention_heads: 4 # 多头注意力头数
attention_layer_type: rel_selfattn # 相对位置自注意力
pos_enc_layer_type: rel_pos
rel_pos_type: latest # 相对位置编码实现版本
cgmlp_linear_units: 1024 # CGMLP 中 FFN 隐层维度
cgmlp_conv_kernel: 31 # CGMLP 深度卷积核大小
use_linear_after_conv: false
gate_activation: identity # 门控激活函数
num_blocks: 16 # 编码器层数(本实验的核心变量)
dropout_rate: 0.1
positional_dropout_rate: 0.1
attention_dropout_rate: 0.1
input_layer: conv2d # 前端下采样:2 维卷积
layer_drop_rate: 0.0
linear_units: 1024 # FFN 隐层维度
positionwise_layer_type: linear
use_ffn: true # 启用标准 FFN
macaron_ffn: true # 启用 macaron 风格 FFN
merge_conv_kernel: 31 # 双分支融合模块的深度卷积核
E-Branchformer 12 层(tuning 变体)
conf/tuning/train_asr_e_branchformer_linear1024.yaml 与 16 层版本的主要差异:
num_blocks: 12(层数减少 4 层);- 优化器学习率
lr: 0.0005(16 层版为0.001),warmup_steps: 30000(16 层版为35000); - 训练轮数
max_epoch: 50(16 层版为 60); - SpecAugment 时间掩码使用绝对宽度
time_mask_width_range: [0, 40]、num_time_mask: 2,而 16 层版使用相对宽度time_mask_width_ratio_range: [0.0, 0.05]、num_time_mask: 10;频率掩码宽度 16 层版为[0, 27]、12 层版为[0, 30]。
Conformer 12 层(基线)
conf/train_asr_conformer.yaml 展示了 Conformer 的经典配置,与 E-Branchformer 形成结构对照:
encoder: conformer
encoder_conf:
output_size: 256
attention_heads: 4
linear_units: 2048 # FFN 隐层维度(Conformer 更大)
num_blocks: 12
dropout_rate: 0.1
positional_dropout_rate: 0.1
attention_dropout_rate: 0.0
input_layer: conv2d
normalize_before: true
pos_enc_layer_type: rel_pos
selfattention_layer_type: rel_selfattn
activation_type: swish # Swish 激活
macaron_style: true # macaron 风格
use_cnn_module: true
cnn_module_kernel: 15 # 卷积模块核大小 15
Conformer 采用"标准 MHSA + CNN 模块 + macaron FFN"的串联式块结构,而 E-Branchformer 则改为"MHSA 与 CGMLP 双分支并行、再经融合卷积合并"的结构(原理见下文源码解析)。
解码器、混合 CTC/Attention 与训练超参
三个 ASR 配置共享完全相同的解码器与模型损失配置:
decoder: transformer
decoder_conf:
attention_heads: 4
linear_units: 2048
num_blocks: 6 # 6 层 Transformer 解码器
dropout_rate: 0.1
positional_dropout_rate: 0.1
self_attention_dropout_rate: 0.0
src_attention_dropout_rate: 0.0
model_conf:
ctc_weight: 0.3 # 混合 CTC/Attention 的 CTC 权重
lsm_weight: 0.1 # 标签平滑
length_normalized_loss: false
其中 ctc_weight: 0.3 表示训练损失按 0.3 * CTC 损失 + 0.7 * Attention 损失 加权;lsm_weight: 0.1 为标签平滑系数,有助于缓解过拟合并提升泛化。
训练/优化相关差异(E-Branchformer 16 层 vs 12 层 vs Conformer):
| 超参 | E-Branchformer 16 层 | E-Branchformer 12 层 | Conformer |
|---|---|---|---|
| batch_type / batch_bins | numel / 16000000 | numel / 16000000 | numel / 4000000 |
| accum_grad | 1 | 1 | 4 |
| grad_clip | 5 | 5 | 5 |
| max_epoch | 60 | 50 | 50 |
| use_amp | true | — | — |
| num_workers | 6 | 4 | — |
| optim | adam | adam | adam |
| lr | 0.001(weight_decay 1e-6) | 0.0005 | 0.0005 |
| scheduler | warmuplr / 35000 | warmuplr / 30000 | warmuplr / 30000 |
说明:
batch_type: numel表示按张量元素总数(batch_bins)动态组批,而非固定句数,这样长短不一的中文音频能被更高效地打包;- Conformer 配置的
batch_bins较小(4000000)但accum_grad: 4,有效批大小与 16 层 E-Branchformer 相当; - 三份配置的模型选择策略一致:
best_model_criterion: valid acc max,并保留keep_nbest_models: 10个最优模型用于后续平均; - 16 层 E-Branchformer 启用了
use_amp: true(自动混合精度),并带weight_decay: 0.000001。
SpecAugment 数据增强配置
SpecAugment 是本实验提升泛化能力的关键增强手段,16 层 E-Branchformer 配置如下:
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: 10
而 12 层 E-Branchformer 与 Conformer 采用绝对宽度的时间掩码(time_mask_width_range: [0, 40],num_time_mask: 2)。两种表述等价:ratio_range 按输入帧长比例计算掩码宽度,更适合超长音频;width_range 直接以帧数为单位。复现时可按数据长度灵活选择。
Transformer 语言模型(LM)配置
conf/train_lm_transformer.yaml 定义了实验共用的中文 char 级 Transformer LM:
lm: transformer
lm_conf:
pos_enc: null # 不单独使用位置编码(模型内置相对位置)
embed_unit: 128 # 词嵌入维度
att_unit: 512 # 注意力维度
head: 8 # 注意力头数
unit: 2048 # FFN 隐层维度
layer: 16 # 16 层
dropout_rate: 0.1
grad_clip: 5.0
batch_type: numel
batch_bins: 2000000
accum_grad: 1
max_epoch: 15 # 15 轮即收敛
optim: adam
optim_conf:
lr: 0.001
scheduler: warmuplr
scheduler_conf:
warmup_steps: 25000
best_model_criterion: # LM 按 valid loss 选优
- - valid
- loss
- min
keep_nbest_models: 10
LM 训练文本直接取自训练集标注:--lm_train_text "data/${train_set}/text"(见 run.sh)。
解码(推理)配置
conf/decode_asr.yaml 控制推理行为:
beam_size: 20 # 束搜索宽度
penalty: 0.0 # 长度惩罚
maxlenratio: 0.0 # 最大解码长度 = maxlenratio * 输入长度
minlenratio: 0.0
ctc_weight: 0.4 # 解码时 CTC 权重(与训练 0.3 不同)
lm_weight: 0.3 # 语言模型权重
注意解码阶段 ctc_weight: 0.4 高于训练时的 0.3,这是 ESPnet 混合 CTC/Attention 模型常用的"训练轻 CTC、解码重 CTC"策略;lm_weight: 0.3 表示解码打分中融合 LM 概率。评测结果表格中的目录名 decode_asr_lm_lm_train_lm_transformer_zh_char_valid.loss.ave_asr_model_valid.acc.ave 即对应"带 LM、ASR 取 valid acc 平均模型、LM 取 valid loss 平均模型"的解码产物。
一键训练脚本 run.sh 与参数说明
egs2/aidatatang_200zh/asr1/run.sh 是该配方的入口脚本,核心参数如下:
train_set=train
valid_set=dev
test_sets="dev test"
asr_config=conf/train_asr_e_branchformer.yaml # 默认 16 层 E-Branchformer
inference_config=conf/decode_asr.yaml
lm_config=conf/train_lm_transformer.yaml
use_lm=true
speed_perturb_factors="0.9 1.0 1.1" # 速度扰动(3 倍数据扩充)
./asr.sh \
--ngpu 2 \
--lang zh \
--audio_format wav \
--feats_type raw \
--token_type char \
--use_lm ${use_lm} \
--lm_config "${lm_config}" \
--asr_config "${asr_config}" \
--inference_config "${inference_config}" \
--train_set "${train_set}" \
--valid_set "${valid_set}" \
--test_sets "${test_sets}" \
--speed_perturb_factors "${speed_perturb_factors}" \
--asr_speech_fold_length 512 \
--asr_text_fold_length 150 \
--lm_fold_length 150 \
--lm_train_text "data/${train_set}/text" "$@"
要点说明:
--speed_perturb_factors "0.9 1.0 1.1"会对训练集做 0.9/1.0/1.1 倍速扰动,扩充后训练集名为train_sp;--asr_speech_fold_length 512与--asr_text_fold_length 150控制训练时语音/文本按 512/150 的倍数截断,避免单 batch 内元素过多,配合batch_type: numel使用;"$@"允许在命令行追加覆盖参数,例如替换编码器配置:./run.sh --asr_config conf/tuning/train_asr_e_branchformer_linear1024.yaml即可切换到 12 层版本;- 若切换实验配置,可参考各 tuning 配置文件中的差异(
num_blocks、lr、warmup_steps、SpecAugment 参数)自行编写新配置。
环境与任务调度
执行前需先安装 ESPnet 依赖(参见仓库根目录 README.md 与 tools/README.md),并在 db.sh 中设置 AIDATATANG_200ZH=/path/to/data。任务调度后端由 cmd.sh 的 cmd_backend 变量控制,可选 local(本机并行,默认)、stdout、sge、pbs、slurm、ssh,对应 conf/queue.conf、conf/slurm.conf、conf/pbs.conf 等队列配置;多 GPU 训练时 --ngpu 2 会被传递到 cuda_cmd。GPU 数量、batch_bins、accum_grad 需根据显存实际情况调整。
E-Branchformer 架构原理(源码级解析)
E-Branchformer 编码器实现在 espnet2/asr/encoder/e_branchformer_encoder.py,核心是 EBranchformerEncoderLayer(第 58 行起)。从 forward 方法(第 113 行)可以清晰看到其块结构:
- 可选 macaron FFN 前置:若启用
macaron_ffn,先经过norm_ff_macaron+ 尺度为 0.5 的 FFN 残差子层(对应配置中的macaron_ffn: true); - 双分支并行:
- 分支 1(注意力):
x1 = self.norm_mha(x1)后进入多头自注意力,rel_selfattn使用相对位置编码pos_emb(配置pos_enc_layer_type: rel_pos); - 分支 2(卷积门控 MLP):
x2 = self.norm_mlp(x2)后进入ConvolutionalGatingMLP(cgmlp),对应配置中的cgmlp_linear_units: 1024、cgmlp_conv_kernel: 31、gate_activation: identity;
- 分支 1(注意力):
- 融合模块:
x_concat = torch.cat([x1, x2], dim=-1)拼接双分支输出,先经过mask_padded_frames屏蔽填充帧,再通过depthwise_conv_fusion(核大小merge_conv_kernel,深度卷积)沿时间维做局部融合,最后merge_proj线性投影回模型维度并残差相加; - 标准 FFN 残差:若
use_ffn: true,再经过norm_ff+ FFN 残差子层;最终norm_final输出。
EBranchformerEncoder(第 191 行)的构造参数与 YAML 一一对应,例如 num_blocks、layer_drop_rate(可配合 layer_drop_rate > 0 做层丢弃训练)等。与 Conformer 的"串行堆叠 MHSA、CNN、FFN"不同,E-Branchformer 让全局自注意力与局部卷积门控两条路径并行,再通过可学习的融合卷积合并,从而同时捕获全局与局部依赖——这正是 16 层配置在相同参数量下 CER 略优的结构性原因。
相关实现还可参考 e_branchformer_ctc_encoder.py(CTC 分支版本)以及训练入口脚本 espnet2/bin/asr_train.py(配置解析与训练循环)。
复现步骤总结
- 安装 ESPnet 与依赖,激活虚拟环境;
- 在
db.sh中设置AIDATATANG_200ZH数据存放路径; - 按需修改
cmd.sh中的cmd_backend(单机建议local)与conf/queue.conf; - 执行默认 16 层 E-Branchformer 实验:
./run.sh; - 复现 12 层变体:
./run.sh --asr_config conf/tuning/train_asr_e_branchformer_linear1024.yaml; - 复现 Conformer 基线:
./run.sh --asr_config conf/train_asr_conformer.yaml; - 训练完成后查看
exp/下各实验目录的decode_asr_lm_*结果,CER 通过show_asr_result.sh汇总展示(scripts/utils/show_asr_result.sh),或参照 README 中的 CER 表格格式整理报告。
如果只想评测不训练,也可以从 Hugging Face 下载 README 中记录的预训练模型链接(pyf98/aidatatang_200zh_e_branchformer_e16、pyf98/aidatatang_200zh_e_branchformer、sw005320/aidatatang_200zh_conformer),配合 inference 流程 直接对 dev/test 做解码验证。