NLP——ELMO模型

NLP——ELMO模型

1、模型预训练和模型微调

作为近些年来深度学习的两个应用思路,预训练和模型微调为后面的任务提供了良好的基础。所以,我们先来介绍一下预训练和模型微调的概念。

1.1 预训练

我们从一个例子开始,假设我们接到的是一个文本分类的任务,需要对数据集A中的文本进行文本分类,我们的首先要做的是对于A中的文本进行分词,生成词向量。然后采用某一个深度学习的模型。训练分类的参数。现在,我们将目光聚焦在词向量生成的过程中,假设我们同时有一个超大的文本数据集B,B中的文档的数量要远远大于A中文档的数量,换句话说,如果我们采用某一种词向量的计算方法对数据集A和数据集B中的词汇计算词向量,那么由B生成的某个词的词向量所蕴含的特征信息要比由A生成的相同词所蕴含的特征信息要高很多,因为B中的词能够综合更多的文本特征信息。那么很自然的,我们就可以想到,我们可以利用B中的词汇来训练词向量,然后利用这些词向量完成对于A的文本分类任务。我们用一个图来展示这个过程:
在这里插入图片描述

如果你对迁移学习有一些基本的了解,那你一定会明白,这不就是迁移学习嘛,没错,所谓的预训练过程,实际上就是迁移学习的一种形式,我们通过一个特别大的训练集来训练一些参数,词向量等等,然后利用生成的参数或者词向量来完成下游的任务,我们将上游预训练参数,词向量等等的过程称为预训练过程。比较著名的预训练模型就是我们接下来将会介绍的ELMO模型等等。

1.2 模型微调fine-tuning

上面我们介绍了预训练的概念,我们接着上面的例子,假设我们从B中通过预训练获得了一组参数W,然后利用这组参数来对于A中的文本进行分类,这里有一个小问题,虽然我们通过大量的文本获得了参数组W,但是这组参数能够完全契合我们的数据集A吗?换句话来说,假设我们的样本集B是维基百科中的全部文本集,数据集A为一个关于医疗的文本集合,那么我们从维基百科文本中获得的参数可以完全拟合医疗文本吗?这显然是不行的,因为对于医疗文本而言,其本身具有的一些文本特性。例如医学名称,药物名词等等这些都是和其他类型的文本是不同的,所以,我们不能直接使用参数W,但是由于W是基于大规模文本来的,所以我们只需要在参数W的基础上进行一些调整,使其能够更加的满足我们医疗文本的特征就可以了,这个调整的过程被称为fine-tunning。

总结一下,所谓的模型微调,是指我们在大规模数据中获得了参数W,为了能更好的使用小规模数据的特性,我们对参数W进行稍微的调整,而不是重新的进行训练。这样,我们可节省大量的训练时间,同时还能够从大规模的数据中获得有用的特征,同时还不会影响到我们对于小规模数据的特征计算。fine-tuning中比较知名的模型是Bert,我们会在之后的文章中进行讲解。

2、ELMO模型

2.1 模型引入

在了解了模型的预训练和模型的微调的过程之后,我们首先来介绍一个经典的预训练模型——ELMO。我们之前多次讲述过,在NLP任务中,最为基础,同时也最为重要的过程就是词向量的获取,而对于词向量的获取,目前来看,大多数的模型都是使用到了语言模型的思想,这种思想的核心在于利用前面的n-1个词来预测当前的第n个词,也就是:
P ( w n w 1 , w 2 , w 3 , . . . . , w n 1 ) P(w_n|w_1,w_2,w_3,....,w_{n-1})
这种利用前面词汇的形式,在深度学习中,我们有一类很好的模型可以对其进行模拟,那就是RNN类的深度学习模型。进一步,为了解决语言模型中只考虑前面的词局限性,我们可以使用双向的RNN类模型来同时综合上下文环境。而ELMO就是基于上面描述的这些点的一个预训练模型。下面我们来具体介绍一下。

2.2 RNN类模型回顾

在深度学习中,RNN类模型在基于序列建模的任务上有着很好的拟合情况,同时也产生的非常好的效果。我们首先来回顾一下RNN类模型的基本架构和其中最为经典的LSTM模型。

2.2.1 RNN类模型综述

