NMT Tutorial 1. 统计语言模型之N元语法

本系列笔记主要来自于以下三篇关于神经机器翻译(NMT)的tutorial:

其它资料可能来自于斯坦福CS224课程、Yoav Goldberg的Neural Network Methods for Natural Language Processing和其它到时列明的课程讲义/书籍

本篇主要来自于Neubig2017,以统计语言模型为主。尽管这些概念/方法在NMT中已不太常用,但是个人感觉仍然有必要了解一下,打好基础

统计机器翻译问题的形式化定义

假设输入句子(源句子)\(F\)是一个序列: \[ F = f_1, \ldots, f_J = f_1^{|F|} \] 输出句子(目标句子)\(E\)也是一个序列: \[ E = e_1, \ldots, e_I = e_1^{|E|} \] 那么任何翻译系统都可以看成是一个函数 \[ \hat{E} = {\rm mt}(F) \] 其接受一个输入\(F\)作为源句子,返回一个假设\(\hat{E}\)作为翻译结果

统计机器翻译(SMT)是通过创建一个概率模型\(P(E|F;\theta)\)来翻译,目的是找到能最大化这个\(P\)的目标句,即得到的\(\hat{E}\)满足 \[ \hat{E} = \mathop{\rm arg\max}_EP(E|F;\theta) \] 其中\(\theta\)是模型参数,指定概率分布。通常机器翻译算法从源语句和目标语句对齐的数据源(称为平行语料)学出参数\(\theta\)。在这个框架下,需要解决三个主要问题

  • 建模问题:模型\(P(E|F;\theta)\)长什么样?有什么参数?如何使参数指定概率分布?
  • 学习问题:采用什么样的学习方法?
  • 搜索问题:如何找到概率最大的句子?搜索最优假设的过程通常也被称为解码

逐词计算概率

在解决翻译问题之前,先看一下如何为目标句创建一个语言模型。语言模型的作用可以大致理解为,对某个给定的单词序列,计算这个序列在语言中出现的概率。对于目标句,就是要创建概率模型\(P(E)\),用它来评估译句的自然度,以及生成文本。形式化地说,就是计算 \[ P(E) = P(|E|=T, e_1^T) \] 即当句子长度\(|E|\)\(T\)时,第一个单词为\(e_1\),第二个单词为\(e_2\)……第\(T\)个单词为\(e_T\)的联合概率。此外,通常会在句末添加一个表达句子结束的符号</s>,因此长度为\(T\)的句子实际长度为\(T+1\),其中\(e_{T+1} = \langle /s \rangle\)。这样,当解码输出</s>时,就可以知道句子该结束了

但是,很难直观得到这个概率值:假设单词表大小为\(V\),句子长度为\(T\),那么一共有\(V^T\)个可能的句子。不过,联合概率可以表示成若干条件概率的连乘。例如,\(P(e_1, e_2, e_3) = P(e_1)P(e_2|e_1)P(e_3|e_1e_2)\)。更一般地说,有 \[ P(E) = \prod_{t=1}^{T+1}P(e_t|e_1^{t-1}) \] 那么,问题转化为,如何在已知前面单词的情况下,有效计算\(P(e_t|e_1^{t-1})\)

基于记数的n元语法

计算该概率的方法比较简单:准备一份训练数据,然后先数出\(e_1, e_2, \ldots, e_t\)的数量,再数出\(e_1, e_2, \ldots, e_{t-1}\)的数量。例如,对句子"you are from Beijing",先数出所有"you are from Beijing"开头的字符串的数量,再数出"you are from"开头的字符串的数量,两者相除,就得到了要求的概率值。形式化地说,为 \[ P_{\rm ML}(e_t|e_1^{t-1}) = \frac{c_{\rm prefix}(e_1^t)}{c_{\rm prefix}(e_1^{t-1})} \] 这里\(c_{\rm prefix}(\cdot)\)是指定字符串在训练数据中句首出现的次数,这种方法称为最大似然法

这种方法的问题是,不是所有句子都能在训练集出现。例如,训练集中可能有很多句"you are from Shanghai"或者"they are from Beijing",但是就是没有"you are from Beijing"。按照上面列出的原始的概率算法,"you are from Beijing"这句话的概率为0——推而广之,语言模型会给每句没有在训练集中出现的句子的概率都给成0,因此不是特别有意义

