SpeechBrain 端到端语音识别模板实战:Tokenizer + RNNLM + CRDNN/GRU 三步训练完整指南
本指南以 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),依赖 HuggingFace datasets |
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.yaml
2.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<a href="https://link.gitcode.com/i/85c915d01fcef05afd04e3b955e0ad6c" target="_blank">"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
先决条件:需要安装 HuggingFace datasets 库:
pip install datasets
LM 目录的 README.md 指出,该模板同时支持 RNN-based LM 与 Transformer-based LM(通过替换 YAML 中的模型定义实现),脚本的数据读取由 HuggingFace datasets 管理。
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.yaml
4.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-librispeech
pretrainer(见 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: 40
compute_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 保证训练可中断续跑。理解这一模板,即可在此基础上替换数据、模型与解码策略,快速搭建属于自己的语音识别系统。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.24 K638- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python670
SlideSCIPPT插件,支持素材库、AI助手、一键添加图片标题,复制粘贴位置、一键图片对齐、一键插入Markdown(加粗、超链接等行内样式、代码块、LaTeX等块级样式)、便捷导出图片!C#230
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python52874
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go22545
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java36351