语言模型
什么是语言模型
语言模型是衡量一句话出现在自然语言中的概率的模型
语言模型的数学表示
在数学上,给定一句话s=\{w_1,w_2,...,w_n\}
,它出现的概率P(s)
可以表示为P(s)=P(w_1,w_2,...,w_n)
。根据联合概率的链式法则,因此P(s)
可以转换为:
P(w_1,w_2,...,w_n) = P(w_1) * P(w_2|w_1) * P(w_3|w_2,w_1) * ... * P(w_n|w_{n-1},...,w_1)
这里面的核心是P(w_i|w_{i-1},...,w_1)
,也就是说根据前文预测下一个词出现的概率。这里的问题在于当i
很大时,P(w_i|w_{i-1},...,w_1)
估算的难度很高。
根据K阶马尔可夫假设,当前词出现的概率只和它前面的k个词相关,因此,P(w_i|w_{i-1},...,w_1) \approx P(w_i|w_{i-1},...,w_{i-k})
。
根据P(A,B)=P(A|B)*P(B)
,P(w_i|w_{i-1},...,w_{i-k}) = P(w_i,w_{i-1},...,w_{i-k})/P(w_{i-1},...,w_{i-k})\\=count(w_i,w_{i-1},...,w_{i-k})/count(w_{i-1},...,w_{i-k})
。
问题在于,这里用的是连乘,由于数据稀疏问题,假如说\{w_i,w_{i-1},...,w_{i-k}\}
在语料库里面没出现,那么整个概率都会为0,假如说\{w_{i-1},...,w_{i-k}\}
在语料库里没出现,那么整个概率直接没法算了。因此,需要通过一些手段进行处理。
对于分子为0的情况,可以采用拉普拉斯平滑,即P(w_i|w_{i-1},...,w_{i-k}) =(count(w_i,w_{i-1},...,w_{i-k})+1)/(count(w_{i-1},...,w_{i-k})+|V|)
,其中|V|
为词表的大小(因为在\{w_{i-1},...,w_{i-k}\}
定了的情况下,\{w_i,w_{i-1},...,w_{i-k}\}
只有|V|
种可能)。
对于分母为0的情况下,分子一定为9(因为前缀字符串没有出现,那么以此为前缀的更不会出现了),此时采用回退策略。遍历j
,直到count(w_{i},w_{i-1},...,w_{i-k+j})/count(w_{i-1},...,w_{i-k+j})
可以计算。
评价指标
困惑度:用来度量一个概率分布或概率模型预测样本的好坏程度,困惑度越低越好。
Perplexity(s)=2^{H(s)}=2^{-\frac{1}{N}log_2P(s)}=\sqrt[n]{\frac{1}{P(s)}}
词的表示
词库
一个包含同义词和上位词的知识库
词库的差异性
- 缺少差异性,同义词不够精确
- 缺少新词,无法实时更新
- 人工标注,具有主观性
离散词表示
把每个单词被视为独立的个体,没有其他信息的嵌入,不考虑单词之间的语义或上下文关系。
One-hot表示
当前词维度为1,其他词维度为0,向量的维度是词表的长度。
词袋模型
基于One-hot表示,单词对应的维度上的值表示其出现的次数、频率、逆文档频率或TF-IDF等
TF-IDF
词频 TF
在一个文档中出现频率越高的词对当前文档可能越重要
f_{ij}=\frac{文档j中单词i出现的次数}{文档j中所有单词出现的总次数} \\
tf_{ij} = \frac{f_{ij}}{max_k(f_{kj})}
逆文档频率
在很多文档中都出现的词可能不重要(如虚词)
df_{i}=包含单词i的文档数量\\
idf_{i} = log_2\frac{文档总数}{df_{i}}
TF-IDF
综合一个词在当前文档中的频率和所有文档中出现的次数来度量这个词对当前文档的重要性
tf_{ij}-idf{i}=ntf_{ij}*idf{i}
离散词表示的问题
- 语义鸿沟:无法表征两个词之间的语义关系
- 维度爆炸:当词表很大时,存储和计算的开销极大
分布式词表示
用一个低维稠密的向量表示单词的整体含义,向量的每一维不表示具体的含义,利用整体来表达含义,其核心思想是一个词的含义能被这个词所在的上下文反映。具有低维(节省存储、计算开销)和可以度量词与词之间的语义相似性的特点。
Word2Vec
算法思想
- 大量的自然语言文本(训练语料)
- 为词表中的每个词随机初始化一个向量表示
- 遍历文本中的每个单词,其上下文单词为
- 使用单词的上下文预测单词的概率分布(核心思想)
- 更新词向量的表示使得单词的预测概率最大化
连续词袋模型CBOW
CBOW的原理是给定文本序列S=\{w_1,w_2,...,w_n\}
,在给定上下文滑动窗口m
的情况下,通过已知的上下文词来最大化中心词出现的条件概率。用数学公式来表示就是
\forall i,max_{\theta}P(w_i|w_{i-m},...,w_{i-1},w_{i+1},...,w_{i+m};\theta)
即CBOW模型需要最大化的似然函数为:
L(\theta) = \prod_{i=1}^n P(w_i|w_{o};\theta)
其中,w_{o}
表示w_{i}
的上下文。
为了便于计算,可以把最大化似然函数转换为最小化负对数似然的平均
J(\theta) = -\frac{1}{N}\sum_{i=1}^n log P(w_i|w_{o};\theta)
现在,问题就变成了如何计算P(w_i|w_{o};\theta)
。这里考虑以下这种建模方式:对于已知的上下文词,模型需要在词表中找到与之尽可能相似的词,因此,可以通过度量中心词和上下文之间的相关性(v_o^Tv_i
,v_o
为上下文词向量的平均)来建模条件概率。为了使得概率最后和为1,引入了softmax对其进行归一化,因此最后用下面这个式子计算P(w_i|w_{o};\theta)
:
P(w_i|w_{o};\theta) = \frac{exp(v_o^Tv_i)}{\sum_{j=1}^{|V|}v_o^Tv_j}
之后就可以用梯度下降去更新模型参数。
模型优化
为了让训练更加稳定,实际训练时上下文会使用另一套词向量u_o
。
Softmax在计算时需要遍历词表中的所有词,非常耗时。因此可以采用负采样的方式进行优化,即随机采样一些噪音词作为负样本,通过正样本和负样本之间的对比学习让模型知道当前位置应该是放什么词。
J(\theta)=-log \sigma(v_o^Tv_i) - \sum_{m \in 负样本}log \sigma(-v_o^Tv_m)
Skip-gram
与CBOW相反,Skipgram旨在利用中心词预测上下文。优化目标是:
\forall i,max_{\theta}P(w_{i-m}|w_i;\theta) \times ... \times P(w_{i-1}|w_i;\theta) \times P(w_{i+1}|w_i;\theta) \times P(w_{i+m}|w_i;\theta)
即
max_{\theta}\sum_{i=1}^{n} P(w_{i-m}|w_i;\theta) \times ... \times P(w_{i-1}|w_i;\theta) \times P(w_{i+1}|w_i;\theta) \times P(w_{i+m}|w_i;\theta)
同样的,对里面的乘法可以用负对数来表示
J(\theta) = -\frac{1}{N}\sum_{i=1}^{n} \sum_{-m \le j \le m;m \neq 0}P(w_{i-j}|w_i;\theta)
P(w_{i-j}|w_i) = \frac{exp(v_{i-j}^Tv_i)}{\sum_{k=1}^{|V|}exp(v_k^Tv_i)}
GloVe
基于窗口的共现矩阵
共现窗口矩阵是基于词语在文本中的共现关系构建的矩阵。具体而言,对于一个给定的词语,我们考察其在一定窗口范围内与其他词语的共现次数,从而构建词语间的共现矩阵。该矩阵可以反映词语间的上下文关系。
基于窗口的共现矩阵是简单的计数矩阵,非常高维,需要大量存储空间,且存在稀疏性的问题。为了生成低维向量,选择矩阵中最有效的信息进行存储,可以进行SVD分解。但是SVD分解性能不佳,分解得到的信息很多和功能词和停用词有关。一种修复方式就是去除功能词、停用词,同时对频数取对数。
共现矩阵
基于窗口的共现矩阵,统计窗口内单词之间的共现信息,能够捕获一些句法和语义信息(局部信息)。
基于文档的共现矩阵,统计文档和单词之间的共现信息,能够捕获话题信息(全局信息)。
与直接学习法相比,共现矩阵具有学习速度快,能有效利用统计数据的有点,但过分依赖单词共现性和数据量。直接学习法能够捕获语法和语义信息,但是速度和数据规模相关、未有效利用统计数据。
Glove
集两家之长,以学习的方式,用词向量之间的语义关系来拟合共现概率矩阵。
神经网络与语言模型
人工神经网络
人工神经网络(Artificial Neural Network,ANN)从信息处理角度对人脑神经元网络进行抽象,建立某种算法数学模型,从而达到处理信息的目的。
人工神经元用数学可以表达为f(WX+b)
,其中权重参数W
进行缩放拟合,偏置b
进行平移拟合,非线性激活函数f
使神经网络具有非线性拟合能力。
循环神经网络和语言模型
语言模型
衡量一句话出现概率的判别模型,它的输入是一句话,输出是这句话出现的概率,即这些单词的联合概率。
统计语言模型(N-Gram)
N-Gram基于马尔科夫假设,认为第i个词出现的概率只和它前面的N-1个词相关,即P(w_i|w_1,...,w_{i-1})=P(w_i|w_{i-N+1},...,w_{i-1})
。
假设句子S由\{w_1,w_2,...,w_n\}
组成,则:
P(s)=P(w_1,w_2,...,w_n)\\=P(w_1)P(w_2|w_1)...P(w_n|w_1,w_2,...w_{n-1}) \\= P(w_1)P(w_2|w_1)...P(w_n|w_{n-N+1},...w_{n-1})
问题就转变为了怎么计算P(w_n|w_{n-N+1},...w_{n-1})
。根据大数定律,只要数据量足够大,相对频度就可以等于概率。因此,P(w_n|w_{i-N+1},...w_{n-1}) = \frac{P(w_{n-N+1},...w_{n-1},w_n)}{P(w_{i-N+1},...w_{n-1})}
。
通过对每个w_n
进行遍历,寻找使得P(s)
最大的那个w_n
,就可以预测下一个词。(本质上就是给定前N-1个词,预测下一个词)
统计语言模型存在的问题是存在稀疏性(需要进行平滑和回退等操作)和存储问题。
基于N-Gram的神经网络语言模型
与N-Gram类似,神经网络的输入是N-1
个上下文词,其拼接词向量(一维向量)e \in \mathbb{R}^{N*d}
。
首先利用一个隐藏层,对词向量进行非线性变换h=f(We+b_1)
,h \in \mathbb{R}^{c}
。
再利用softmax,输出预测概率\hat{y}
,\hat{y}=softmax(Uh+b_2)
,\hat{y} \in \mathbb{R}^{|V|}
。
最后,选择预测概率最大的那个位置对应地词就可以了。
该方法的优点是不会有稀疏性的问题,也不需要存储所有的N-Gram,问题在于视野有限,无法建模长距离语义,并且窗口越大,参数规模越大。
循环神经网络
循环神经网络重复使用隐层参数,可以处理任意序列长度。
h_t = f(W_hh_{t-1}+W_xx_t+b)
循环神经网络的优点在于能够处理任意长度序列,能够使用历史信息,模型参数量不随序列长度增加;但是逐步计算,速度较慢,存在长期依赖问题。
训练过程
假设输入为长度为T
的文本:x_1,x_2,...x_T
。首先将文本输入RNN-LM,计算每一步预测单词的概率分布\hat{y}^t
。
然后,计算每一步预测单词的概率分布\hat{y}^t
和真实单词y^t
(one-hot向量)之间的交叉熵。
J^t(\theta)=CE(y^t,\hat{y}^t)=-\displaystyle \sum_{w \in V} y_w^t \text{log} \hat{y}_w^t
由于,y^t
是one-hot的,所以只在分类正确的地方有值,因此可以进一步简化为
J^t(\theta)=- y_{x_{t+1}}^t \text{log}\hat{y}_{x_{t+1}}^t
最后,模型在输入文本上的训练损失可以表示为
J(\theta)=\frac{1}{T} J^t(\theta)
梯度爆炸、梯度消失
在RNN中,梯度是逐时间步累乘的。如果每一步的梯度值稍大于 1,经过多次相乘后,梯度会变得非常大,导致 梯度爆炸;如果每一步的梯度稍小于 1,梯度会逐渐趋近于 0,导致 梯度消失。
高级循环神经网络
长短期记忆网络 LSTM
长短期记忆网络引入三个门和一个细胞状态来控制神经元的信息流动。
遗忘门f_t
控制哪些信息应该从之前的细胞状态中遗忘f_t = \sigma(W_fh_{t-1}+U_fx_t+b_f)
。
输入门i_t
控制哪些信息应该被更新到细胞状态中i_t = \sigma(W_ih_{t-1}+U_ix_t+b_i)
。
候选细胞状态\hat{C}_t
生成可能的新状态信息\hat{C}_t = \text{tanh}(W_ch_{t-1}+U_cx_t+b_c)
。
细胞状态更新C_t
容纳神经元信息C_t = f_t ⊙ C_{t-1} + i_t ⊙ \hat{C}_t
输出门o_t
控制哪些信息应该被输出到隐层状态h_t
中f_o = \sigma(W_oh_{t-1}+U_ox_t+b_o)
;h_t = o_t ⊙ \text{tanh}(C_t)
。
由于LSTM使用累加的线性变化来传递上下文信息,而不是传统的覆写形式,因此可以缓解远程梯度爆炸和梯度消失问题。
门控循环单元 GRU
与LSTM相比,GRU不使用细胞状态,参数更少,速度更快。
更新门z_t
控制哪些信息应该被更新z_t = \sigma(W_zh_{t-1}+U_zx_t+b_z)
。
重置门r_t
控制哪些信息应该被重置r_t = \sigma(W_rh_{t-1}+U_rx_t+b_r)
。
候选隐状态\widetilde{h}_t
将之前的历史信息和当前时间步的输入进行了结合\widetilde{h}_t = \sigma(W_h(r_t ⊙ h_{t-1})+U_hx_t+b_h)
。
输出隐状态h_t
确定新的隐状态在多大程度上来自旧的状态和新的候选状态h_t = (1 - z_t) ⊙ h_{t-1} + z_t ⊙ \widetilde{h}_t
双向循环神经网络 (Bi-RNN)
双向循环神经网络由两个RNN网络结合而成,一个网络从前往后处理输入序列,另一个网络从后往前处理输入序列,可以同时捕捉输入序列的上下文语义。
多层循环神经网络(STACKED-RNN)
多层RNN是一种通过堆叠多个RNN层来构建深度循环神经网络的方法。每个RNN层都有自己的参数,并且前一层RNN的输出状态向量会被用作下一层RNN的输入。这种结构可以捕捉输入序列的深层语义信息,提高模型的表示能力。
应用:利用RNN-LM生成文本
讨论:仅仅RNN有梯度问题吗?
神经网络都有可能会产生梯度问题,深层网络更容易产生梯度问题(梯度连乘后容易接近0(消失)或者爆炸)。
梯度消失常用解决方案:
- ReLU
- 残差连接
梯度爆炸常用解决方案:
- 梯度裁剪(Clipping)