为了避免这样的问题出现,可以使用一种退而求其次的方法来近似估计某句话在语言里出现的概率,即不再看以某个字符串开头的句子,而是设置一个固定大小的窗口,限定单词上下文(或称为语境)的长度。例如,假设将语境限制为目标单词的前\(n-1\)个单词,那么就有 \[ P(e_t|e_1^{t-1}) \approx P_{\rm ML}(e_t|e_{t-n+1}^{t-1}) \] 这种模型称为n元语法模型。N元语法模型的参数\(\theta\)包含了所有给定\(n-1\)个单词时,出现下一个单词的概率 \[ \theta_{e_{t-n+1}^t} = P(e_t | e_{t-n+1}^{t-1}) \] 为了训练n元模型,可以使用MLE来计算 \[ \theta_{e_{t-n+1}^t} = P_{\rm ML}(e_t | e_{t-n+1}^{t-1}) = \frac{c(e_{t-n+1}^t)}{c(e_{t-n+1}^{t-1})} \] 其中\(c(\cdot)\)是指定字符串在语料中任何位置出现的次数

但是,这里还有一个问题:上面这个式子里,分子\(c(e_{t-n+1}^t)\)可能还会是0,这样,算出来的概率也还是0。为了彻底解决这个问题,n元语法使用了若干种平滑方法(smoothing)。例如,插值法(interpolation)的原理是在找不到n元组时,退而使用n-1元组出现的概率。在最简单的二元语法中,有 \[ P(e_t|e_{t-1}) = (1-\alpha)P_{\rm ML}(e_t|e_{t-1}) + \alpha P_{\rm ML}(e_t) \] 超参数\(\alpha\)越大,一元语法(独立于语境,单词\(e_t\)出现的频率)的比重越大。进一步扩展,n元语法的插值法是递归设置 \[ P(e_t|e_{t-m+1}^{t-1}) = (1-\alpha_m)P_{\rm ML}(e_t|e_{t-m+1}^{t-1}) + \alpha_m P(e_t|e_{t-m+2}^{t-1}) \] 其中,第一项是\(m\)元语言模型的最大似然估计,第二项递归计算了从1元到\(m-1\)元语言模型的插值

在此基础上,还有一些更复杂的平滑技术,例如

  • 上下文相关的平滑系数。上式中给定的\(\alpha_m\)不再是一个常数,而是一个跟上文有关的数\(\alpha_{e_{t-m+1}^{t-1}}\)。这样,可以使\(\alpha\)正比于\(c(e^t_{t-n+1})\)
  • 回退法(backoff)。当高元语法的概率值为0时,再计算低元语法的概率值
  • 修改的分布。计算\(m\)元语言模型的概率值时,不再使用最大似然估计计算\(P_{\rm ML}\),而是使用一些其它的算法。例如折扣法需要将求出的计数值\(c\)再减去一个常数

目前,修改后的Kneser-Ney平滑(Modified Kneser-Ney Smoothing)是一种最常用,最有效的标准平滑算法。关于平滑算法的综述,更详细的介绍可以参见[Chen1996]

语言模型的评估

度量语言模型准确性最直接的方法是计算模型在验证集或测试集上的似然。参数\(\theta\)在某数据上的似然就是模型为该数据所计算出的概率。例如,假设测试集为\(\mathcal{E}_{\rm test}\),则似然就是 \[ P(\mathcal{E}_{\rm test};\theta) \] 通常数据集都包含若干独立的文档或句子\(E\),因此 \[ P(\mathcal{E}_{\rm test};\theta) = \prod_{E\in \mathcal{E}_{\rm test}}P(E;\theta) \] 进一步地,一般是使用对数似然 \[ \log P(\mathcal{E}_{\rm test};\theta) = \sum_{E \in \mathcal{E}_{\rm test}}\log P(E;\theta) \] 由于语言模型对每个句子所计算出的概率一般都非常小,若干很小的概率值相乘以后,很可能出现下溢现象。而如果求对数以后再求和,可以很好地避免这种现象发生。此外,做基于梯度的优化时,加和项的求导比乘积项的求导计算起来方便很多。综上所述,对数似然是一种更好的方法。也可以在求出对数似然以后除以语料库中单词的个数,这样可以比较不同语料库得到的语言模型的效果

