深度学习:前沿技术-从Attention,Transformer,ELMO,GPT到BERT
欢迎转载,作者:Ling,注明出处:前沿技术-从Attention,Transformer,ELMO,GPT到BERT
1.1 2018NLP:BERT惊艳四座
2018年一篇论文 “BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding”腾空出世,刷新了11项NLP任务的最优性能记录。这有点像前几年CNN参加Image Net比赛,刷新了图像识别领域记录,从而让全球掀起了一场人工智能风暴时的场景。基本上也宣告了NLP进入一个新纪元。
BERT出现并非偶然,其中提出的技术,实际上也并非之前都没有出现过,我更愿将其看成是NLP最新技术的一个集大成者,它综合了Attention,Transformer,ELMO, GPT等的优点,从而达到现今的成果。
本文将由浅入深,从Attention原理谈起,然后介绍Transformer的原理,最后一直介绍到BERT的原理,中间还会介绍Word Embedding,ELMO,GPT等知识,以便了解BERT出现的历史必然,以及为什么BERT能够成功。
NLP有四大类问题,基本可以以此衡量NLP发展情况。
早期NLP发展是基于规则解决问题,比如专家系统,这种方式扩展性差,因为无法通过人来书写所有规则。
之后提出了基于统计学的自然语言处理,早期主要是基于浅层机器学习解决NLP问题。例如,通过马尔科夫模型获得语言模型,通过条件随机场CRF进行词性标注。如果你去看StandFord的NLP工具,里面处理问题的早期方法,都是这类方法。
当深度学习在图像识别领域得到快速发展时,人们也开始将深度学习应用于NLP领域。深度学习在NLP领域的发展,有很多可圈可点的东西。
首先是Word Embedding。它可以看成是对单词特征提取得到的产物,它也是深度学习的副产物。随后,人们又提出了word2vec,glove等类似预训练的词向量,作为对单词的特征抽象,输入深度学习模型。
其次是RNN。RNN使得神经网络具有时序的特性,这种特性非常适合解决NLP这种词与词之间有顺序的问题。但是,深度学习存在梯度消失问题,这在RNN中尤其明显,于是人们提出了LSTM和GRU等技术,以解决这种梯度消失问题。在2018年以前,LSTM和GRU在NLP技术中占据了绝对统治地位。具体原理可以参考我之前的博客。
当时RNN有个致命的问题,就是训练慢,无法并行处理,这限制了其发展。于是人们想到了是否可以用CNN替代RNN,以解决这个问题。于是人们提出了用1D CNN来解决NLP问题,具体可以参考我之前的博客。但是这种方式也有个明显问题,就是丢掉了RNN的时序优势。
除了时序问题,我们还不得不提另外一个关键问题,即注意力Attention。Attention最早用于图像识别领域,然后再被用于NLP领域,后面会详细介绍Attention。
有了Attention技术,我们急需新技术既可以保证并行处理,又可以解决时序问题。于是Transformer腾空出世。它也是BERT的基础之一。后面会详细介绍Tranformer。
除此之外,ELMO提出的预训练双向语言模型以及GPT提出的单向Tranformer也是最新双向Transformer发展的基础,在《Attention Is All You Need》一文,甚至Transformer上升到另外一个高度。
BERT正是综合以上这些优势提出的方法,可以解决NLP中大部分问题。
在具体介绍什么是Attention之前,我们先介绍Seq2Seq模型,然后介绍Attention在其中的应用。
Seq2Seq模型的典型使用场景是用于机器翻译:输入一种语言的句子,经过seq2seq模型,输出另外一种翻译后的语言的句子 。
运行前:
运行后:
动态过程:
细化:实际上seq2seq模型里面有两个东西,一个Encoder,一个Decoder:
Encoder不断接受输入,生成隐含层,当全部输入完毕,生成一个固定隐含层向量context,然后结合Decoder,不断生成输出结果。
运行前:
输入第一个单词, 生成隐含层:
所有输入完毕,生成context向量:
输出第一个单词:
依次输出所有单词:
动态过程:
更加细化:每个Encoder都是RNN,不断输入单词,生成隐含层,输入完毕,生成context固定向量,然后不断结合Decoder RNN,依次生成输出
运行前:
输入一个单词,生成隐含层h1:
所有输入完成,生成固定维度的context向量(隐含层):
依次生成结果,注意这里生成am时,实际上会将I作为输入:
动态过程:
如果将RNN换成LSTM或者GRU就是基于LSTM或者GRU的Seq2Seq模型。
在一般的Seq2Seq模型中,我们发现存在两个问题:
1)无论输入多长,都会生成一个固定的context向量,也就是说,无论输入句子信息量如何,生成的context向量是固定的,而越长的句子,需要存储更多context信息,用相同context向量存储,不合适。
2)在传统翻译中,有个句子对齐的概念,比如 I -> 我,am -> 是,但是在一般seq2seq模型中并未体现出来,所以我们需要加入Attention,让输入的不同单词,对最后生成的每个单词贡献不同的信息量。
这就是Attention出现的根本原因。
Attention就是让输入不再使用一个固定维度的Context向量,而是将所有输入的每个隐含层都取出,按照对不同的输出单词贡献信息量的不同,分配比例,从而使得效果更好。
加入attention后:
运行前:
输入部分过程和之前完全一样:
不同在于所有输入隐含层都将用于生成输出:
生成输出:注意生成am时,I会作为输入,图中并未显示出来
动态过程:
接下来我们只用回答以下两个问题即可:
问题一:Attention Decoder RNN内部细节是什么?
角度一:
1)hinit(初始固定隐含层) + <END>(生成第一个输出的固定向量)通过RNN生成h4
2)输入h1,h2,h3和h4,通过一定方式计算得到C4,这个就是Attention向量
3)拼接h4和C4,然后通过前向NN,生成输出o1
4)h4+o1生成h5
5)h1,h2,h3和h5,生成C5
6)拼接h5和C5,生成输出o2
如此反复,直到生成结尾
动态过程:
角度二:
1)输入h1,h2,h3,h4,得到Attention Scores
2)通过Softmax,得到h1,h2,h3对当前输出分配的比例
3)h1,h2,h3乘以各自比例求和得到C4
动态过程:
问题二:“一定方式”是什么什么方式
不同方法有不同方式,常见的有:
训练神经网络:h1,h2,h3,h4->C4
求相似度:h1,h2,h3分别和h4求相似度得到C4
总结:
Attention就是根据输入隐含层和当前输出隐含层,计算出来的一个分配比例(概率),该分配比例决定了如何将输入的所有隐含层,综合得到一个对当前输出的context向量,从而代替之前的固定context向量,影响输出结果。
通过该图可以看出,加入Attention可以使得不同输入,对每个输出单词贡献不同,从而达到句子对齐的目的。
Transformer是建立在Attention基础之上,是更加一般化的Attention应用。它出自于Attention is All You Need。
官方图:
不好理解,我们分解细化深入研究。
抽象看:
Transformer可以将输入转成输出
内部组成:
Transformer内部实际上是包含了一组Encoders和一组Decoders
具体点:包含6个encoder和decoder的Transformer
Encoder和Decoder内部:
一般情况下:
Encoder包含:一个Self-Attention和一个Feed Forward NN
Decoder包含:一个Self-Attention,一个Encoder-Decoder Attention和一个Feed Forward NN
Encoder继续细化:
Encoder接受输入单词的word Embedding,经过Self-Attention得到z1,z2,z3, 你可以理解为,对所有word重新计算了其特征表示,然后再经过一个Feed Forward NN得到最终每个word的特征向量
多个Encoder一起看:
经过Feed Forward NN得到r1,r2,这个是最终的每个单词的特征表示。
问题:为什么这种特征表示比word Embedding特征表示更好?
回答:关键在于Self-Attention
什么是Self-Attention:
举个例子:我们希望翻译The animal didn't cross the street because it was too tired”
这个句子中的it在翻译时候实际上和该句子中其他单词有关系:
图中颜色深浅表示关系强弱。
也就是说,在翻译时,不仅应该考虑当前单词,还得考虑周围单词,这个就是Self-Attention
Self-Attention就是要对句子中其他词分配一个比例,从而为it_生成新的特征向量表示。
Self-Attention详解:x1如何生成z1?
1) 通过word Embedding生成q,k,v
q1=X1 * WQ, q2=X2*WQ
k1=X1*WK, k2=X2*WK
v1=X1*WV, v2=X2*WV
也就是我们通过训练,要得到WQ,WK,WV三个矩阵,它们分别乘以输入,可以得到每个输入的q,k,v
通过接下来的步骤,我们可以知道q,k,v的含义。
2) 计算Attention Scores:
通过相似度计算,即q1*k1可以得到X1和自己的相似度,通过q1*k2可以得到X1和X2的相似度,也就是说q和k是用于计算自己和其他单词相似度的。
3)计算分配比例:
为了不要让每个值太大,除以dk开根号
然后计算softmax,也就是每个x1,x2对生成x1特征应当贡献的比例
4)计算最终特征向量
用比例乘以之前的v,然后求和,得到最终的特征向量z,这就是x1在该句子中,经过self-attention之后带上下文信息的特征向量。
矩阵运算:前面我们是分解查看,实际上运行时,是矩阵运算
整体公式:
在论文中公式:
多头:
以上得到的实际上是每个单词的一个特征表示,也可以称为一个“Head”,实际上我们看东西可以从不同角度看,通过不同的WQ,WK,WV,我们可以得到不同的特征表示,也就是“Multi-Head”
这有点像CNN中通过不同参数矩阵,提取不同特征类似。
图中显示了我们通过不同的WQ,WK,WV得到的七个Head
Z0, Z1,...,Z7
这样每个word都有多个特征表示,最终我们希望只有一个特征表示,我们可以通过下面方式使得每个word只有一个特征表示:
1)首先concatenate所有head
2)然后乘以一个训练出来的W
3)得到最终的每个word的特征表示
综合前面所有步骤:
1)输入word Embedding
2)乘以不同的WQ, WK, WV得到不同的z
3)乘以w,得到最终的Z
这个Z就是基于上下文的每个单词的特征表示
不同head对结果的贡献效果:
位置信息:Position Encoding
从前文可以看出,所有word Embedding是同时输入,这样做法和RNN相比,缺少了时间序列信息,于是我们需要引入Positional encoding vector将时间序列信息加入到最终的word特征向量表示中:
即在输入前,先将Word Embedding加上位置信息,然后再输入
残差网络:Residual
由于有多个Encoder存在,所以会导致层次比较深,存在梯度消失问题,所以需要加入残差连接和Normalization步骤:
一个Encoder有两个残差连接
具体点:
1)浅绿色x1,x2和z1,z2求和,做Normalization得到新的深红色z1,z2
2)新的深红色z1,z2和Feed Forward结果求和做Normalization,得到最终一个Encoder输出的最终z1,z2,这就是经过Encoder之后的,对原有加了位置信息的Word Embedding提取的新的每个Word的特征向量,它将作为Decoder中encoder-decoder attention的输入
整体看2 Encoders和2 Decoders:
我们可以看到,Encoder结果将作为每个DecoderEncoder-Decoder Attention的输入。
Decoder:
三部分构成:
Self-Attention
Encoder-Decoder Attention
Feed Forword NN
Self-Attention:和encoder完全类似
1)输入当前(注意,最一开始是<END> word Embedding)word Embedding,结合Positional encoding Vector 作为输入x1
2)经过Self-Attention得到z1(参考之前如何做self-attention)
3)x1和z1求和,做Normalization得到新的z11输出,作为Encoder-Decorder Attention输入
Encoder-Decoder Attention:
1)假设Encoder最终输出为ZZ1和ZZ2
2)我们根据self Attention方法,先乘以WK和WV,多头是多个WK和WV,得到K和V
3)由z11乘以WQ,多头是多个WQ,得到Q
4)由K,V,Q生成新的z111
5)新z111和老的z11求和,然后Normalize,生成更新的z1111
Feed Forword NN:
1)新的z1111经过FFNN,生成更更新的z11111
2)然后再经过Add & Normalization生成最终的z111111
如此经过多个decoder
来到linear & softmax
linear就是一个全连接层,softmax最后进行多分类,得到输出结果 I
动态过程:
通过类似方法直到生成<END>
以上就是Transformer的全部过程
动态过程:
3.3 Transformer成功原因
Transformer成功主要原因如下:
1)self-attention
以往我们都是用一个固定的word Embedding表示每个单词的特征向量,但是实际上在不同的句子中,相同单词可能含义不一样,比如play,可以是玩,也可以是戏剧,所以我们应当给予不同的特征向量,Transformer可以输入Word Embedding得到这样的带上下文信息的word向量,也就是将句子中其他单词分配一定的比例,重新计算每个单词的特征向量。
self-attention不仅用于Encoder,也用于Decoder
2)mutil-head attention
为了保证从不同角度分配attention,引入了多头的概念。
3)Postional Vector
引入以保证有时序信息
4)encoder-decoder attention
和seq2seq model with attention一样,在生成输出时,对输入隐含层分配不同的比例来影响输出。
整个过程:
1)带有时序信息
2)可并行
在图像识别领域,已经可以很好地进行迁移学习。
迁移学习主要分两步:
1)预训练:通过CNN学习一个神经网络,去掉最后1-*层,保持前几层参数不变,用于提取特征。
2)Fine-tuning:加入新的最后全连接和softmax分类层,Fine tuning最后几层参数。
优点:
1)避免训练前面特征提取层参数,节约时间。
2)通用性增强,语料不足也没关系,可以使用别人大型语料训练的前几层,然后用自己的小型训练语料训练最后几层。
BERT是NLP领域的迁移学习方法。
特点:
1)基于Tranformer
2)双向Transformer
3)超强特征提取
4)可以用于迁移学习
5)可以解决NLP各类问题
现有NLP深度学习集大成者。
4.2 ELMO简介
在介绍BERT之前,先简单介绍ELMO和GPT,这样可以更好理解BERT原理。
Word Embedding有个缺点,就是固定不变,像Paly这种有多重语义的单词,没法在不同上下文中区分开。于是就有了ELMO,它可以使得每个单词在不同语义下,有不同的word向量表示,或者说word特征表示。
ELMO是“Embedding from Language Models”的简称,其实这个名字并没有反应它的本质思想,提出ELMO的论文题目:“Deep contextualized word representation”更能体现其精髓,而精髓在哪里?在deep contextualized这个短语,一个是deep,一个是context,其中context更关键。在此之前的Word Embedding本质上是个静态的方式,所谓静态指的是训练好之后每个单词的表达就固定住了,以后使用的时候,不论新句子上下文单词是什么,这个单词的Word Embedding不会跟着上下文场景的变化而改变,所以对于比如Bank这个词,它事先学好的Word Embedding中混合了几种语义 ,在应用中来了个新句子,即使从上下文中(比如句子包含money等词)明显可以看出它代表的是“银行”的含义,但是对应的Word Embedding内容也不会变,它还是混合了多种语义。这是为何说它是静态的,这也是问题所在。ELMO的本质思想是:我事先用语言模型学好一个单词的Word Embedding,此时多义词无法区分,不过这没关系。在我实际使用Word Embedding的时候,单词已经具备了特定的上下文了,这个时候我可以根据上下文单词的语义去调整单词的Word Embedding表示,这样经过调整后的Word Embedding更能表达在这个上下文中的具体含义,自然也就解决了多义词的问题了。所以ELMO本身是个根据当前上下文对Word Embedding动态调整的思路。
ELMO分两步:
1)预训练:通过训练语言模型,训练一个可以让word在不同环境下有不同向量的网络。
2)Fine-tuning:根据预训练结果,求每个word特征向量,然后结合具体问题,微调具体问题的模型后面几层。
语言模型训练:
输入:前面单词
输出:下一个单词
训练模型:
ELMO采用了典型的两阶段过程:
第一个阶段是利用语言模型进行预训练;
第二个阶段是在做下游任务时,从预训练网络中提取对应单词的网络各层的Word Embedding作为新特征补充到下游任务中。
上图展示的是其预训练过程,它的网络结构采用了双层双向LSTM,目前语言模型训练的任务目标是根据单词 W_i 的上下文去正确预测单词 W_i , W_i 之前的单词序列Context-before称为上文,之后的单词序列Context-after称为下文。图中左端的前向双层LSTM代表正方向编码器,输入的是从左到右顺序的除了预测单词外 W_i 的上文Context-before;右端的逆向双层LSTM代表反方向编码器,输入的是从右到左的逆序的句子下文Context-after;每个编码器的深度都是两层LSTM叠加。这个网络结构其实在NLP中是很常用的。使用这个网络结构利用大量语料做语言模型任务就能预先训练好这个网络,如果训练好这个网络后,输入一个新句子 Snew ,句子中每个单词都能得到对应的三个Embedding:最底层是单词的Word Embedding,往上走是第一层双向LSTM中对应单词位置的Embedding,这层编码单词的句法信息更多一些;再往上走是第二层LSTM中对应单词位置的Embedding,这层编码单词的语义信息更多一些。也就是说,ELMO的预训练过程不仅仅学会单词的Word Embedding,还学会了一个双层双向的LSTM网络结构,而这两者后面都有用。
使用:
输入Word Embedding,经过语言模型训练的网络得到新的特征向量,用于下游具体任务。
缺点:
LSTM并发求解能力差
LSTM特征抽取能力低于Transformer
4.3 GPT简介
GPT:GPT是“Generative Pre-Training”的简称,从名字看其含义是指的生成式的预训练。
GPT也采用两阶段过程:
第一个阶段是利用语言模型进行预训练
第二阶段通过Fine-tuning的模式解决下游任务。
下图展示了GPT的预训练过程,其实和ELMO是类似的,主要不同在于两点:
首先,特征抽取器不是用的RNN,而是用的Transformer,上面提到过它的特征抽取能力要强于RNN,这个选择很明显是很明智的;
其次,GPT的预训练虽然仍然是以语言模型作为目标任务,但是采用的是单向的语言模型,所谓“单向”的含义是指:语言模型训练的任务目标是根据 W_i 单词的上下文去正确预测单词 W_i , W_i 之前的单词序列Context-before称为上文,之后的单词序列Context-after称为下文。ELMO在做语言模型预训练的时候,预测单词 W_i 同时使用了上文和下文,而GPT则只采用Context-before这个单词的上文来进行预测,而抛开了下文。这个选择现在看不是个太好的选择,原因很简单,它没有把单词的下文融合进来,这限制了其在更多应用场景的效果,比如阅读理解这种任务,在做任务的时候是可以允许同时看到上文和下文一起做决策的。如果预训练时候不把单词的下文嵌入到Word Embedding中,是很吃亏的,白白丢掉了很多信息。
训练:
输入前面的单词,输出下一个单词,中间是Tranformer的Decoders+FFNN+Softmax
使用:将训练好的Decorders作为Encoders,输入句子,得到每个单词的特征向量,用于下游任务
上图展示了GPT在第二阶段如何使用:
首先,对于不同的下游任务来说,本来你可以任意设计自己的网络结构,现在不行了,你要向GPT的网络结构看齐,把任务的网络结构改造成和GPT的网络结构是一样的。然后,在做下游任务的时候,利用第一步预训练好的参数初始化GPT的网络结构,这样通过预训练学到的语言学知识就被引入到你手头的任务里来了,这是个非常好的事情。
再次,你可以用手头的任务去训练这个网络,对网络参数进行Fine-tuning,使得这个网络更适合解决手头的问题。就是这样。看到了么?这有没有让你想起最开始提到的图像领域如何做预训练的过程,这跟那个模式是一模一样的。
新问题:
对于NLP各种花样的不同任务,怎么改造才能靠近GPT的网络结构呢?
GPT论文给了一个改造施工图如上:
1)分类问题,不用怎么动,加上一个起始和终结符号即可;
2)句子关系判断问题,比如Entailment,两个句子中间再加个分隔符即可;
3)本相似性判断问题,把两个句子顺序颠倒下做出两个输入即可,这是为了告诉模型句子顺序不重要;
4)多项选择问题,则多路输入,每一路把文章和答案选项拼接作为输入即可。
从上图可看出,这种改造还是很方便的,不同任务只需要在输入部分施工即可。
优点:
采用了Tranformer替代LSTM,并行,特征提取能力强
缺点:
缺少ELMO的双向
缺乏炒作
4.4 BERT详解
BERT也是分两个阶段:
- 预训练:根据语言模型,训练一个提取特征的网络
- Fine-tuning:根据具体任务,微调最后几层参数
注意:BERT文章还提出了next sentence等概念,个人感觉非核心知识,可有可无,所以本文不介绍。
我们先介绍如何使用BERT,然后介绍如何训练BERT。
使用BERT
图为典型的使用BERT进行NLP分类的问题。
训练好BERT,输入句子每个单词的word Embedding,经过BERT得到优化后的每个单词的特征向量,然后经过Classifier进行分类。
BERT分BERT base和BERT large:
主要区别:在于encoder数目不一样
具体:
输入CLS开头,以及输入句子,经过多个Encoder,得到新的每个Word特征向量,其中Encoders就是Tranformer,Transformer具体参考之前介绍。
唯一不同在于多了一个CLS:它对应的输出特征向量可以用于分类问题
训练BERT:
GPT训练Tranformer是通过预测下一个单词实现,是单向,丢失了下游单词信息,BERT改进:MASK
BERT通过MASK其中某个单词,然后预测它,从而实现双向Transformer
输入带MASK的句子,输出MASK对应的单词,训练Tranformer
和GPT一样,对于NLP四大任务,BERT需要改造下游任务:
1)对于句子关系类任务,很简单,和GPT类似,加上一个起始和终结符号,句子之间加个分隔符即可。对于输出来说,把第一个起始符号对应的Transformer最后一层位置上面串接一个softmax分类层即可。
2)对于分类问题,与GPT一样,只需要增加起始和终结符号,输出部分和句子关系判断任务类似改造;
3)对于序列标注问题,输入部分和单句分类是一样的,只需要输出部分Transformer最后一层每个单词对应位置都进行分类即可。
从这里可以看出,上面列出的NLP四大任务里面,除了生成类任务外,Bert其它都覆盖到了,而且改造起来很简单直观。尽管Bert论文没有提,但是稍微动动脑子就可以想到,其实对于机器翻译或者文本摘要,聊天机器人这种生成式任务,同样可以稍作改造即可引入Bert的预训练成果。只需要附着在seq2seq结构上,encoder部分是个深度Transformer结构,decoder部分也是个深度Transformer结构,同时还包含一个encoder-decoder attention。根据任务选择不同的预训练数据初始化encoder和decoder即可。这是相当直观的一种改造方法。当然,也可以更简单一点,比如直接在单个Transformer结构上加装隐层产生输出也是可以的。不论如何,从这里可以看出,NLP四大类任务都可以比较方便地改造成Bert能够接受的方式。这其实是Bert的非常大的优点,这意味着它几乎可以做任何NLP的下游任务,具备普适性,这是很强的。
BERT成功原因我觉得有以下几点:
综合了各大方法的优点,然后都进行了改进
1)采用了Tranformer,这种超强的word Embedding到word特征向量的特征提取方法
2)利用Mask引入了双向语言模型
3)提出了解决NLP各大类问题的方法
BERT具有里程碑式的意义,Tranformer将逐步替代RNN,CNN在自然语言中的地位,NLP两阶段模型,双向语言模型训练和Fine Tuning将会得到普及,迁移学习可以称为现实。
虽然未来肯定还会有新的技术替代BERT,但是对现在来说,BERT开创了NLP的一个新时代。
留言