easy-algorithm-interview-an.../traditional-algorithm/NLP中的语言模型.md

4.3 KiB
Raw Permalink Blame History

前言

最近一直在处理文本相关的一些内容,涉及到文本分类等工作。正好趁此机会,针对于文本相关的问题记录一个系列的内容,争取将文本处理过程中用到的一些技术做下大致的归纳总结。

1.什么是语言模型

所谓的语言模型,简单来说,就是看一句话到底是不是人话。或者说,语言模型是用来计算一个句子概率的模型,也就是计算一句话是不是人话的概率。

那么如何计算这个句子的概率呢?给定一个句子,假设这个句子的序列为

S = w_1,w_2,\cdots, w_k
那么这个概率给可以表示为:
P(S) = P(w_1, w_2, \cdots, w_k) = p(w_1)p(w_2|w_1)\cdots p(w_k|w_1w_2,\cdots, w_{k-1})

如果直接使用上面的方法,存在两个致命的问题:
1.参数空间过大条件概率P(wn|w1,w2,..,wn-1)的可能性太多,无法估算,不可能有用,就是俗称的维度灾难(curse of dimensionality)。
2.数据稀疏严重对于非常多词对的组合在语料库中都没有出现依据最大似然估计得到的概率将会是0。

2.马尔科夫链(Markov chain)

为了解决參数空间过大的问题。引入了马尔科夫假设随意一个词出现的概率只与它前面出现的有限的一个或者几个词有关。这就是所谓的n-gram模型。

如果一个词的出现于周围的词独自我们称之为unigram即一元语言模型

P(S) = p(w_1)\*p(w_2)\*p(w_3)\cdots*p(w_n)

如果一个词的出现依赖于前面出现的一个词那么我们就称之为bigram:
\begin{aligned} P(S) &= P(w_1,w_2,w_3,\cdots, w_n) \\\\ & = P(w_1)p(w_2|w_1)\cdots p(w_n|w_1w_2,\cdots, w_{n-1}) \\\\ & = P(w_1)p(w_2|w_1) p(w_3|w_2)\cdots p(w_n | w_{n-1}) \end{aligned}

在实践中用的最多的就是bigram和trigram(三元模型)了,高于四元的用的非常少,由于训练它须要更庞大的语料,并且数据稀疏严重,时间复杂度高,精度却提高的不多。

3.如何计算概率

关于n-gram模型基本思路可以总结如下
1.句子可以看成是一系列词组成的。
2.每一种排列情况都能够通过条件概率公式计算得到一个表示这个句子合理性的概率。
3.通过马尔科夫链,减小了计算量。

一般来说N元模型就是假设当前词的出现概率只与它前面的N-1个词有关。而这些概率参数都是可以通过大规模语料库来计算比如三元概率有
P(w_i|w_{i-1}, w_{i-2}) = \frac {count(w_{i-2}w_{i-1}w_i)} {count(w_{i-2}w_{i-1})}

实际中n的取值大小其实是模型精度与计算能力之间的一个平衡。理论上n越大模型越精确越能反应句子的真实情况但是需要的计算量也越大。当n超过4以后模型准确度提升有限但是计算量却大了很多。所以实际中一般使用bigram与trigram最多。

4.平滑

语言模型中需要知道的所有的条件概率,我们称之为模型的参数,从语料中获得这些概率的过程就是模型学习的过程。

从第三部分易知模型训练的过程其实就是语料库中词频的统计计算问题。往往会出现这样的情况两个词同时出现的次数为0那么根据公式应有P(w_i|w_{i-1}) = 0。或者反过来,两个词同时只出现一次,而且w_{i-1}也只出现一次,那么P(w_i|w_{i-1}) = 1。显然这些都是不合理的。

如果某个P(w_i|w_{i-1}) = 0因为概率的整体计算为连乘运算将导致整体结果为0这种情况我们是不希望看到的此时需要进行相应的平滑操作。一般只要是有概率连乘出现的地方我们都需要对其进行平滑。

比如最简单的一种平滑方式:

P(w_i|w_{i-1}, w_{i-2}) = \frac {count(w_{i-2}w_{i-1}w_i) + \lambda} {count(w_{i-2}w_{i-1}) + \lambda V}

其中V表示词库的大小。

5.怎么使用n-gram进行分类

其实很简单了,只要根据每个类别的语料库训练各自的语言模型,也就是频率分布表,实质上就是每一个篇章单元的类别都有一个概率分布,当新来一个篇章单元的时候,只要根据各自的语言模型,计算出每个语言模型下这个篇章单元的发生概率,篇章单元在哪个模型的概率大,这篇文本就属于哪个类别了。