作者:chen_h
微信号 & QQ:862251340
微信公众号:coderpai
(一)ngram 模型
N-gram 模型是一种语言模型(Language Model,LM),语言模型是一个基于概率的判别模型,它的输入是一句话(单词的顺序序列),输出是这句话的概率,即这些单词的联合概率(joint probability)。
N-gram 本身也指一个由N个单词组成的集合,各单词具有先后顺序,且不要求单词之间互不相同。常用的有 Bi-gram (N=2) 和 Tri-gram (N=3),一般已经够用了。例如有一句话 ”I love deep learning“ 在这句话里,我可以分解的 Bi-gram 和 Tri-gram :
Bi-gram : {I, love}, {love, deep}, {love, deep}, {deep, learning}
Tri-gram : {I, love, deep}, {love, deep, learning}
Ngram 中的概率计算
假设我们有一个由 n 个词组成的句子 S = ( w 1 , w 2 , . . . , w n ) S=(w_1, w_2, ..., w_n) S=(w1,w2,...,wn) ,那么如何衡量它的概率呢?让我们假设,每一个单词 w i w_i wi 都要依赖于从第一个单词 w 1 w_1 w1 到它之前一个单词 w i − 1 w_{i-1} wi−1 的影响:
p ( S ) = p ( w 1 , w 2 , . . . , w n ) = p ( w 1 ) p ( w 2 ∣ w 1 ) . . . p ( w n ∣ w n − 1 . . . w 2 w 1 ) p(S)=p(w_1,w_2,...,w_n)=p(w_1)p(w_2|w_1)...p(w_n|w_{n-1}...w_2w_1) p(S)=p(w1,w2,...,wn)=p(w1)p(w2∣w1)...p(wn∣wn−1...w2w1)
是不是非常季丹丹?但是,这个衡量方法有两个致命缺陷:
- 参数控件过大,概率 p ( w n ∣ w n − 1 . . . w 2 w 1 ) p(w_n|w_{n-1}...w_2w_1) p(wn∣wn−1...w2w1) 的参数有 O ( n ) O(n) O(n) 个。
- 数据稀疏严重,词同时出现的情况可能没有,组合劫数高时尤其明显。
为了解决第一个问题,我们引入马尔科夫假设(Markov Assumption):一个词的出现仅与它之前的若干个词有关。
p
(
w
1
⋯
w
n
)
=
∏
p
(
w
i
∣
w
i
−
1
⋯
w
1
)
≈
∏
p
(
w
i
∣
w
i
−
1
⋯
w
i
−
N
+
1
)
p\left(w_{1} \cdots w_{n}\right)=\prod p\left(w_{i} | w_{i-1} \cdots w_{1}\right) \approx \prod p\left(w_{i} | w_{i-1} \cdots w_{i-N+1}\right)
p(w1⋯wn)=∏p(wi∣wi−1⋯w1)≈∏p(wi∣wi−1⋯wi−N+1)
- 如果一个词的出现仅依赖于它前面出现的一个词,那么我们就称之为 Bi-gram:
p ( S ) = p ( w 1 w 2 ⋯ w n ) = p ( w 1 ) p ( w 2 ∣ w 1 ) ⋯ p ( w n ∣ w n − 1 ) p(S)=p\left(w_{1} w_{2} \cdots w_{n}\right)=p\left(w_{1}\right) p\left(w_{2} | w_{1}\right) \cdots p\left(w_{n} | w_{n-1}\right) p(S)=p(w1w2⋯wn)=p(w1)p(w2∣w1)⋯p(wn∣wn−1)
- 如果一个词的出现仅依赖于它前面出现的两个词,那么我们就称之为 Tri-gram:
p ( S ) = p ( w 1 w 2 ⋯ w n ) = p ( w 1 ) p ( w 2 ∣ w 1 ) ⋯ p ( w n ∣ w n − 1 w n − 2 ) p(S)=p\left(w_{1} w_{2} \cdots w_{n}\right)=p\left(w_{1}\right) p\left(w_{2} | w_{1}\right) \cdots p\left(w_{n} | w_{n-1} w_{n-2}\right) p(S)=p(w1w2⋯wn)=p(w1)p(w2∣w1)⋯p(wn∣wn−1wn−2)
N-gram的 N 可以取很高,然而现实中一般 bi-gram 和 tri-gram 就够用了。
那么,如何计算其中的每一项条件概率
p
(
w
n
∣
w
n
−
1
⋅
⋅
w
2
w
1
)
p\left(w_{n} | w_{n-1} \cdot \cdot w_{2} w_{1}\right)
p(wn∣wn−1⋅⋅w2w1) 呢?答案是极大似然估计,说人话就是数频率:
p
(
w
n
∣
w
n
−
1
)
=
C
(
w
n
−
1
w
n
)
C
(
w
n
−
1
)
p\left(w_{n} | w_{n-1}\right)=\frac{C\left(w_{n-1} w_{n}\right)}{C\left(w_{n-1}\right)}
p(wn∣wn−1)=C(wn−1)C(wn−1wn)
p ( w n ∣ w n − 1 w n − 2 ) = C ( w n − 2 w n − 1 w n ) C ( w n − 2 w n − 1 ) p\left(w_{n} | w_{n-1} w_{n-2}\right)=\frac{C\left(w_{n-2} w_{n-1} w_{n}\right)}{C\left(w_{n-2} w_{n-1}\right)} p(wn∣wn−1wn−2)=C(wn−2wn−1)C(wn−2wn−1wn)
p ( w n ∣ w n − 1 ⋅ ⋅ w 2 w 1 ) = C ( w 1 w 2 ⋯ w n ) C ( w 1 w 2 ⋯ w n − 1 ) p\left(w_{n} | w_{n-1} \cdot \cdot w_{2} w_{1}\right)=\frac{C\left(w_{1} w_{2} \cdots w_{n}\right)}{C\left(w_{1} w_{2} \cdots w_{n-1}\right)} p(wn∣wn−1⋅⋅w2w1)=C(w1w2⋯wn−1)C(w1w2⋯wn)
具体地,以Bi-gram为例,我们有这样一个由三句话组成的语料库:
<s>I am Sam<s>
<s>Sam I am<s>
<s>I do not like eggs and ham<s>
容易统计,“I”出现了3次,“I am”出现了2次,因此能计算概率:
p
(
a
m
∣
I
)
=
2
3
p(a m | I)=\frac{2}{3}
p(am∣I)=32
同理,还能计算出如下概率:
p
(
I
∣
<
s
>
)
=
0.67
p
(
Samlam
)
=
0.5
p
(
<
s
>
∣
S
a
m
)
=
0.5
p
(
d
o
∣
I
)
=
0.33
p
(
not
∣
d
o
)
=
1
p
(
like
∣
not
)
=
1
\begin{array}{rlrl}{p(I |<s>)=0.67} & {p(\text {Samlam})=0.5} & {p(<s>| S a m)} & {=0.5} \\{p(d o | I)=0.33} & {p(\text {not} | d o)=1} & {p(\text {like} | \text {not})=1}\end{array}
p(I∣<s>)=0.67p(do∣I)=0.33p(Samlam)=0.5p(not∣do)=1p(<s>∣Sam)p(like∣not)=1=0.5
N-gram中N的确定
为了确定N的取值,《Language Modeling with Ngrams》使用了 Perplexity 这一指标,该指标越小表示一个语言模型的效果越好。文章使用了华尔街日报的数据库,该数据库的字典大小为19,979,训练集包含 38 million 个词,测试集包含 1.5 million 个词。针对不同的N-gram,计算各自的 Perplexity。
P P ( W ) = 1 P ( w 1 w 2 ⋯ w n ) n = ∏ i = 1 n 1 p ( w i ∣ w i − 1 ⋯ w 1 ) n P P(W)=\sqrt[n]{\frac{1}{P\left(w_{1} w_{2} \cdots w_{n}\right)}}=\sqrt[n]{\prod_{i=1}^{n} \frac{1}{p\left(w_{i} | w_{i-1} \cdots w_{1}\right)}} PP(W)=nP(w1w2⋯wn)1=ni=1∏np(wi∣wi−1⋯w1)1
结果显示,Tri-gram的Perplexity最小,因此它的效果是最好的。
那么N 越大是否越好呢?
N-gram中的数据平滑方法
上面提到,N-gram的N越大,模型 Perplexity 越小,表示模型效果越好。这在直观意义上是说得通的,毕竟依赖的词越多,我们获得的信息量越多,对未来的预测就越准确。然而,语言是有极强的创造性的(Creative),当N变大时,更容易出现这样的状况:某些n-gram从未出现过,这就是稀疏问题。
n-gram最大的问题就是稀疏问题(Sparsity)。例如,在bi-gram中,若词库中有20k个词,那么两两组合
(
C
20
k
2
)
\left(C_{20 k}^{2}\right)
(C20k2)就有近2亿个组合。其中的很多组合在语料库中都没有出现,根据极大似然估计得到的组合概率将会是0,从而整个句子的概率就会为0。最后的结果是,我们的模型只能计算零星的几个句子的概率,而大部分的句子算得的概率是0,这显然是不合理的。
因此,我们要进行数据平滑(data Smoothing),数据平滑的目的有两个:一个是使所有的N-gram概率之和为1,使所有的n-gram概率都不为0。它的本质,是重新分配整个概率空间,使已经出现过的n-gram的概率降低,补充给未曾出现过的n-gram。
拉普拉斯平滑
Add-one
拉普拉斯平滑,即强制让所有的n-gram至少出现一次,只需要在分子和分母上分别做加法即可。这个方法的弊端是,大部分n-gram都是没有出现过的,很容易为他们分配过多的概率空间。
p
(
w
n
∣
w
n
−
1
)
=
C
(
w
n
−
1
w
n
)
+
1
C
(
w
n
−
1
)
+
∣
V
∣
p\left(w_{n} | w_{n-1}\right)=\frac{C\left(w_{n-1} w_{n}\right)+1}{C\left(w_{n-1}\right)+|V|}
p(wn∣wn−1)=C(wn−1)+∣V∣C(wn−1wn)+1
Add-K
在Add-one的基础上做了一点小改动,原本是加一,现在加上一个小于1的常数KKK。但是缺点是这个常数仍然需要人工确定,对于不同的语料库KKK可能不同。
p
(
w
n
∣
w
n
−
1
)
=
C
(
w
n
−
1
w
n
)
+
k
C
(
w
n
−
1
)
+
k
∣
V
∣
p\left(w_{n} | w_{n-1}\right)=\frac{C\left(w_{n-1} w_{n}\right)+k}{C\left(w_{n-1}\right)+k|V|}
p(wn∣wn−1)=C(wn−1)+k∣V∣C(wn−1wn)+k
内插与回溯
内插
内插法(Interpolation) 有点像滑动平均,它的核心思想是,既然高阶组合可能出现次数为0,那稍微低阶一点的组合总有不为0的。如下事一个三阶组合,假设
p
(
w
n
∣
w
n
−
1
w
n
−
2
)
=
0
p\left(w_{n} | w_{n-1} w_{n-2}\right)=0
p(wn∣wn−1wn−2)=0 而
p
(
w
n
∣
w
n
−
1
)
p\left(w_{n} | w_{n-1}\right)
p(wn∣wn−1) 且
p
(
w
n
)
>
0
p\left(w_{n}\right)>0
p(wn)>0 ,则加权平均值后的概率不为0,从而达到平滑的效果。
p
^
(
w
n
∣
w
n
−
1
w
n
−
2
)
=
λ
3
p
(
w
n
∣
w
n
−
1
w
n
−
2
)
+
λ
2
p
(
w
n
∣
w
n
−
1
)
+
λ
1
p
(
w
n
)
\hat{p}\left(w_{n} | w_{n-1} w_{n-2}\right)=\lambda_{3} p\left(w_{n} | w_{n-1} w_{n-2}\right)+\lambda_{2} p\left(w_{n} | w_{n-1}\right)+\lambda_{1} p\left(w_{n}\right)
p^(wn∣wn−1wn−2)=λ3p(wn∣wn−1wn−2)+λ2p(wn∣wn−1)+λ1p(wn)
回溯
回溯法(backoff) 与内插有点像,只是它会尽可能地用最高阶组合计算概率,当高阶组合不存在时,退而求其次找次低阶,直到找到非零组合为止。参考下式,这是一个递归运算。
p
(
w
n
∣
w
n
−
1
⋯
w
n
−
N
+
1
)
=
{
p
∗
(
w
n
∣
w
n
−
1
⋯
w
n
−
N
+
1
)
C
(
w
n
−
1
⋯
w
n
−
N
+
1
)
>
0
α
(
w
n
−
1
⋯
w
n
−
N
+
1
)
p
(
w
n
∣
w
n
−
1
⋯
w
n
−
N
+
2
)
otherwise
p\left(w_{n} | w_{n-1} \cdots w_{n-N+1}\right)=\left\{\begin{array}{ll}{p^{*}\left(w_{n} | w_{n-1} \cdots w_{n-N+1}\right)} & {C\left(w_{n-1} \cdots w_{n-N+1}\right)>0} \\{\alpha\left(w_{n-1} \cdots w_{n-N+1}\right) p\left(w_{n} | w_{n-1} \cdots w_{n-N+2}\right)} & {\text { otherwise }}\end{array}\right.
p(wn∣wn−1⋯wn−N+1)={p∗(wn∣wn−1⋯wn−N+1)α(wn−1⋯wn−N+1)p(wn∣wn−1⋯wn−N+2)C(wn−1⋯wn−N+1)>0 otherwise