0%

nlp自学2-二元语法与中文分词

上一篇主要讨论了词典分词。词典分词可以解决“字符串能否成词”的问题,但无法很好处理切分歧义。例如“研究生命起源”既可以切成“研究 / 生命 / 起源”,也可以切成“研究生 / 命 / 起源”。两条路径可能都能在词典中找到对应词语,因此还需要一个标准来判断哪一种切分更合理。

二元语法模型(Bigram Language Model)正是这种标准中最基础的一种。它利用相邻两个词的共现概率,对候选切分路径进行打分。

问题定义

设一句话对应的分词结果为:

W = w1, w2, ..., wn

理想情况下,我们希望选择概率最大的那条切分路径:

W* = arg max P(W)

其中 P(W) 表示该词序列作为自然语言出现的概率。

但直接估计:

P(w1, w2, ..., wn)

几乎不可行,因为词序列空间过大,语料中很难覆盖所有组合。因此需要对联合概率进行近似建模。

马尔可夫假设与二元语法

由链式法则可得:

P(w1, w2, ..., wn) = P(w1) P(w2|w1) P(w3|w1,w2) ... P(wn|w1,...,wn-1)

若采用一阶马尔可夫假设,即认为当前词只依赖于前一个词,则有:

P(wi|w1,...,wi-1) ≈ P(wi|wi-1)

于是整句概率近似为:

P(W) ≈ P(w1) ∏(i=2..n) P(wi|wi-1)

这就是二元语法模型。它的核心在于估计条件概率 P(wi|wi-1)

参数估计

设:

  • C(wi-1, wi) 表示二元词对 (wi-1, wi) 在语料中的出现次数
  • C(wi-1) 表示词 wi-1 在语料中的出现次数

则最大似然估计为:

P(wi|wi-1) = C(wi-1, wi) / C(wi-1)

句首词的概率可以写为:

P(w1) = C(w1) / N

其中 N 为语料中的总词数,或者也可以显式加入句子起始标记 <BOS>,把首词概率改写为:

P(w1|<BOS>)

在实现中,加入 <BOS><EOS> 往往更统一,也更方便写动态规划。

为什么二元语法适合中文分词

中文分词的本质,是在一个句子对应的多条候选切分路径中找到最优路径。词典告诉我们“哪些片段可能是词”,二元语法告诉我们“哪些词连接在一起更自然”。

例如句子:

南京市长江大桥

候选切分可以写成:

  1. 南京市 / 长江大桥
  2. 南京 / 市长 / 江大桥

若单看词典,第二条路径未必在形式上完全非法;但从统计语言模型角度看:

P(长江大桥|南京市)

通常远大于:

P(市长|南京) * P(江大桥|市长)

因此第一条路径会获得更高得分。

分词中的打分函数

在中文分词任务中,我们最终想求的是:

W* = arg max [P(w1) ∏(i=2..n) P(wi|wi-1)]

由于多个小概率连乘容易造成数值下溢,实际中通常取对数:

W* = arg max [log P(w1) + Σ(i=2..n) log P(wi|wi-1)]

等价地,也可以写成最小化负对数形式:

W* = arg min [-log P(w1) - Σ(i=2..n) log P(wi|wi-1)]

这样一来,中文分词就转化成了一个路径搜索问题:

  1. 节点表示候选词
  2. 边表示相邻词之间的转移
  3. 边权由 -log P(wi|wi-1) 给出
  4. 最终寻找总代价最小的路径

这个过程可以结合 DAG、动态规划或 Viterbi 算法来完成。

一个简单例题

考虑句子:

商品和服务

假设词典给出的两条候选路径为:

  1. 商品 / 和 / 服务
  2. 商 / 品和 / 服务

进一步假设语料统计如下:

  • C(商品) = 100
  • C(和) = 200
  • C(服务) = 150
  • C(商品, 和) = 80
  • C(和, 服务) = 120
  • C(商, 品和) = 1
  • C(品和, 服务) = 0

则有:

P(和|商品) = 80 / 100 = 0.8

P(服务|和) = 120 / 200 = 0.6

于是路径 1 的条件概率部分约为:

0.8 * 0.6 = 0.48

而路径 2 中,由于:

P(服务|品和) = 0

所以整条路径概率直接变为 0。可见二元语法会明显偏向第一种更自然的切分结果。

平滑

上述估计有一个经典问题:数据稀疏。若某个二元词对没有在训练语料中出现,则最大似然估计给出的概率为 0:

P(wi|wi-1) = 0

这会导致只要路径中有一条未见过的转移,整条路径概率就归零。为了缓解这个问题,需要做平滑。

最简单的方式是加一平滑:

P(wi|wi-1) = (C(wi-1, wi) + 1) / (C(wi-1) + |V|)

其中 |V| 表示词表大小。

虽然加一平滑并不是最优方法,但在课程练习或入门实现里,它足够直观。更常见、效果更好的方法还包括:

  1. Good-Turing
  2. Katz Backoff
  3. Kneser-Ney

与词典分词的结合

在工程实现中,二元语法通常不会单独工作,而是和词典匹配一起使用。一个典型流程如下:

  1. 使用词典或 Trie 枚举所有可能词语
  2. 构建句子的候选词图
  3. 用二元语法为相邻候选词赋予转移概率
  4. 使用动态规划寻找最优路径

因此可以把整个分词器理解为两层:

  1. 词典层负责“召回候选词”
  2. 语言模型层负责“排序候选路径”

上一篇偏重第一层,这一篇偏重第二层。

局限性

二元语法模型虽然简单有效,但它有明显的表达上限。

  1. 只考虑前一个词,无法建模更长距离的依赖
  2. 对语料规模较敏感,小语料下统计不稳定
  3. 对未登录词仍然不够友好

例如有些歧义需要结合更长上下文才能解决,这时二元语法往往不够,需要进一步引入:

  1. 三元语法
  2. HMM
  3. CRF
  4. 神经网络语言模型

小结

二元语法的核心思想可以概括为一句话:用相邻词的共现概率来近似刻画整条分词路径的合理性。

其基本公式为:

P(W) ≈ P(w1) ∏(i=2..n) P(wi|wi-1)

在中文分词中,我们并不是单纯判断“某个片段是不是词”,而是在所有候选切分路径中寻找概率最大的那一条。因此,二元语法实际上把中文分词从“字符串匹配问题”推进成了“统计建模 + 路径搜索问题”。

继续往后学习时,一个自然的问题就是:如何把二元语法与 Viterbi 解码结合,真正实现一个可运行的统计分词器。