在这里插入图片描述
这是一个RNN的总体结构图,对于RNN类的模型而言,其输入包括两种,第一种基于当前时刻的输入X,第二种是基于前一个时刻的状态来作为输入,通过一个权重,模型可以决定这两个部分在当前时刻的占比,然后在融合之前的信息和当前信息的基础上产生当前时刻的输出。其基本的计算公式为:
h t = f ( W X t + U h t 1 + b ) h_t=f(WX_t+Uh_{t-1}+b)
其中W和U都是用来调节占比的权重矩阵,b表示偏置项。f表示激活函数。

这种机制存在存在以下两个问题:

  1. 长距离依赖性。
    所谓的长距离依赖指的是,在计算的过程中,随着RNN链的不断增加,距离当前时刻比较远的信息被保留下来的非常少,换句话来讲,当前时刻的状态更多的依赖于前几个距离较近的时刻的状态,而不是之前所有时刻。
  2. 梯度消失、梯度爆炸
    这个问题很好理解,在RNN的反向传播过程中,使用BPTT算法,对于某一个时刻计算梯度值的时候,使用的是类似于下面的公式:
    L h i = L h n L h n 1 , . . , L h i + 1 L h i \frac{∂L}{∂h_i}=\frac{∂L}{∂h_n}\frac{∂L}{∂h_n-1},..,\frac{∂L}{∂h_{i+1}}\frac{∂L}{∂h_i}
    如果对于其中的一些项而言,其大数如果大于1的话,反向传播的梯度值可能会产生指数级的增长,则也就引起了梯度爆炸。同时,如果某些项的梯度值小于1的话,其梯度也会呈现出指数级的下降,这也就引起了梯度消失的问题。

为了解决上面所提出来的问题,于是就提出了对于简单的RNN改进的一种算法——LSTM。

2.2.2 LSTM模型

首先,我们给出LSTM的基本结构:

在这里插入图片描述

可以看出,在整体结构上,LSTM的依旧使用了RNN的基本结构,但是为了解决我们上面提到的问题,LSTM在每一个时刻的单元内部做出一些改进。

首先,LSTM中采用了不同的门控方式,对于最左侧的门控,我们称其为遗忘门,其主要的作用是用于判断从前一个时刻传递过来的信息。其基本的计算公式如下:
f t = s i g m o i d ( W f X t + U f h t 1 + b f ) f_t=sigmoid(W_fX_t+U_fh_{t-1}+b_f)
中间的门控被称为输入门,用于控制输入信息:
i t = s i g m o i d ( W i X t + U i h t 1 + b i ) i_t=sigmoid(W_iX_t+U_ih_{t-1}+b_i)
最右侧的门被称为输出门,用于控制输出信息:
o t = s i g m o i d ( W o X t + U o h t 1 + b o ) o_t=sigmoid(W_oX_t+U_oh_{t-1}+b_o)
同时,我们在维护一个负责控制当前输入的候选细胞状态,由这个候选状态来控制输入门结果的输入:
g t = t a n h ( W g X t + U g h t 1 + b g ) g_t=tanh(W_gX_t+U_gh_{t-1}+b_g)
然后我们更新细胞状态为:
c t = f t c t 1 + i t g t c_t=f_t*c_{t-1}+i_t*g_t
最后产生隐状态输出:
h t = o t t a n h ( c t ) h_t=o_t*tanh(c_t)
通过LSTM的各个门控结构,尽量降低了梯度爆炸或者梯度消失的可能性,同时尽量解决了长距离依赖的问题。由于我们只是对于LSTM进行回顾,有兴趣的读者可以仔细的去对LSTM进行深入的了解。

2.3 通过双向的LSTM来模拟语言模型

老规矩,我们也先给出ELMO的模型结构,在进行具体的叙述:

在这里插入图片描述
在上面的结构中,我们可以看到,采用的是双层双向的LSTM得结构,我们首先来分析第一层的双向LSTM结构。

对于前向的LSTM中的第t个时刻而言,由于其模拟的是语言模型,那么也就是说,第t个时刻的输出为:
P ( h t ) = P ( h t h 1 , h 2 , . . . , h t 1 ) P(h_t)=P(h_t|h_1,h_2,...,h_{t-1})
所以,对于整个序列的输出有:
P ( h 1 , h 2 , . . . . , h n ) = k = 1 n p ( h k h 1 , h 2 , . . . h k 1 ) P(h_1,h_2,....,h_n)=∏_{k=1}^np(h_k|h_1,h_2,...h_{k-1})

