SpeechBrain 实战:为 CommonVoice 训练 KenLM n-gram 语言模型并提升 Wav2Vec2 解码性能
2026/9/15 11:18:00 网站建设 项目流程

SpeechBrain 实战:为 CommonVoice 训练 KenLM n-gram 语言模型并提升 Wav2Vec2 解码性能

【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain

导读

本篇文章基于 SpeechBrain 仓库中的 recipes/CommonVoice/LM 配方,完整讲解如何为 Mozilla CommonVoice 数据集训练 KenLM n-gram 语言模型,并将其与已微调的 Wav2Vec2 ASR 模型结合,通过 CTC 束搜索(beam search)显著降低词错误率(WER)。读完本文,你将掌握从安装 KenLM 依赖、构建 n-gram 语料、编写超参数配置,到最终在解码阶段接入.arpa语言模型文件的完整实战链路。


一、背景:为什么 Wav2Vec2 需要 n-gram 语言模型

SpeechBrain 在 CommonVoice 上的 CTC 配方(recipes/CommonVoice/ASR/CTC/README.md)验证了一个重要结论:将 Wav2Vec2 与语言模型结合使用可以带来显著的性能提升,尤其是当模型在较小的语音数据集上微调时

其原理是:纯 CTC 解码只依赖声学模型输出的字符/子词概率,缺乏语言先验;而 n-gram 语言模型能够在束搜索过程中为"更像自然语言"的假设路径加分,从而纠正声学模型的拼写级错误。在 CommonVoice 实验中,SpeechBrain 使用训练集转写文本训练出的 5-gram 模型,在英语测试集上将 WER 从无 LM 时的水平进一步压低(如 5-gram 加持下英语验证集 WER 10.79 / 测试集 11.37,见 ASR/CTC README 结果表)。

注意:对于中文(zh-CN),由于"词"的概念不明确,该配方改用字符错误率(CER)评估,且不使用 5-gram 语言模型。

本 LM 配方即为此目的而设计:它读取 CommonVoice 训练集的转写文本,用 KenLM 训练 n-gram 模型,输出为业界标准的 ARPA 格式,可直接被 SpeechBrain 的 CTC 束搜索解码器加载。


二、配方文件结构

本配方位于 recipes/CommonVoice/LM,共四个文件:

文件作用
train.py主训练脚本:解析超参数、准备数据、调用lmplz训练 n-gram、修复 ARPA 文件中缺失的</s>符号
hparams/train_kenlm.yaml超参数配置:语言、数据路径、文本路径、gram 阶数等
common_voice_prepare.py数据准备脚本(与 recipes/CommonVoice/common_voice_prepare.py 同源):将.tsv标注转换为 SpeechBrain 使用的 CSV 格式
README.md使用说明(即本文依据)

需要说明的是,该配方没有独立的extra_requirements.txt文件,README 中提到的pip install -r extra_requirements.txt是指 KenLM 的 Python 绑定等额外依赖,具体安装方式见下文。


三、环境准备:安装 KenLM 及依赖

KenLM 是一个用 C++ 编写的高效 n-gram 语言模型工具库,其命令行程序lmplz负责从纯文本语料统计并训练 n-gram 模型。安装分三步:

1. 安装 Ubuntu 系统依赖

sudo apt install build-essential cmake libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-test-dev libeigen3-dev zlib1g-dev libbz2-dev liblzma-dev

