FunASR 语言模型(LM)训练实战:从 n-gram 语料到解码图 TLG.fst 的完整流程
2026/9/13 9:28:57 网站建设 项目流程

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 按顺序执行了同样五个阶段:

  1. 数据准备:下载示例语料textlexicon与 AM 建模单元units.txt
  2. 训练 arpa:用 srilm 的ngram-count训练 4 元 n-gram 语言模型;
  3. 生成 lexicon:将词表映射到 AM 单元(字/音素),得到lexicon.out
  4. 编译 TLG.fst:先编译 token FST(T.fst)与 lexicon FST(L.fst),再把 LM 编译为 G.fst 并合成为最终解码图 TLG.fst;
  5. 收集资源:产出推理侧所需的lm/resource目录(含TLG.fstconfig.yaml)。

数据准备

按 LM 训练教程 的说法,先下载示例训练语料(含textlexicon和 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-countarpa2fstadddisambig等工具),FST 编译则依赖 Kaldi FST 工具集,文档建议参考 ONNXRuntime 运行环境说明 安装 FST 相关环境。

执行:

bash fst/train_lms.sh

train_lms.sh 内部做了三件事:

  1. 生成词表lm/corpus.dict:对lm/text提取第 2 列起的每个词、小写化,再并入特殊符号<unk><s></s>,去重排序得到(见 train_lms.sh#L15-L17)。
  2. 生成训练文本lm/train:把每条句子的词序列拼成一行,供 n-gram 计数使用。
  3. 训练 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.out

generate_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 工具链的PATHLC_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.outunits.txt。它完成了标准 Kaldi 风格的 FST 准备工作:

  1. 构造 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)。
  2. 编译 T.fst(token FST):由 ctc_token_fst.py 为每个 CTC 标签生成"发音 + 自环"结构——每个 token 节点带一个同标签自环,用于吸收 CTC 框架中重复发射,然后经fstcompile+fstarcsort --sort_type=olabel编译并排序(见 compile_dict_token.sh#L56-L58)。
  3. 构造 word 表words.txt<eps>为 0 号,各词按序编号,末尾追加#0<s></s>三个符号。
  4. 编译 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>两个参数:

  1. LM 转 G.fst:读取lm/lm.arpa,先用grep过滤掉<s> <s></s> <s></s> </s><unk>行(ARPA 中的背景/未登录项,避免与符号表冲突),再经arpa2fst转成 FST,并用fst/eps2disambig.plfst/s2eps.pl做 Kaldi 风格的<s>/</s>消歧改写,最后fstrmepsilon去 ε、fstarcsort --sort_type=ilabel排序(见 make_decode_graph.sh#L13-L21)。脚本还会用fstisstochastic检查 G.fst 的随机性(输出第一个数应接近 0,即各源点的出射概率和约等于 1)。
  2. 合成最终解码图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.fst4-gram 语言模型的概率约束
TLG.fstT ∘ L ∘ G 的合成结果,供解码器直接使用的最终解码图

收集推理资源:lm/resource

fst/collect_resource_file.sh lm lm/resource

collect_resource_file.sh 会校验lm/lang/TLG.fst存在后:

  1. TLG.fst复制到lm/resource/(见 collect_resource_file.sh#L13);
  2. 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-countarpa2fst)、Kaldi FST 工具集(fstcompilefsttablecomposefstdeterminizestar等),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 succeededcollect_resource_file.sh会在缺TLG.fstwords.txt时直接报错退出;
  • 一键执行:在runtime/tools下运行 train_compile_ngram.sh 即可复现本文全部步骤,替换lm/textlm/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),仅供参考

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

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

立即咨询