最后一种衡量语言模型准确度的方法是困惑度(perplexity, ppl),是每个单词负对数似然的平均值的自然指数 \[ {\rm ppl}(\mathcal{E}_{\rm test};\theta) = e^{-(\log P(\mathcal{E}_{\rm test};\theta)) / {\rm length}(\mathcal{E}_{\rm test})} \] 另一种更常见的写法是 \[ \begin{align*} {\rm ppl} &= e^{-l} \\ l &= \frac{1}{M}\sum_{i=1}^M\log P(s_i) \end{align*} \] 其中\(M\)是测试集语料的长度,\(P(s_i)\)是模型对第\(i\)条语料正确单词给出的概率值

对这个指标,一种直观的解释是“模型在做决定的时候,对这个决定由多犹豫?”,更准确地说,这个值描述的是“如果每次出词的时候都按照语言模型的概率分布随机猜一个词,那么平均每多少个词可以猜到那个正确的词?”

困惑度这种度量方案比较为研究人员所偏爱,因为这种方法做出来的结果比较大,因此不同模型之间的差别体现得更加直观(所以提高了论文投中的概率[手动滑稽])

处理未知词

测试集里出现的单词可能在训练集里没有出现过,这种词一般称为未知词(简称UNK),需要做进一步处理。语言模型常见的处理方法包括

  • 假设词表就是封闭的,即就假设测试集里出现的单词也一定会在训练集出现

  • 对UNK设置一个分布,然后求插值。即认为UNK实际上是“零元语法”,在算一元语法时计算 \[ P(e_t) = (1-\alpha_1)P_{\rm ML}(e_t) + \alpha_1P_{\rm unk}(e_t) \] 这里,\(P_{\rm unk}\)这个分布要为所有单词\(V_{\rm all}\)都能算出一个概率,而不只是对训练语料看到的词表\(V\)计算概率。分布的求法有两种,一种是再训练一个基于字符的语言模型,这样它可以“拼出”UNK;另一种是猜测\(|V_{\rm all}|\)(也就是全词表的大小,要求\(|V_{\rm all}| > |V|\)),然后定义\(P_{\rm unk}(e_t) = 1/|V_{\rm all}|\)

  • 将训练集中的某些词替换为<unk>。通常可以把那些只出现了一次的词替换为<unk>,这样还可以预测出在什么语境下会看到未知词

N元语法的扩展

关于N元语法更详细的描述,可以参考[Goodman2001]。其它一些扩展的研究方向包括

  • 大规模语言模型,可以参考CMU 11-711 "Algorithms for NLP" Language Modeling 部分的课件和扩展阅读
  • 专门领域的语言模型,例如[Bellegarda2004]
  • 长距离的语言模型,例如cache LM [DeMori1990]、主题模型
  • 基于语法的语言模型,例如[Weischedel2008]

[Bellegarda2004] Jerome R Bellegarda. Statistical language model adaptation: review and perspectives. Speech communication, 42(1):93–108, 2004.

[Chen1996] Stanley F. Chen and Joshua Goodman. An empirical study of smoothing techniques for language modeling. In Proceedings of the 34th Annual Meeting of the Association for Computational Linguistics (ACL), pages 310–318, 1996.

[DeMori1990] Roland Kuhn and Renato De Mori. A cache-based natural language model for speech recognition. IEEE transactions on pattern analysis and machine intelligence, 12(6):570–583, 1990.

[Goodman2001] Joshua T. Goodman. A bit of progress in language modeling. Computer Speech & Language, 15(4):403–434, 2001.

[Weischedel2008] Libin Shen, Jinxi Xu, and Ralph Weischedel. A new string-to-dependency machine translation algorithm with a target dependency language model. In Proceedings of the 46th Annual Meeting of the Association for Computational Linguistics (ACL), pages 577–585, 2008.

坚持原创技术分享,您的支持将鼓励我继续创作!