语音识别中的语言模型:N-gram 与平滑算法详解
在语音识别系统中,仅靠声学模型往往不足以应对复杂的词汇表。当词汇量达到数万甚至数十万时,解码空间巨大,单纯依靠声学概率会导致大量错误组合。因此,必须引入语言模型(Language Model, LM)来约束识别结果,确保输出序列符合自然语言的语法和语义习惯。例如,让'今天天气很好'的概率远高于'今天天汽很好'。
1. 语言模型基础
定义与本质
语言模型的核心任务是计算一个词序列出现的概率。给定词序列 $S = (w_1, w_2, …, w_n)$,语言模型的目标是估计联合概率 $P(w_1, w_2, …, w_n)$。
从本质上讲,语言模型是对语句的概率分布进行建模。通俗来说,它用于判断一句话是否合理,或者计算该句子在语料库中出现的频率。
链式法则分解
根据概率论的链式法则,联合概率可以分解为条件概率的乘积:
$$ P(w_1, w_2, …, w_n) = P(w_1) \times P(w_2|w_1) \times P(w_3|w_1, w_2) \times … \times P(w_n|w_1, …, w_{n-1}) $$
面临的挑战
直接基于历史所有词计算条件概率面临两个主要问题:
- 自由参数问题:随着字符串长度增加,可能的上下文组合呈指数级增长,导致模型参数无法有效估计。
- 零概率问题(OOV):训练语料有限,许多合理的词序列未出现过,导致最大似然估计结果为 0,使得整个句子概率为 0。
2. N-gram 语言模型
为解决上述问题,引入了马尔科夫假设(Markov Assumption):当前词出现的概率仅依赖于前 $n-1$ 个词。基于此假设的统计语言模型称为 N-gram 模型。
公式表示
对于词序列 $S=(w_1, w_2, …, w_n)$,其概率近似为:
$$ P(w_1, w_2, …, w_n) \approx \prod_{i=1}^{n} P(w_i | w_{i-n+1}, …, w_{i-1}) $$
其中,$w_{i-n+1}$ 到 $w_{i-1}$ 构成了长度为 $n-1$ 的历史上下文。
N 的取值
- Unigram (n=1):词之间相互独立,忽略上下文。
- Bigram (n=2):依赖前一个词。
- Trigram (n=3):依赖前两个词。
理论上 $n$ 越大效果越好,但参数数量随 $n$ 指数增长,且数据稀疏性加剧。通常在实际应用中,3-gram 或 4-gram 是平衡效果与效率的常用选择。
3. 数据平滑算法
由于语料稀疏性,许多 N-gram 在训练集中计数为 0。平滑(Smoothing)技术通过重新分配概率质量,解决零概率问题。
(1)加一平滑(Add-one Smoothing)
思想:将所有计数加 1,使未出现过的 N-gram 也有非零概率。
公式:
$$ P_{add1}(w_i | h) = \frac{C(h, w_i) + 1}{C(h) + V} $$
其中 $V$ 为词汇表大小。
优缺点:简单直观,但会给未出现项分配过多概率,导致已出现项概率被稀释。
(2)古德 - 图灵平滑(Good-Turing Smoothing)
思想:利用出现次数为 $r$ 的 N-gram 的数量来估计出现次数为 $r^*$ 的概率。即'用看见过一次的估计没看见过的'。
应用:常用于调整高频词的折扣率,将部分概率转移给低频或未出现词。
(3)回退平滑(Katz Smoothing / Back-off)
思想:优先使用高阶模型;若高阶不存在,则回退到低阶模型并打折。
流程:
- 检查 $n$-gram 是否存在。
- 若存在,使用打折后的概率(如 Good-Turing 打折)。
- 若不存在,回退到 $n-1$-gram,并乘以回退系数。
(4)插值平滑(Jelinek-Mercer Smoothing)
思想:线性组合不同阶的 N-gram 概率。
公式:
$$ P_{interp}(w_i | h) = \lambda_n P_n(w_i|h) + \lambda_{n-1} P_{n-1}(w_i|h) + … + \lambda_1 P_1(w_i) $$
其中 $λ$ 为权重参数,满足 $Σλ = 1$。
(5)Witten-Bell Smoothing
思想:根据当前上下文中新词出现的频率来决定是否回退。如果当前上下文中出现过新词,说明需要更多关注低阶信息。
特点:自适应性强,无需额外参数估计。
(6)Kneser-Ney Smoothing (KN)
思想:不仅考虑词频,还考虑词在不同上下文中的多样性(接续概率)。如果一个词出现在多种不同的上下文中,它作为后续词的可能性更高。
接续概率:
$$ P_{cont}(w) = \frac{\text{count}(\cdot, w)}{\sum_{w'} \text{count}(\cdot, w')} $$
目前 KN 平滑是 N-gram 语言模型中最主流的方法,尤其在大规模语料下表现优异。
4. 困惑度与评估指标
困惑度(Perplexity, PPL)
困惑度是衡量语言模型性能的核心指标。其基本思想是:给测试集句子赋予较高概率的模型较好,对应的困惑度较低。
公式:
$$ PPL(W) = P(w_1, …, w_N)^{-1/N} = 2^{-H(p)} $$
其中 $H(p)$ 为交叉熵。
理解:困惑度相当于一个虚拟词典的大小。值越小,说明模型对下一个词的选择越确定,训练效果越好。
相关概念
- 熵(Entropy):描述随机变量的不确定性。熵越大,不确定性越大。
- 相对熵(KL Divergence):衡量两个概率分布的差异。
- 交叉熵(Cross Entropy):衡量估计模型与真实分布之间的差异。困惑度本质上是交叉熵的指数形式。
5. 语言模型搭建流程
构建一个完整的 N-gram 语言模型通常包含以下步骤:
- 语料预处理:分词、清洗、统一大小写。
- 词频统计:统计 N-gram 的出现次数。
- 模型训练:应用平滑算法计算概率。
- 模型保存:导出为二进制或文本格式供解码器加载。
- 测试评估:在测试集上计算困惑度。
代码实现逻辑示例
以下伪代码展示了 N-gram 计数的核心逻辑:
def count_ngrams(corpus, n):
counts = defaultdict(int)
for sentence in corpus:
tokens = ['<s>'] * (n-1) + sentence.split() + ['</s>']
for i in range(len(tokens) - n + 1):
context = tuple(tokens[i:i+n-1])
word = tokens[i+n-1]
counts[(context, word)] += 1
return counts
6. SRILM 工具包使用
SRILM (Speech Recognition Language Modeling Toolkit) 是业界广泛使用的语言模型工具包,支持高效的 N-gram 训练与评估。
词频统计
使用 ngram-count 命令进行统计:
ngram-count -text train.txt -order 3 -write train.count
参数说明:
-text: 输入语料文件。
-order: N-gram 阶数。
-write: 输出计数文件。
模型训练
使用平滑算法训练模型:
ngram-count -text train.txt -order 3 -discount kneser_ney -lm lm.kn.bin
ngram-count -text train.txt -order 3 -discount witten_bell -lm lm.wb.bin
模型评估
计算测试集的困惑度:
ngram-test -lm lm.kn.bin -text test.txt -ppl
模型剪枝
为了减小模型体积,可以使用剪枝功能删除低频 N-gram:
ngram-prune -lm lm.full.bin -threshold 0.0001 -write lm.pruned.bin
剪枝策略是在保证 PPL 增加不超过阈值的前提下,尽可能减少模型大小。
7. 总结与工程实践
N-gram 与 RNN 的对比
虽然 RNN 及 Transformer 类模型能捕捉更长距离的依赖关系,但在传统语音识别解码阶段,N-gram 仍占据重要地位。原因如下:
- 效率:N-gram 可编译为加权有限状态转换器(WFST),解码过程转化为图搜索,速度极快。
- 确定性:N-gram 概率计算是确定的,便于调试和优化。
- 二次解码:RNN 模型常作为重排序(Rescore)模块,在 N-gram 初步解码后提升精度。
工程建议
- 语料规模:平滑算法的效果高度依赖语料规模,小语料建议使用 Witten-Bell 或 Add-one,大语料推荐 Kneser-Ney。
- OOV 处理:建立通用 OOV 标记,结合子词(Subword)技术可有效缓解未登录词问题。
- 混合模型:现代系统常采用 N-gram 与神经语言模型(NLM)混合的方式,兼顾速度与精度。
通过合理选择平滑算法与工具链,可以构建出高效、准确的语言模型,显著提升语音识别系统的整体性能。