这些包分别提供编译工具链(build-essentialcmake)、Boost 库(KenLM 依赖的线程/程序选项/测试组件)、Eigen3 线性代数库以及 zlib/bz2/lzma 压缩支持。完整依赖说明可参考 KenLM 官方依赖指南(https://kheafield.com/code/kenlm/dependencies/)。

2. 下载并解压 KenLM 源码

wget -O - https://kheafield.com/code/kenlm.tar.gz | tar xz

3. 使用 CMake 编译二进制

KenLM 使用 C++ 编写,通过 CMake 构建:

mkdir kenlm/build && cd kenlm/build && cmake .. && make -j2

-j2指定 2 个并行编译任务,可根据机器 CPU 核数调大。

4. 将可执行文件加入 PATH

lmplzbuild_binary等可执行文件位于kenlm/build/bin,需要将其加入环境变量:

  • 用文本编辑器打开~/.bashrc
  • 在文件末尾追加一行(替换为自己的实际路径):
    export PATH=$PATH:/your/path/to/kenlm/build/bin
  • 保存后执行source ~/.bashrc使配置生效

提示:KenLM 的 Python 绑定(供解码阶段加载模型使用)可通过pip install https://github.com/kpu/kenlm/archive/master.zip安装,见 speechbrain/decoders/ctc.py 中的安装提示。


四、超参数配置详解

hparams/train_kenlm.yaml 是训练的核心配置,使用 SpeechBrain 的 HyperPyYAML 语法(!ref引用变量、!PLACEHOLDER标记必填占位符):

# Seed needs to be set at top of yaml, before objects with parameters are made seed: 1986 __set_seed: !apply:speechbrain.utils.seed_everything [!ref <seed>] output_folder: !ref results/CommonVoice/ngrams/<language>/<seed> # Data files data_folder: !PLACEHOLDER # e.g, /localscratch/cv-corpus-14.0-2023-06-23/en train_tsv_file: !ref <data_folder>/train.tsv language: en # accented_letters should be set according to the language accented_letters: True train_csv: !ref <output_folder>/train.csv skip_prep: False text_file: !ref <output_folder>/train.txt ngram: 5 ngram_file: !ref <output_folder>/<language>_<ngram>gram.arpa

各参数含义:

参数默认值说明
seed1986随机种子,通过speechbrain.utils.seed_everything保证可复现
output_folderresults/CommonVoice/ngrams/<language>/<seed>输出目录,含中间 CSV、txt 语料与最终 ARPA 模型
data_folder必填占位符CommonVoice 数据根目录,需包含语言子目录,如cv-corpus-14.0-2023-06-23/en
train_tsv_file<data_folder>/train.tsvCommonVoice 官方训练标注文件(Tab 分隔)
languageen语言代码,决定文本规范化规则(见第六节)
accented_lettersTrue是否保留带重音字母;False时会将重音字母转成最近的非重音形式
train_csv<output_folder>/train.csv数据准备阶段生成的 CSV(含wrd转写列)
skip_prepFalseTrue时跳过数据准备(语料已存在时加速)
text_file<output_folder>/train.txtlmplz训练的纯文本语料(每行一句)
ngram5n-gram 阶数,CommonVoice 实验中使用 5-gram
ngram_file<output_folder>/<language>_<ngram>gram.arpa输出的 ARPA 格式模型路径,如en_5gram.arpa

五、运行训练

确保数据就绪后(CommonVoice 数据集需先从commonvoice.mozilla.org/en下载),在 recipes/CommonVoice/LM 目录下执行:

python train.py hparams/train_kenlm.yaml --data_folder=your/data/folder

--data_folder通过 HyperPyYAML 的命令行覆盖机制(sb.parse_arguments)直接覆盖配置中的!PLACEHOLDER,无需修改 YAML 文件。

训练流程拆解

脚本 train.py 的执行逻辑清晰,共五步:

第 1 步:解析超参数并创建实验目录

hparams_file, run_opts, overrides = sb.parse_arguments(sys.argv[1:]) with open(hparams_file, encoding="utf-8") as fin: hparams = load_hyperpyyaml(fin, overrides) sb.create_experiment_directory( experiment_directory=hparams["output_folder"], hyperparams_to_save=hparams_file, overrides=overrides, )

第 2 步:数据准备(仅主进程执行,兼容 DDP)

if not os.path.exists(hparams["text_file"]): run_on_main( prepare_common_voice, kwargs={ "data_folder": hparams["data_folder"], "save_folder": hparams["output_folder"], "train_tsv_file": hparams["train_tsv_file"], "accented_letters": hparams["accented_letters"], "language": hparams["language"], "skip_prep": hparams["skip_prep"], }, ) csv2text()

prepare_common_voice(来自 recipes/CommonVoice/common_voice_prepare.py)负责将train.tsv转换为 CSV,并执行文本清洗(详见第六节)。run_on_main保证多卡(DDP)环境下只在主进程执行一次,避免数据重复准备。

第 3 步:CSV 转纯文本语料

csv2text()读取train.csv,定位wrd列,把每条转写按行写入train.txt

def csv2text(): annotation_file = open(hparams["train_csv"], newline="", encoding="utf-8") reader = csv.reader(annotation_file) headers = next(reader, None) text_file = open(hparams["text_file"], "w+", encoding="utf-8") index_label = headers.index("wrd") for row in reader: sent = row[index_label] text_file.write(sent + "\n")

第 4 步:调用lmplz训练 n-gram

tmp_ngram_file = "ngram.arpa" cmd = f'lmplz -o {hparams["ngram"]} <"{hparams["text_file"]}" > "{tmp_ngram_file}"' os.system(cmd)

lmplz -o 5表示训练 5-gram 模型,输入语料来自train.txt,原始输出暂存到ngram.arpa

第 5 步:修复 ARPA 文件中的</s>符号

这是本配方一个值得注意的实现细节:lmplz默认只写出<s>起始符,而 SpeechBrain 的束搜索解码需要</s>结束符来正确截断假设。脚本遍历 ARPA 文件,在ngram 1=计数行上把 unigram 数量 +1,并在首个<s>条目后追加一个等概率的</s>条目:

with open(tmp_ngram_file, encoding="utf-8") as read_file, open( hparams["ngram_file"], "w", encoding="utf-8" ) as write_file: has_added_eos = False for line in read_file: if not has_added_eos and "ngram 1=" in line: count = line.strip().split("=")[-1] write_file.write(line.replace(f"{count}", f"{int(count) + 1}")) elif not has_added_eos and "<s>" in line: write_file.write(line) write_file.write(line.replace("<s>", "</s>")) has_added_eos = True else: write_file.write(line) os.remove(tmp_ngram_file)

最终模型写入ngram_file指定路径(如en_5gram.arpa),临时文件被清理。训练日志会输出模型路径:

5-gram kenlm model was built and saved in results/CommonVoice/ngrams/en/1986/en_5gram.arpa.

六、语言相关的文本规范化

n-gram 语料质量直接影响模型效果。prepare_common_voice在生成 CSV 时会根据language参数执行语言特定的预处理(common_voice_prepare.py):

  • 英语/法语/意大利语/基尼亚卢旺达语(en/fr/it/rw):过滤掉字母、数字与重音字符之外的符号,并统一转为大写;
  • 德语(de):特殊处理ß(先替换为占位符再upper(),避免 Python 的upper()ß变成SS导致信息丢失);
  • 法语(fr):额外处理L'D'J'等粘连撇号与AUJOURD'HUI等复合词;
  • 阿拉伯语(ar)/波斯语(fa):使用各自字母表白名单过滤;
  • 爱尔兰语(ga-IE):采用复杂的大小写规则(upper()不确定,改用小写加前缀规则);
  • 西班牙语(es):修复数据集中$符号导致的键错误,将$替换为s

此外,若accented_letters=False,还会通过 Unicode NFD 规范化剥离重音(strip_accents),并将'替换为空格。这些规则保证了进入lmplz的语料干净、一致,避免 OOV(词表外词)噪声。


七、将 n-gram 模型接入 CTC 束搜索解码

训练好的 ARPA 模型要与 ASR 系统结合,需要在 CTC 配方的解码配置中启用 KenLM。以 recipes/CommonVoice/ASR/CTC/hparams/train_en_with_wav2vec.yaml 为例:

test_beam_search: blank_index: !ref <blank_index> beam_size: 100 beam_prune_logp: -12.0 token_prune_min_logp: -1.2 prune_history: False topk: 1 alpha: 1.0 beta: 0.5 # To use n-gram LM for decoding, follow steps in README.md. # kenlm_model_path: none

接入步骤(见 ASR/CTC README):

  1. 取消注释test_beam_search中的kenlm_model_path一行;
  2. 将其值设置为上一步训练出的 ARPA(或build_binary转换的.bin)文件路径。

在源码层面,speechbrain/decoders/ctc.py 中的CTCBeamSearcher接收kenlm_model_path参数,文档注释明确说明:

kenlm_model_path : str, optional— The path to the kenlm model.Use .bin for a faster loading.

也就是说,若希望解码时加载更快,可先用 KenLM 的build_binary工具将.arpa转为二进制.bin格式。kenlm_model通过 Python 绑定kenlm.Model(kenlm_model_path)加载,当传入.arpa时会进一步调用load_unigram_set_from_arpa提取 unigram 集合(ctc.py)。

其他束搜索参数的作用:

参数说明
beam_size100束宽,越大搜索越充分但越慢
beam_prune_logp-12.0束内剪枝的 log 概率阈值
token_prune_min_logp-1.2单 token 剪枝阈值
alpha1.0LM 权重(对数域插值系数)
beta0.5长度惩罚系数

八、结果与产出物

训练完成后,输出目录(results/CommonVoice/ngrams/<language>/<seed>/)包含:

  • train.csv:SpeechBrain 格式的训练标注(含ID, duration, wav, spk_id, wrd五列);
  • train.txt:逐句转写纯文本语料;
  • <language>_<ngram>gram.arpa:最终 n-gram 模型(ARPA 格式),即解码所需的产物。

仓库 ASR/CTC README 结果表 展示了该 5-gram 模型在英语(2024-01-05 版 CommonVoice)上取得的验证集 WER 10.79、测试集 WER 11.37 的成绩;预训练的 n-gram 模型也可从 README 提供的 Dropbox 共享文件夹获取,它们同样基于 CommonVoice 训练集转写训练。


九、小结

通过本配方,你可以在 SpeechBrain 框架内以"数据准备 → 文本语料构建 → KenLM n-gram 训练 → ARPA 修复 → CTC 束搜索接入"的完整链路,为任意支持语言的 CommonVoice 数据集训练 n-gram 语言模型,从而显著改善 Wav2Vec2 在小数据量场景下的解码效果。关键要点回顾:

  • KenLM 需先安装系统依赖并通过 CMake 编译,lmplz可执行文件需加入PATH
  • 超参数集中于 train_kenlm.yaml,ngram: 5是 CommonVoice 实验中的默认选择;
  • 训练脚本会自动修复 ARPA 文件缺失的</s>符号,无需手工干预;
  • 语言相关文本规范化由language参数控制,多语言场景请按需调整accented_letters
  • 解码接入只需在test_beam_search中设置kenlm_model_path,生产环境建议使用.bin格式加速加载。

如果你使用 SpeechBrain 进行科研或商业用途,请按 README.md 末尾给出的 BibTeX 条目引用 SpeechBrain。

【免费下载链接】speechbrainA PyTorch-based Speech Toolkit项目地址: https://gitcode.com/GitHub_Trending/sp/speechbrain

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询