FunASR 语言模型(LM)训练实战:从 n-gram 语料到解码图 TLG.fst 的完整流程
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
FunASR 支持为离线/混合(2-pass)解码流程训练自己的语言模型,并将其编译为 FST 解码图TLG.fst,供 ONNXRuntime 与 HTTP 推理引擎在解码时加载。本文基于仓库文档 LM 训练教程 与 训练脚本 展开,完整覆盖数据准备、n-gram 语言模型训练、lexicon 生成、FST 编译和资源收集五个阶段,并结合runtime/tools/fst/下的脚本实现说明每一步的底层逻辑,帮助你在掌握流程后能为自己的领域语料定制 LM。
整体流程概览
整个 LM 训练与编译链路如下,仓库提供的一键脚本 train_compile_ngram.sh 按顺序执行了同样五个阶段:
- 数据准备:下载示例语料
text、lexicon与 AM 建模单元units.txt; - 训练 arpa:用 srilm 的
ngram-count训练 4 元 n-gram 语言模型; - 生成 lexicon:将词表映射到 AM 单元(字/音素),得到
lexicon.out; - 编译 TLG.fst:先编译 token FST(T.fst)与 lexicon FST(L.fst),再把 LM 编译为 G.fst 并合成为最终解码图 TLG.fst;
- 收集资源:产出推理侧所需的
lm/resource目录(含TLG.fst与config.yaml)。
数据准备
按 LM 训练教程 的说法,先下载示例训练语料(含text、lexicon和 AM 建模单元units.txt):
# 下载: 示例训练语料text、lexicon 和 am建模单元units.txt wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/requirements/lm.tar.gz # 如果是匹配8k的am模型,使用 https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/requirements/lm_8358.tar.gz tar -zxvf lm.tar.gz需要准备两类语料文件:
- 训练语料
lm/text:一行一条,首列为句子 ID,其余为已按词(word)切分并全部小写化的文本,例如:
BAC009S0002W0122 而 对 楼市 成交 抑制 作用 最 大 的 限 购 BAC009S0002W0123 也 成为 地方 政府 的 眼中 钉units.txt:AM(声学模型)的建模单元表。注意文档特别强调——如果目标是匹配8k 采样率的 AM 模型,应改用lm_8358.tar.gz包,因为不同 AM 模型的输出单元集不同,LM 编译的 token 表必须与 AM 输出对齐。
语料解压后会得到lm/目录,其中text是 LM 训练语料,lexicon.txt是"词 → 单元序列"的映射,units.txt列出 AM 全部建模单元。
训练 arpa:srilm n-gram 语言模型
前置依赖:确保 srilm 已安装(提供ngram-count、arpa2fst、adddisambig等工具),FST 编译则依赖 Kaldi FST 工具集,文档建议参考 ONNXRuntime 运行环境说明 安装 FST 相关环境。
执行:
bash fst/train_lms.shtrain_lms.sh 内部做了三件事:
- 生成词表
lm/corpus.dict:对lm/text提取第 2 列起的每个词、小写化,再并入特殊符号<unk>、<s>、</s>,去重排序得到(见 train_lms.sh#L15-L17)。 - 生成训练文本
lm/train:把每条句子的词序列拼成一行,供 n-gram 计数使用。 - 训练 4 元 LM,核心命令为(见 train_lms.sh#L22-L23):
ngram-count -text $dir/train -order 4 -limit-vocab -vocab $dir/corpus.dict -unk \ -kndiscount -interpolate -gt1min 1 -gt2min 1 -gt3min 2 -gt4min 2 -lm $dir/lm.arpa各参数含义:
| 参数 | 作用 |
|---|---|
-order 4 | 训练 4-gram(4 元)语言模型 |
-limit-vocab -vocab lm/corpus.dict | 只统计词表内出现过的词,控制词表规模 |
-unk | 为未登录词保留<unk>概率 |
-kndiscount | 使用 Kneser-Ney 平滑 |
-interpolate | 对低阶 n-gram 做插值平滑 |
-gt1min 1 -gt2min 1 -gt3min 2 -gt4min 2 | 各阶 n-gram 的最小出现次数(1-gram/2-gram 至少 1 次,3/4-gram 至少 2 次),用于过滤低频噪声 |
-lm lm/lm.arpa | 输出标准 ARPA 格式的语言模型文件 |
最终产物是lm/lm.arpa,即后续编译 G.fst 的输入。
生成 lexicon:词到 AM 单元的映射
LM 工作在"词"层面,而解码图要求与 AM 输出的"单元"层面对齐,因此需要把corpus.dict中的每个词映射为单元序列。执行:
python3 fst/generate_lexicon.py lm/corpus.dict lm/lexicon.txt lm/lexicon.outgenerate_lexicon.py 的映射策略(见 generate_lexicon.py#L21-L35):
- 逐行读取
corpus.dict(跳过<s>/</s>); - 若该词在
lexicon.txt(制表符分隔的两列格式:词、单元序列)中直接命中,则取整词映射; - 否则退化为逐字映射:按字查
lexicon.txt,能查到的拼上对应单元,查不到的字填<unk>; - 输出
word\tunit1 unit2 ...格式的lm/lexicon.out。
这种"整词优先、逐字兜底"的策略保证了解码图覆盖语料中全部词汇,即使 lexicon 本身不完整也不会报错,未覆盖部分以<unk>形式进入 FST。
编译解码图 TLG.fst
编译前需进入runtime/tools目录并加载环境变量脚本 path.sh(它会设置 FST 工具链的PATH与LC_ALL=C)。FST 编译分两步,全部命令在 LM 训练教程 中给出:
# Compile the lexicon and token FSTs fst/compile_dict_token.sh lm lm/tmp lm/lang # Compile the language-model FST and the final decoding graph TLG.fst fst/make_decode_graph.sh lm lm/lang || exit 1; # Collect resource files required for decoding fst/collect_resource_file.sh lm lm/resource # 编译后的模型资源位于 lm/resource第一步:compile_dict_token.sh —— 编译 T.fst 与 L.fst
compile_dict_token.sh 需要三个参数:<dict-src-dir> <tmp-dir> <lang-dir>,输入目录须包含lexicon.out与units.txt。它完成了标准 Kaldi 风格的 FST 准备工作:
- 构造 token 表
tokens.txt:以<eps>为 0 号符号,随后按units.txt顺序编号全部 AM 单元,再追加消歧符号#0、#1……(编号列表来自 lexicon 消歧脚本add_lex_disambig.pl的返回值 +1)。消歧符号是 L.fst 与 G.fst 合成后能成功确定性化(determinization)的关键,脚本内注释明确说明"Without these symbols, determinization will fail"(见 compile_dict_token.sh#L44-L54)。 - 编译 T.fst(token FST):由 ctc_token_fst.py 为每个 CTC 标签生成"发音 + 自环"结构——每个 token 节点带一个同标签自环,用于吸收 CTC 框架中重复发射,然后经
fstcompile+fstarcsort --sort_type=olabel编译并排序(见 compile_dict_token.sh#L56-L58)。 - 构造 word 表
words.txt:<eps>为 0 号,各词按序编号,末尾追加#0、<s>、</s>三个符号。 - 编译 L.fst(lexicon FST):先用 perl 给 lexicon 每条目附加 1.0 概率,再经
make_lexicon_fst.pl生成词→单元 FST,fstaddselfloops分别给 token 侧与 word 侧加自环后编译(见 compile_dict_token.sh#L74-L82)。
脚本执行成功会输出Dict and token FSTs compiling succeeded。
第二步:make_decode_graph.sh —— 编译 G.fst 并合成 TLG.fst
make_decode_graph.sh 接收<lm_dir> <tgt_lang>两个参数:
- LM 转 G.fst:读取
lm/lm.arpa,先用grep过滤掉<s> <s>、</s> <s>、</s> </s>和<unk>行(ARPA 中的背景/未登录项,避免与符号表冲突),再经arpa2fst转成 FST,并用fst/eps2disambig.pl与fst/s2eps.pl做 Kaldi 风格的<s>/</s>消歧改写,最后fstrmepsilon去 ε、fstarcsort --sort_type=ilabel排序(见 make_decode_graph.sh#L13-L21)。脚本还会用fstisstochastic检查 G.fst 的随机性(输出第一个数应接近 0,即各源点的出射概率和约等于 1)。 - 合成最终解码图:
fsttablecompose L.fst G.fst | fstdeterminizestar --use-log=true | fstminimizeencoded得到确定性、最小化的LG.fst,再与T.fst合成得到TLG.fst,最后删除中间产物LG.fst(见 make_decode_graph.sh#L27-L33)。
三个 FST 的分工可以这样理解:
| FST | 作用 |
|---|---|
| T.fst | 把 CTC 输出单元(含 blank 自环)映射到解码空间 |
| L.fst | 词 ↔ AM 单元的 lexicon 映射(含消歧符号与自环) |
| G.fst | 4-gram 语言模型的概率约束 |
| TLG.fst | T ∘ L ∘ G 的合成结果,供解码器直接使用的最终解码图 |
收集推理资源:lm/resource
fst/collect_resource_file.sh lm lm/resourcecollect_resource_file.sh 会校验lm/lang/TLG.fst存在后:
- 把
TLG.fst复制到lm/resource/(见 collect_resource_file.sh#L13); - 从
lm/lang/words.txt取第一列生成lm/resource/config.yaml,内容为 YAML 的token_list列表——即解码图 word 符号表的反查表,推理引擎用它把 FST 输出的符号 ID 还原为文本(见 collect_resource_file.sh#L16-L29)。
最终lm/resource/目录包含:
lm/resource/ ├── TLG.fst # 编译后的解码图 └── config.yaml # token_list:符号 ID 到词的反查表推理侧如何加载
编译产物交给 FunASR runtime 的 C++ 推理引擎使用。以 2-pass(混合解码)ONNXRuntime 二进制为例,--lm_dir参数帮助文本明确要求该目录"包含编译后的模型:TLG.fst, config.yaml, lexicon.txt"(见 funasr-onnx-2pass.cpp#L55);HTTP 服务端二进制 funasr-http-main.cpp#L156 的参数说明与之相同,代码中会直接加载<lm_dir>/TLG.fst(见 funasr-http-main.cpp#L412)。从源码结构看,离线解码路径同样以TLG.fst+config.yaml作为 LM 资源约定(宏定义LM_FST_RES "TLG.fst",见 com-define.h#L85)。因此交付时建议把lm/resource整体(必要时补上lexicon.txt)作为 LM 模型目录传给推理服务。
实践要点小结
- 环境依赖:srilm(
ngram-count、arpa2fst)、Kaldi FST 工具集(fstcompile、fsttablecompose、fstdeterminizestar等),FST 环境安装参考 ONNXRuntime 运行环境说明; - 语料格式:
lm/text首列为句 ID、词已切分且小写;lexicon.txt为制表符分隔的两列; - 采样率匹配:8k AM 模型务必使用
lm_8358.tar.gz中的units.txt与 lexicon,保证 LM token 空间与 AM 输出一致; - 常见校验点:
fstisstochastic首值应接近 0;make_decode_graph.sh成功会打印Composing decoding graph TLG.fst succeeded;collect_resource_file.sh会在缺TLG.fst或words.txt时直接报错退出; - 一键执行:在
runtime/tools下运行 train_compile_ngram.sh 即可复现本文全部步骤,替换lm/text与lm/lexicon.txt为你自己的领域语料即可训练定制 LM。
【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考