同理对于后向的LSTM而言,其计算结果就是:
P ( h 1 , h 2 , . . . . , h n ) = k = 1 n p ( h k h k + 1 , h k + 2 , . . . h n ) P(h_1,h_2,....,h_n)=∏_{k=1}^np(h_k|h_{k+1},h_{k+2},...h_{n})

综上所述,对于第一层的BI-LSTM,我们可以综合前向和后向的两个LSTM得到输出的似然函数为:
i = 1 n l o g ( P ( h i ) ) = l o g ( P ( h i h 1 , h 2 , . . . h i 1 ; θ x ; θ l e f t ; θ s ) ) + l o g ( p ( h i h i + 1 , h i + 2 , . . . h n ; θ x ; θ r i g h t ; θ s ) ) ∑_{i=1}^nlog(P(h_i))=log(P(h_i|h_1,h_2,...h_{i-1};θ_x;θ_{left};θ_s))+log(p(h_i|h_{i+1},h_{i+2},...h_{n};θ_x;θ_{right};θ_s))
其中三个θ表示的输入X的参数,lstm的参数和softmax参数。参数的意义我的最后会提到

如果了解了第一层的BI-LSTM,那么下面的就很好理解了,我们上第一层BI-LSTM的每个时刻的输出作为下一层的BI-LSTM的每个时刻的输入,在将第一层的BI-LSTM的计算过程重复一遍即可。可能有的读者会有一些疑惑,简单的复制这个过程的意义在哪里?这里我们可以这样理解,从输入到第一层的BI-LSTM,是建立在词汇级别的特征抽取,第二层的BI-LSTM的是站在句法级别的特征抽取。

最终,我们可以获得整个模型的极大似然函数为:

i = 1 n l o g ( P ( h i ) ) = l o g ( P ( h i h 1 , h 2 , . . . h i 1 ; θ x ; θ l e f t ; θ s ) ) + l o g ( p ( h i h i + 1 , h i + 2 , . . . h n ; θ x ; θ r i g h t ; θ s ) ) ∑_{i=1}^nlog(P(h_i))=log(P(h_i|h_1,h_2,...h_{i-1};θ_x;θ_{left};θ_s))+log(p(h_i|h_{i+1},h_{i+2},...h_{n};θ_x;θ_{right};θ_s))

这里我们需要对参数进行一下解释,对于第一个参数 θ x θ_x ,其表示的是从输入到第一层LSTM的相关参数, θ l e t f θ r i g h t θ_{letf}和θ_{right} 分别表示双向的LSTM中的参数(两层的LSTM参数是不共享的,但是某一层中的单元对于LSTM是共享的), θ s θ_s 表示词汇softmax的参数,也就是我们要预测输出的参数。

2.4 EMLO的输出结果

对于EMLO而言,如果我们调节LSTM有L层,那么我们根据前向后向以及最初的输入,可以得到对于每一个词汇有2L+1个词向量。有下面的公式表示就是:
在这里插入图片描述
这样,我们就确定了最终的每一个词汇的表示。

2.5 ELMO的应用

对于ELMO模型最简单的使用方式是单独使用整个模型最终的输出,而不去考虑其他的层的输出和最开始的输入:
在这里插入图片描述
但是为了更多的特征信息,我们通常也会综合其所有的输出信息,这个时候将不同层的输出进行拼接,在通过参数对维度进行调节,以及γ的缩放和s的正则化调节。

2.6 ELMO的优势分析

如果我们通过预训练的方式获得了ELMO中的参数,那么当我们想要获得某一个词的向量的时候,这种词向量的形式是否固定呢?答案是否定的,由于LSTM的形式,我们每次的输入一个句子,那么在获取输出的时候,LSTM的网络结构会考虑单词的不同的上下文信息,换句话来说,当词汇处于不同的上下文中,那么其获得上下文信息是不同的,那么其输出也就是不同的。这也就是ELMO能够产生动态词向量的原因。在产生动态词向量之后,就可以去完成下游的不同任务了。

2.7 总结

作为一种经典的预训练模型,ELMO的整体思想是很简单的,同时也可以看出语言模型在NLP中的重要性。其动态,基于语境的词向量生成方式,为下游的任务带来了很多的便捷。

3、参考

  1. ELMo:Deep contextualized word representations
  2. ELMo原理解析及简单上手使用