N-gram语言模型 -- 潘登同学的NLP学习笔记
语言模型
语言模型通俗的将就是判断一句话是不是正常人说出来的。统计语言模型是所有 NLP的基础,被广泛应用与语音识别、机器翻译、分词、词性标注和信息检索等任务。传统的统计语言模型是表示语言基本单位(一般为句子)的概率分布函数,这个概率分布也是该语言的生成模型。通俗的讲,如果一句话没有在语料库中出现,可以模拟句子的生成的方式,生成句子在语料库中的概率。一般语言模型可以使用各个词语条件概率的形式表示: $$ p(w_1^n) = p(w_1,w_2,\ldots,w_n) = \prod_{i=1}^n p(w_i|Context) $$ 其中,Context 为 w_i 的上下文表示。根据 Context 的表示差异,统计语言模型又可以分为不同的类别,其中最具代表性的有 n-gram 语言模型及 nn 语言模型
N-gram
通常在 NLP 中,人们基于一定的语料库,可以利用 N-gram 来做以下几类事情:
- 预计或者评估一个句子是否合理;
- 评估两个字符串之间的差异程度,这也是模糊匹配中常用的一种手段;
- 语音识别;
- 机器翻译;
- 文本分类。
概率模型
统计语言模型实际上是一个概率模型,所以常见的概率模型都可以用于求解这些参数常见的概率模型有:N-gram 模型、决策树、最大熵模型、隐马尔可夫模型、条件随机场、神经网络等
目前常用于语言模型的是 N-gram 模型和神经语言模型
概率模型的缺陷: 观察如下句子 我-今天-要-去-学NLP
将其表示为概率模型
$$
p(S) = p(w_1,w_2,\ldots,w_n) = p(w_1)p(w_2|w_1)p(w_3|w_1,w_2)\ldots p(w_n|w_1,\ldots,w_{n-1})
$$
而条件概率
$$
p(w_i|w_1,w_2,\ldots,w_{i-1}) = \frac{p(w_1,w_2,\ldots,w_i)}{p(w_1,w_2,\ldots,w_{i-1})}
$$
由于要计算 $w_i$ 出现的概率,就要去统计前 $i-1$ 词出现的情况,假设词库中有 $n$ 个词,就有
$n^(i-1)$种可能,这样每增加一个单词,模型的计算成本都指数倍的增长。
总的来说,概率模型的缺陷就是
- 数据过于稀疏(如果语料库(文章资料)过少,或者词表过大(词的种类过多),就会导致稀疏)
- 参数空间太大
为了减少计算成本, 增加了马尔科夫假设
马尔科夫假设
基于马尔可夫假设,N-gram 语言模型认为一个词出现的概率只与它前面的 n-1 个词相关,假设下一个词的出现依赖它前面的一个词: $$ p(S) = p(w_1,w_2,\ldots,w_n) = p(w_1)p(w_2|w_1)p(w_3|w_2)\ldots p(w_n|w_{n-1}) $$
通常情况下,我们管这样的叫 n-gram 模型
- 当 N=1 的时候,为一元模型(Unigram model): $$ P(S)=P(w_1,w_2,w_3,..,w_n)=P(w_1)P(w_2)...*P(w_n) $$
- 当 N=2 的时候,叫二元模型(Bigram model)(常见的): $$ P(S)=P(w_1,w_2,w_3,..,w_n)=P(w_1|start)P(w_2|w_1)...*P(w_n|w_{n-1}) $$
- 当 N=3 的时候,叫三元模型(trigram model): $$ P(S)=P(w_1,w_2,w_3,..,w_n)=P(w_2|start,w_1)P(w_3|w_1,w_2)...*P(w_n|w_{n-1},w_{n-2}) $$
选取N的艺术
- 更大的 n:对下一个词出现的约束信息更多,具有更大的辨别力;(更准)
- 更小的 n:在训练语料库中出现的次数更多,具有更可靠的统计信息,具有更高的可靠性。
理论上,n 越大越好,但在经验上看,trigram 用的最多,尽管如此,原则上,能用 bigram 解决,绝不使用 trigram。
- 问题: 假设没有计算和存储限制,n 是不是越大越好?
早期因为计算性能的限制,一般最大取到 n=4;如今,即使 n>10 也没有问题,但是,随着 n 的增大,模型的性能增大却不显著,这里涉及了可靠性与可区别性的问题参数越多,模型的可区别性越好,但是可靠性却在下降——因为语料的规模是有限的,导致 count(W) 的实例数量不够,从而降低了可靠性
举例说明
一元单词分布表
词 i want to eat chinese food lunch spend 频率 2533 927 2417 746 158 1093 341 278 二元单词分布表
词 i want to eat chinese food lunch spend i 5 827 0 9 0 0 0 2 want 2 0 608 1 6 6 5 1 to 2 0 4 686 2 0 6 211 eat 0 0 2 0 16 2 42 0 chinese 1 0 0 0 0 82 1 0 food 15 0 15 0 1 4 0 0 lunch 2 0 0 0 0 1 0 0 spend 1 0 1 0 0 0 0 0 第一行、第二列表示给定前一个词为
i
的时候,当前词的want
的情况一共出现了827次进而可以得出频率分布表
以i want
为例,其频率值为$p(want|i) = \frac{n(i,want)}{n(i)} = \frac{827}{2533} = 0.3265$, 以频率作为概率那么进而也能得到一句话的概率,以I want chinese food
为例
$$
P(I\quad want\quad chinese\quad food) = P(want|I)P(chinese|want)P(food|chinese)
$$
观察上表,出现了很多零,这就是稀疏问题,当一句话中,包含了其中为0的一个条件概率,那么连乘的结果就为0
OOV 问题
OOV 即 Out Of Vocabulary,也就是序列中出现了词表外词,或称为未登录词或者说在测试集和验证集上出现了训练集中没有过的词
一般解决方案:
- 设置一个词频阈值,只有高于该阈值的词才会加入词表
- 所有低于阈值的词替换为 UNK(一个特殊符号) 无论是统计语言模型还是神经语言模型都是类似的处理方式
平滑处理
- 问题: count(W) = 0 是怎么办? 平滑方法(除了这个之外还有很多):
- Add-one Smoothing (Laplace) (在二元单词)分布表中给0的加1
总结
该语言模型只看当前词的前 n-1 个词对当前词的影响。所有该模型的优势为:
- 该模型包含了前 n-1 个词所能提供的全部信息,这些词对当前词的出现具有很强的约束能;
- 只看前 n-1 个词而非所有词,所以使得模型的效率较高。
该模型也有很多缺陷:
- n-gram 语言模型无法建模更远的关系,语料的不足使得无法训练更高阶的语言模型(通常n=2 或 3)
- 该模型无法建模出词与词之间的相似度,比如“白色汽车”和“白色轿车”;
- 训练语料中有些 n 元组没有出现过,其对应的条件概率为 0,导致计算一整句话的概率为 0!
NPLM(Neural Probabilistic Language Model)
NPLM说的是: 只要你给我一个词,给我上下文,我就能计算出这个词在给定上下文下的条件概率 $$ P(w|context(w)) = g(i_w,V_{context}) $$
- 其中g表示神经网络,$i_w$表示$w$在词表中的序号,$context(w)$为$w$的上下文
- $V_{context}$为上下文构成的特征向量(一个词是一个向量,一段上下文就是一个更长的向量)
N-gram 神经语言模型
这是一个经典的神经概率语言模型,它沿用了 N-gram 模型中的思路,将 $w$ 的前 $n-1$ 个 词作为 $w$ 的上下文 $context(w)$,而 $V_{context}$ 由这 $n-1$ 个词的词向量拼接而成,即 $$ P(w_k|w_{k-n-1}^{k-1}) = g(i_{w_k},[C(w_{k-n+1}),\ldots,C(w_{k-1})]) $$
- 其中 $c(w)$ 表示 $w$ 的词向量
- 不同的神经语言模型中 $context(w)$ 可能不同,比如 Word2Vec 中的 CBOW 模型
- 每个训练样本是形如 $(context(w), w)$ 的二元对,其中 $context(w)$ 取 $w$ 的前 $n-1$个词;当不足 $n-1$,用特殊符号填充
- 同一个网络只能训练特定的 $N$,不同的 $N$ 需要训练不同的神经网络
网络结构
其中$m,n,h$为超参数,视训练集规模而定,也可以人为设置阈值
相比 N-gram 模型,NPLM 的优势
单词之间的相似性可以通过词向量来体现
- S1=“我 今天 去 网咖” 出现了 1000 次
- S2=“我 今天 去 网吧” 出现了 10 次 对于 N-gram 模型:$P(S1)>>P(S2)$ 而神经网络模型计算的 $P(S1)≈P(S2)$
词向量
- One-hot representation:对应位置数字取 1,其他位置全为 0
$$ \begin{pmatrix} the \ cat \ sat \ on \ the \ mat \ \end{pmatrix} = \begin{pmatrix} 1 & 0 & 0 & 0 & 0 \ 0 & 1 & 0 & 0 & 0 \ 0 & 0 & 1 & 0 & 0 \ 0 & 0 & 0 & 1 & 0 \ 1 & 0 & 0 & 0 & 0 \ 0 & 0 & 0 & 0 & 1 \ \end{pmatrix} $$
计算机是无法直接处理文本信息的,所以,在我们构建神经网络之前,要对文本进行一定的处理。
虽然one-hot编码可以构建词向量,但是表示文本的矩阵会非常的稀疏,极大得浪费了空间,而且这样一个矩阵放入神经网络训练也会耗费相当多的时间(而且还可能不收敛)。
为此,提出了词向量模型(Word2Vec)。词向量模型是一种将词的语义映射到向量空间的技术,说白了就是用向量来表示词,但是会比用独热编码用的空间小,而且词与词之间可以通过计算余弦相似度来看两个词的语义是否相近,显然 King 和 Man 两个单词语义更加接近,而且通过实验我们知道 King-Man+Woman=Queen
Distributed representation:通过训练将每一个词都映射为一个 K 维的浮点数向量
Word2Vec
CBOW模型(Continuous Bag-of-Words Model)
而W矩阵也叫做look up table(因为第k单词的词向量就是W矩阵第k行的向量),用one hot的词向量与W相乘得到稠密的词向量通常称为Word embedding
注意
这里的hidden layer只是像隐藏层,但是不是真正的隐藏层,因为没有激活函数
Continuous Bag-of-Word Model(连续词袋模型)和 skip-gram model(跳字模型),分别对应了词向量的两种训练方法:利用 context 预测中心词以及利用中心词去预测context。对于连续词袋模型(CBOW)来说,一般的做法是先对每个单词进行 one-of-N编码(one-hot encoded),作为训练网络的输入,接着构建一层 hidden layer,最后构建输出层,这一层是一个 softmax 层,每个 context 单词到中心单词的事件都被认为是独立的,所以将这些事件发生的概率相乘(似然函数) ,最后构建损失函数,即:将输出概率分布和实际选中的词概率分布进行 Corss Entropy 计算,接下来使用 SGD 对参数进行更新。这里,hidden layer 的训练结果就是最终的 word vector 了。
Skip-gram
根据当前这个词来预测上下文:
Skip-gram 的具体训练过程如下,蓝色代表输入的词,图的框框代表滑动窗口,用来截取蓝色词的上下文,蓝色词的上下文作为输出,然后形成训练标本(Training Samples),这样我们就得到了{输入和输出},将他们放入{输入层-隐藏层-输出层}的神经网络训练,我们就能得到 Skip-gram 模型。因为神经网络不能直接处理文本,因此所有的词都用 one-hot encode 表示。
但输出层并不是我们关心的,我们去掉模型的输出层,才是我们想要的词向量模型,我们通过隐藏层的权重来表示我们的词。
两种模型的两种训练方式
因为最终分类的时候只用Softmax,万一有10万个词,那么要计算的参数就会特别多,Hierarchical Softmax与Negative Sampling就是优化softmax层参数计算量过多的方法
哈夫曼树
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树
- 构造流程
- 将softmax转成哈夫曼树
二叉树每一个分裂都是一个条件判断,相当于二分类,sigmoid 函数来判断走左边还是右边
分层Softmax
分层Softmax是由二分类sigmoid组成的类似决策树多分类模型
这样做的好处就是,原本做softmax要用$N$组$\theta$($N$是词库的单词量,$\theta$长度为$M$),而这里只需要用$\log N$组$\theta$即可得到最终的目标(正向传播时,反向传播也类似)
其对数似然及反向传播推导如下
Skip-gram 模型与 CBOW 模型的推导过程大同小异,对于层次 SoftMax 的 skip-gram 模型,已知的是当前词 w,需要对其上下文 Context(w)中的词进行预测,故,其目标函数为:
因为要预测的是一个上下文,所以似然中多了一个加和符号,表示的是C个上下文
负采样
Negative sampling(NEG)可以视为对层次 SoftMax 的一种代替,它不再使用(复杂的)Huffman 树,而是利用(相对简单的)随机负采样,其目的也是用来提高训练速度并改善所得词向量的质量
通常的softmax往往得出的是一个正例与$N-1$个负例,而NEG采用的方法为选择一个正例,加上$k$个负例(论文中是5,小样本5-20,大样本2-5)。 然后在更新$w'$矩阵的时候只需要更新$k+1$组$\theta$即可。 (因为在随机选择了$k$个负例,而不是所有负例,如果仍然使用softmax,那么加和的结果就不是1,所以这里的激活函数是sigmoid)
Word2vec 采用带权采样法:词典 D 中的词在语料 C 中出现的次数有高有底,对于那些高频词,被选为负样本的概率就应该比较大,而低频词出现的概率应该比较小。Word2vec源码中使用下面的公式设置每个词的权重: $$ Weight(w) = \frac{counter(w)^0.75}{\sum_{w\in D}counter(w)^0.75} $$
在 CBOW 模型中,已知词 w 的上下文 Context(w),需要预测 w,因此,对于给定的上下文 Context(w),词 w 就是一个正样本,其他的词就是负样本。负样本太多了,因此我们一般通过上述方法选取适量的负样本,记为$NEG(w)$