FunASR 语言模型(LM)训练实战:从 n-gram 语料到解码图 TLG.fst 的完整流程 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/FunASRFunASR 支持为离线/混合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 FSTT.fst与 lexicon FSTL.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.txtAM声学模型的建模单元表。注意文档特别强调——如果目标是匹配8k 采样率的 AM 模型应改用lm_8358.tar.gz包因为不同 AM 模型的输出单元集不同LM 编译的 token 表必须与 AM 输出对齐。语料解压后会得到lm/目录其中text是 LM 训练语料lexicon.txt是词 → 单元序列的映射units.txt列出 AM 全部建模单元。训练 arpasrilm 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-L23ngram-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-gram4 元语言模型-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_ALLC。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.fstcompile_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.fsttoken FST由 ctc_token_fst.py 为每个 CTC 标签生成发音 自环结构——每个 token 节点带一个同标签自环用于吸收 CTC 框架中重复发射然后经fstcompilefstarcsort --sort_typeolabel编译并排序见 compile_dict_token.sh#L56-L58。构造 word 表words.txteps为 0 号各词按序编号末尾追加#0、s、/s三个符号。编译 L.fstlexicon FST先用 perl 给 lexicon 每条目附加 1.0 概率再经make_lexicon_fst.pl生成词→单元 FSTfstaddselfloops分别给 token 侧与 word 侧加自环后编译见 compile_dict_token.sh#L74-L82。脚本执行成功会输出Dict and token FSTs compiling succeeded。第二步make_decode_graph.sh —— 编译 G.fst 并合成 TLG.fstmake_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_typeilabel排序见 make_decode_graph.sh#L13-L21。脚本还会用fstisstochastic检查 G.fst 的随机性输出第一个数应接近 0即各源点的出射概率和约等于 1。合成最终解码图fsttablecompose L.fst G.fst | fstdeterminizestar --use-logtrue | 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.fst4-gram 语言模型的概率约束TLG.fstT ∘ L ∘ G 的合成结果供解码器直接使用的最终解码图收集推理资源lm/resourcefst/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#L55HTTP 服务端二进制 funasr-http-main.cpp#L156 的参数说明与之相同代码中会直接加载lm_dir/TLG.fst见 funasr-http-main.cpp#L412。从源码结构看离线解码路径同样以TLG.fstconfig.yaml作为 LM 资源约定宏定义LM_FST_RES TLG.fst见 com-define.h#L85。因此交付时建议把lm/resource整体必要时补上lexicon.txt作为 LM 模型目录传给推理服务。实践要点小结环境依赖srilmngram-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首值应接近 0make_decode_graph.sh成功会打印Composing decoding graph TLG.fst succeededcollect_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),仅供参考