SpeechBrain 端到端语音识别模板实战:Tokenizer + RNNLM + CRDNN/GRU 三步训练完整指南
【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain
本指南以 SpeechBrain 仓库中的templates/speech_recognition模板为主体,系统讲解如何从零构建一个离线端到端(E2E)注意力式语音识别系统:先基于 mini-Librispeech 训练 SentencePiece 子词 Tokenizer,再训练 RNN 语言模型,最后训练 CRDNN 编码器 + GRU 注意力解码器,并通过束搜索(Beam Search)耦合语言模型完成解码。读完本文,你将掌握 SpeechBrain 中 ASR 三阶段训练的标准流程、关键 YAML 配置项的含义与调参方法,以及将模板迁移到真实大数据集(如 LibriSpeech)的路径。
一、模板总览:一个完整的三步训练流水线
templates/speech_recognition目录实现了一个基于 mini-librispeech 的简单语音识别器,它是一个离线端到端注意力式语音识别系统。整个训练流程被刻意拆解为三个相互依赖的阶段:
- 训练 Tokenizer:基于训练集转录文本,决定用哪些词片(word piece)作为识别单元。大多数情况下,介于字符(char)与完整单词(word)之间的子词单元最为实用。
- 训练语言模型(LM):在 Tokenizer 产出的 token 序列之上训练 RNN 语言模型,为后续束搜索提供语言学先验。
- 训练语音识别器(ASR):训练 CRDNN 编码器与自回归 GRU 解码器,解码阶段使用耦合 RNN LM 的束搜索。
模板目录结构如下(均在仓库根目录下的 templates/speech_recognition 中):
| 目录/文件 | 作用 |
|---|---|
Tokenizer/ | SentencePiece 子词 Tokenizer 训练(train.py+tokenizer.yaml) |
LM/ | RNN/Transformer 语言模型训练(train.py+RNNLM.yaml),依赖 HuggingFacedatasets |
ASR/ | CTC + seq2seq 语音识别器训练与推理(train.py+train.yaml+inference.yaml+transcribe_file.py) |
mini_librispeech_prepare.py | 三个子目录共用的小型数据准备脚本,负责下载并生成 JSON manifest |
从源码看,这三个阶段之间存在强依赖关系:ASR 的 train.py 在注释中明确要求"先训练 Tokenizer(见 ../Tokenizer),再训练语言模型(见 ../LM),最后训练识别器";更重要的是,LM 与 ASR 必须使用同一个 Tokenizer,否则 AM/LM token 不匹配会导致束搜索结果严重劣化。
二、Step 1:训练 Tokenizer(SentencePiece 子词单元)
Token 的选择直接决定识别单元粒度:最原子的单元是字符(char),最粗的单元是完整单词。SpeechBrain 依赖流行的SentencePiece库完成分词。训练命令非常简单:
cd templates/speech_recognition/Tokenizer python train.py tokenizer.yaml2.1 配置解析:tokenizer.yaml
# 路径配置 data_folder: ../data output_folder: ./save skip_prep: False train_annotation: ../train.json valid_annotation: ../valid.json test_annotation: ../test.json # Tokenizer 参数 token_type: unigram # ["unigram", "bpe", "char"] token_output: 1000 # 词表大小;index(blank/eos/bos/unk) = 0 character_coverage: 1.0 annotation_read: words # 从 manifest 中读取的字段 tokenizer: !name:speechbrain.tokenizers.SentencePiece.SentencePiece model_dir: !ref <output_folder> vocab_size: !ref <token_output> annotation_train: !ref <train_annotation> annotation_read: !ref <annotation_read> model_type: !ref <token_type> character_coverage: !ref <character_coverage> annotation_list_to_check: [!ref <train_annotation>, !ref <valid_annotation>] annotation_format: json关键参数含义:
token_type:可选unigram、bpe、char。模板默认unigram(1K 词表);char对应字符级识别(最原子单元),bpe为字节对编码。注意token_output: 1000表示词表大小为 1000,且索引 0 预留给 blank/eos/bos/unk 特殊符号。character_coverage: 1.0:字符覆盖率,对纯英文语料设为 1.0 即可;若语料包含稀有字符或 CJK 文本,通常需要降低该值(如 0.9995)以避免词表被罕见字符占满。annotation_read: words:指明从 JSON manifest 的words字段读取转录文本用于训练。
2.2 训练入口:Tokenizer/train.py
脚本的执行逻辑清晰地对应了 SpeechBrain 的标准范式:
- 用
sb.parse_arguments解析命令行参数(支持在命令行以key:value形式覆盖 YAML 中的任意超参数); - 用
load_hyperpyyaml加载 YAML,YAML 中的!name:speechbrain.tokenizers.SentencePiece.SentencePiece与!ref语法会被解析为真实对象引用; - 若
skip_prep: False,调用prepare_mini_librispeech下载/准备数据并生成train.json、valid.json、test.json; - 最后执行
hparams["tokenizer"]()触发 speechbrain.tokenizers.SentencePiece 的__call__,完成子词模型训练,模型文件保存在Tokenizer/save/下,例如1000_unigram.model。
三、Step 2:训练语言模型(RNNLM)
拿到目标 token 后,需要在 token 序列之上训练语言模型。理想情况下应使用大规模文本语料(且语料领域与目标应用一致)。本模板为了演示,直接在 mini-librispeech 的训练转录文本上训练 LM:
cd templates/speech_recognition/LM python train.py RNNLM.yaml先决条件:需要安装 HuggingFacedatasets库:
pip install datasetsLM 目录的 README.md 指出,该模板同时支持RNN-based LM与Transformer-based LM(通过替换 YAML 中的模型定义实现),脚本的数据读取由 HuggingFacedatasets管理。
3.1 配置解析:RNNLM.yaml
seed: 2602 __set_seed: !apply:speechbrain.utils.seed_everything [!ref <seed>] lm_train_data: !ref <data_folder>/train.txt lm_valid_data: !ref <data_folder>/valid.txt lm_test_data: !ref <data_folder>/test.txt # 必须与 ASR 使用同一个 tokenizer tokenizer_file: ../Tokenizer/save/1000_unigram.model # 训练参数 number_of_epochs: 20 batch_size: 80 lr: 0.001 grad_accumulation_factor: 1 # 梯度累积,用于模拟大 batch 训练 ckpt_interval_minutes: 15 # 每 N 分钟保存一次 checkpoint # 模型参数 emb_dim: 256 # embedding 维度 rnn_size: 512 # 隐层维度 layers: 2 # 隐层层数 # 特殊符号 bos_index: 0 eos_index: 0 model: !new:custom_model.CustomModel embedding_dim: !ref <emb_dim> rnn_size: !ref <rnn_size> layers: !ref <layers> compute_cost: !name:speechbrain.nnet.losses.nll_loss optimizer: !name:torch.optim.Adam lr: !ref <lr> betas: (0.9, 0.98) eps: 0.000000001 lr_annealing: !new:speechbrain.nnet.schedulers.NewBobScheduler initial_value: !ref <lr> improvement_threshold: 0.0025 annealing_factor: 0.8 patient: 0要点说明:
tokenizer_file指向../Tokenizer/save/1000_unigram.model,通过pretrainer加载到sentencepiece.SentencePieceProcessor——这正是保证LM 与 ASR token 一致的关键机制。custom_model.CustomModel定义在同目录的 custom_model.py 中,用户可以直接编辑该类,或在 YAML 中替换!new指向自定义模型文件。- 学习率调度采用NewBob 算法:当连续两个 epoch 的改善低于
improvement_threshold: 0.0025时,将学习率乘以annealing_factor: 0.8。 - 训练目标为负对数似然(NLL);数据管线(见 LM/train.py 的
dataio_prepare)用 tokenizer 将文本编码为tokens_bos(前插 bos,喂给网络)与tokens_eos(后接 eos,用于计算损失)。
3.2 训练逻辑:LM/train.py
该脚本定义了一个继承sb.core.Brain的LM类,核心方法包括:
compute_forward:取tokens_bos输入self.hparams.model,输出下一 token 的后验概率;compute_objectives:用nll_loss计算预测与tokens_eos之间的损失;on_stage_end:在验证阶段调用lr_annealing更新学习率、记录统计并save_and_keep_only(meta=stats, min_keys=["loss"])保存最优 checkpoint。
数据读取方面,load_dataset("text", data_files={...})加载三个纯文本文件,再经DynamicItemDataset.from_arrow_dataset转为 SpeechBrain 的动态数据集,并通过add_dynamic_item+set_output_keys注册文本处理管线。
3.3 关于大规模 LM 训练的重要提醒
原模板文档特别强调:真实场景下训练 LM 的计算代价极其高昂,在大型语料上训练甚至可能耗费数周乃至数月(即使使用现代 GPU)。因此实践中更推荐的做法是:
- 复用现有 LM:从 HuggingFace 等平台加载已训练好的语言模型;
- 对现有 LM 做微调(fine-tune):仅用目标领域语料微调,成本远低于从零训练。
四、Step 3:训练语音识别器(CRDNN + GRU + Beam Search)
至此可以训练语音识别器本体。模板采用CRDNN模型(CNN + RNN + DNN 级联的编码器)+自回归 GRU 解码器,编码器与解码器之间使用注意力机制,最终词序列通过耦合 RNN LM 的束搜索获得:
cd templates/speech_recognition/ASR python train.py train.yaml4.1 训练配置全景:ASR/train.yaml
该 YAML 是模板中最完整的配置文件,覆盖数据、特征、增强、模型、解码五个层面。
(1)数据与数据准备
data_folder: ../data # 数据将自动下载到此处 data_folder_noise: !ref <data_folder>/noise # 增强用噪声 data_folder_rir: !ref <data_folder>/rir # 增强用房间冲激响应 pretrained_path: speechbrain/asr-crdnn-rnnlm-librispeechpretrainer(见 YAML 末尾)会从pretrained_path加载三样东西:lm.ckpt(预训练 RNNLM)、tokenizer.ckpt、asr.ckpt(在 LibriSpeech 960h 上预训练的 ASR 权重)。模板注释明确说明:mini-librispeech 数据量太小,无法支撑端到端模型从零训练收敛,因此用更大的模型预训练来保证收敛;真实场景下用大数据集可以从零开始训练并跳过预训练。你也可以把pretrained_path改为本地路径,指向自己训练好的 LM 与 Tokenizer。
(2)特征参数
sample_rate: 16000 n_fft: 400 n_mels: 40compute_features使用 speechbrain.lobes.features.Fbank 提取 40 维 Fbank 特征,normalize使用全局均值-方差归一化(norm_type: global)。
(3)训练超参数
number_of_epochs: 15 number_of_ctc_epochs: 5 # 前 5 个 epoch 使用 CTC 目标 batch_size: 8 lr: 1.0 ctc_weight: 0.5 # CTC 与 seq2seq 损失融合权重 sorting: ascending label_smoothing: 0.1模型采用CTC + NLL 多任务训练:前number_of_ctc_epochs个 epoch 同时激活 CTC 与 seq2seq 损失(ctc_weight: 0.5),之后只保留 seq2seq 注意力损失——这是 SpeechBrain 中"先 CTC 预热、后注意力精调"的经典收敛策略,对应 ASR/train.py 中的is_ctc_active(stage)判断逻辑。优化器使用 Adadelta(lr: 1.0, rho: 0.95),学习率调度同样为 NewBob。
(4)模型结构
# 编码器:CRDNN cnn_blocks: 2 cnn_channels: (128, 256) rnn_class: !name:speechbrain.nnet.RNN.LSTM rnn_layers: 4 rnn_neurons: 1024 rnn_bidirectional: True dnn_blocks: 2 dnn_neurons: 512 # 解码器:注意力 GRU emb_size: 128 dec_neurons: 1024 output_neurons: 1000 # token 数,必须与 LM 一致 blank_index: 0 bos_index: 0 eos_index: 0编码器为 speechbrain.lobes.models.CRDNN(2 层 CNN 卷积块 + 4 层双向 LSTM + 2 层 DNN);解码器为 speechbrain.nnet.RNN.AttentionalRNNDecoder(rnn_type: gru,attn_type: location位置注意力);顶部还有ctc_lin与seq_lin两个线性层分别输出 CTC 与 seq2seq 的 log 概率。整个模型通过torch.nn.ModuleList组装,RNNLM 单独作为lm_model(speechbrain.lobes.models.RNNLM.RNNLM,return_hidden: True供推理使用)。
(5)解码配置与 Scorer 体系
valid_beam_size: 8 test_beam_size: 80 eos_threshold: 1.5 max_attn_shift: 240 lm_weight: 0.50 ctc_weight_decode: 0.0 coverage_penalty: 1.5 temperature: 1.25 temperature_lm: 1.25模板构建了完整的束搜索 scorer 组合,全部来自 speechbrain.decoders.scorer:
ctc_scorer(CTCScorer):CTC + 注意力联合束搜索,可提升性能但拖慢解码;coverage_scorer(CoverageScorer):根据束搜索中累积的注意力权重施加覆盖惩罚;rnnlm_scorer(RNNLMScorer):以lm_weight: 0.5加权应用语言模型概率;ScorerBuilder:区分full_scorers(对全词表打分,如 LM、coverage)与partial_scorers(对剪枝后的 token 打分,如 CTC),scorer_beam_scale: 1.5控制剪枝规模。
验证阶段使用较轻量的valid_search(beam=8,仅 coverage scorer),测试阶段使用test_search(beam=80,叠加 LM + CTC scorer)。这些搜索器均实例化为 speechbrain.decoders.S2SRNNBeamSearcher。
(6)数据增强配置
train.yaml中同时展示了波形域与特征域两大增强体系(统一由 speechbrain.augment.augmenter.Augmenter 编排):
- 波形域(
wav_augment):加混响(AddReverb,RIR 数据自动下载)、加噪(AddNoise,SNR 0–15 dB)、语速扰动(SpeedPerturb,[85, 90, 95, 105, 110, 115]%)、频带丢弃(DropFreq)、时间片段丢弃(DropChunk)、削波(DoClip)、随机幅度(RandAmp)、语噪声(sum_batch求和模拟 babble)、位深降低(DropBitResolution)、编解码器增强(CodecAugment); - 特征域(
fea_augment):时间/频率平移(RandomShift)、时间/频率片段丢弃(SpectrogramDrop)、时间/频率弯曲(Warping,SpecAugment 风格); - 每个增强均配有
enable_*布尔开关,便于超参搜索时灵活启停;concat_original: True保证每个 batch 中保留未增强的原始样本。
YAML 注释也提醒:模板刻意演示了全部增强手段的用法,实际项目中应根据任务选择子集以获得更优性能。
4.2 训练入口:ASR/train.py
ASR(sb.Brain)类的核心流程:
prepare_features提取 Fbank 特征并归一化;compute_forward中:编码器输出encoded_signal→ embedding 嵌入tokens_bos→ 注意力解码器 →seq_lin+ log softmax 得到 seq2seq log 概率;CTC 激活时并行计算ctc_logprobs;- 验证/测试阶段调用
valid_search/test_search做束搜索并返回预测 token; compute_objectives中,CTC 损失(speechbrain.nnet.losses.ctc_loss)与 seq2seq 交叉熵损失按ctc_weight加权融合。
训练前,pretrainer.collect_files()会从pretrained_path下载 LM、tokenizer 与 ASR 预训练权重(或读取本地路径),随后checkpointer管理断点续训与最优模型保存。
五、推理:用训练好的模型转写音频
训练完成后,可使用 ASR/inference.yaml 与transcribe_file.py进行单文件转写。inference.yaml基本复制了train.yaml中的模型与解码配置(特征参数、CRDNN/GRU 结构、全部 scorer 参数),保证模型能被完整重载;其pretrained_path同样默认指向speechbrain/asr-crdnn-rnnlm-librispeech,因此也支持直接加载预训练模型做零训练推理。
六、从模板走向真实系统:规模与路径
模板的价值在于展示 SpeechBrain 如何组织一个 e2e 语音识别器,但真实系统必须用远超 mini-librispeech 的数据量训练才能达到可用性能。原文档明确指出:若要更具竞争力的数据规模方案,可参考仓库中的 LibriSpeech 完整食谱(recipes/LibriSpeech/ASR,包含 CTC、seq2seq、transformer、transducer 等多种配置)。此外,模板中 LM 与 ASR 共用同一 tokenizer 的约束、CTC 预热的收敛策略、scorer 组合的解码方式,均与生产级食谱保持一致,可作为将模板扩展到更大数据集的直接起点。
七、总结
templates/speech_recognition为 SpeechBrain 用户提供了一条从零构建端到端 ASR 的最小可行路径:
- Tokenizer(SentencePiece unigram/BPE)定义识别单元;
- RNNLM提供语言学先验(真实场景优先复用或微调);
- CRDNN + 注意力 GRU + CTC/NLL 联合训练,束搜索时通过
ScorerBuilder组合 LM、CTC、coverage 多路打分。
三阶段环环相扣,pretrainer机制保证 tokenizer 与 LM 的一致性,checkpointer保证训练可中断续跑。理解这一模板,即可在此基础上替换数据、模型与解码策略,快速搭建属于自己的语音识别系统。
【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考