语言模型
简介
语言模型是自然语言处理的一个重要部分,在很多生成式任务中,都离不开语言模型。今天我想梳理一下我所理解的语言模型及其发展。
定义
对于一串语言序列 \(w_1w_2\dots w_n\),语言模型试图分析其出现的概率,即 \(P(w_1,w_2,\dots,w_n)\)。进而,可以通过概率大小判断文本是否合理。例如句子 “学生们打开了书” 的概率应该比 “学生们打开了玛卡巴卡” 高得多,即更像是人说的话。
在之前的 VQ-VAE 中,我们提到过自回归模型,按照自回归的思路,如果第 n 个单词只与前 n-1 个单词相关,那么句子的概率可以转化为如下形式: \[ P(w_1,w_2,\dots,w_n)=\prod_t^nP(w_t|w_{t-1:1}) \] 那么怎么求解右侧的式子呢?
N-gram
首先要提到的是 N-gram 模型。为了解决上面这个问题,N-gram 模型引入了马尔科夫假设,认为某一个词只与它之前的 \(N-1\) 个词有关。以 4-gram 为例,即每个词只与其之前的 3 个词有关,即: \[ P(w_n|w_{n-1:1})=P(w_n|w_{n-1},w_{n-2},w_{n-3}) \] 换而言之,只要在大规模语料中进行频数的统计,那么就可以得到上述概率的估计: \[ P(w_n|w_{n-1},w_{n-2},w_{n-3})=\frac{C(w_n,w_{n-1},w_{n-2},w_{n-3})}{C(w_{n-1},w_{n-2},w_{n-3})} \] 进而整个句子的概率可以计算如下: \[ P(w_1,w_2,\dots,w_n)=\prod_t^nP(w_t|w_{t-1},w_{t-2},w_{t-3}) \] 上述的方法虽然简单直接,但是有以下缺点:
- 稀疏问题:一些片段可能没有在语料中出现,计数为 0,在概率连乘之下整句概率变为 0。
- 存储问题:随着 n 的增大,存储量指数级上升,而 n 过小时模型性能又会很差。
基于窗口的神经网络
在 N-gram 的基础上,使用神经网络来计算条件概率。同样以 4-gram 为例,计算用公式表达如下: \[ \begin{align} P(w_n|w_{n-1:1})&=P(w_n|w_{n-1},w_{n-2},w_{n-3})\\ &=softmax(W[w_{n-1};w_{n-2};w_{n-3}]) \end{align} \] 思路非常简单,即将前 N-1 个词输入到神经网络,由神经网络计算得到第 N 个词的概率分布。这样做解决了 N-gram 的稀疏问题与存储问题,但也存在一些问题:
- 缺少参数共享:以上述公式为例,\(W\)中可以分为三部分,分别处理前三个词。然而,词向量的处理逻辑应该是相似的(因为他们都是同样的方法训练出来的)。
- 需要变化窗口大小时,矩阵 W 的形状也需要变化,进而需要重新训练。
循环神经网络 RNN
RNN 的思路同样也很直接,使用同一个矩阵 \(W\) 来处理词向量,并使用一个隐藏状态来记录已处理的信息(换而言之,就无需马尔科夫假设)。RNN 的公式如下: \[ h_t=\sigma(W^{(hh)}h_{t-1}+W^{(hx)}x_t) \]
\[ \hat{y_t}=softmax(W^{(S)}h_t) \]
其中,\(\sigma\) 是激活函数,\(h_t\) 是 t 时刻的隐藏状态,\(W\) 是参数矩阵。
RNN 有以下优点:
- 能够处理任意长度的序列。
- 没有进行马尔科夫假设,理论上每一时刻模型都知道之前时刻的全部信息。
但也有以下缺点:
- 会出现梯度消失和梯度爆炸问题。
- 不支持并行化,计算较慢。(可以说是自回归模型的通病)