Transfomer

Transformer 原理

Transformer 是Google Brain 2017的提出的一篇工作,它针对RNN的弱点进行重新设计,解决了RNN效率问题和传递中的缺陷等,在很多问题上都超过了RNN的表现。Transfromer的基本结构如下图所示,它是一个N进N出的结构,也就是说每个Transformer单元相当于一层的RNN层,接收一整个句子所有词作为输入,然后为句子中的每个词都做出一个输出。但是与RNN不同的是,Transformer能够同时处理句子中的所有词,并且任意两个词之间的操作距离都是1,这么一来就很好地解决了上面提到的RNN的效率问题和距离问题。

在这里插入图片描述

Transformer的结构图,拆解开来,主要分为图上4个部分,其中最重要的就是2和3Encoder-Decoder部分,Transformer是一个基于Encoder-Decoder框架的模型。接下来我将按照1,2,3,4的顺序逐步介绍上图中Transformer的网络结构,这样既能够弄清楚结构原理,又能够方便理解Transformer模型的工作流程。

Transformer的inputs 输入

Transformer输入是一个序列数据,还是以上篇中提到的"Tom chase Jerry" 翻译成中文"汤姆追逐杰瑞"为例:
Encoder 的 inputs就是"Tom chase Jerry" 分词后的词向量。可以是任意形式的词向量,如word2vec,GloVe,one-hot编码。

在这里插入图片描述

假设上图中每一个词向量都是一个512维的词向量。

在这里插入图片描述

我们注意到,输入inputs embedding后需要给每个word的词向量添加位置编码positional encoding,为什么需要添加位置编码呢?

首先咱们知道,一句话中同一个词,如果词语出现位置不同,意思可能发生翻天覆地的变化,就比如:我欠他100W 和 他欠我100W。这两句话的意思一个地狱一个天堂。可见获取词语出现在句子中的位置信息是一件很重要的事情。但是咱们的Transformer 的是完全基于self-Attention地,而self-attention是不能获取词语位置信息地,就算打乱一句话中词语的位置,每个词还是能与其他词之间计算attention值,就相当于是一个功能强大的词袋模型,对结果没有任何影响。(一会儿在介绍Encoder的时候再详细说明)所以在我们输入的时候需要给每一个词向量添加位置编码。

在这里插入图片描述

问题又来了,这个positional encoding怎么获取呢?
1.可以通过数据训练学习得到positional encoding,类似于训练学习词向量,goole在之后的bert中的positional encoding便是由训练得到地。
2.《Attention Is All You Need》论文中Transformer使用的是正余弦位置编码。位置编码通过使用不同频率的正弦、余弦函数生成,然后和对应的位置的词向量相加,位置向量维度必须和词向量的维度一致。过程如上图,PE(positional encoding)计算公式如下:
在这里插入图片描述

解释一下上面的公式:
pos表示单词在句子中的绝对位置,pos=0,1,2…,例如:Jerry在"Tom chase Jerry"中的pos=2;dmodel表示词向量的维度,在这里dmodel=512;2i和2i+1表示奇偶性,i表示词向量中的第几维,例如这里dmodel=512,故i=0,1,2…255。
至于上面这个公式是怎么得来地,其实不重要,因为很有可能是作者根据经验自己造地,而且公式也不是唯一地,后续goole在bert中的positional encoding也没有再使用这种方法而是通过训练PE,说明这种求位置向量的方法还是存在一定问题地。
这里我就不做详细的介绍了,想要深究的朋友可以参考一下知乎上的这些回答:如何理解Transformer论文中的positional encoding,和三角函数有什么关系?

为什么是将positional encoding与词向量相加,而不是拼接呢?

拼接相加都可以,只是本身词向量的维度512维就已经蛮大了,再拼接一个512维的位置向量,变成1024维,这样训练起来会相对慢一些,影响效率。两者的效果是差不多地,既然效果差不多当然是选择学习习难度较小的相加了。

在这里插入图片描述

Transformer 的 Decoder的输入与Encoder的输出处理方法步骤是一样地,一个接受source数据,一个接受target数据,对应到上面例子里面就是:Encoder接受英文"Tom chase Jerry",Decoder接受中文"汤姆追逐杰瑞"。只是在有target数据时也就是在进行有监督训练时才会接受Outputs Embedding,进行预测时则不会接收。

至此,Transformer的第一块输入部分已经讲解完了,接下来就要进入重点部分Encoder和Decoder了。

Transformer的Encoder

在这里插入图片描述

看上图第2部分 Encoder block。Encoder block是由6个encoder堆叠而成,Nx=6。上图2中的灰框部分就是一个encoder的内部结构,从图中我们可以看出一个encoder由Multi-Head Attention 和 全连接神经网络Feed Forward Network构成。
Multi-Head Attention:

在这里插入图片描述

首先回顾一下self-attention,假如输入序列是"Thinking Machines",x1,x2就是对应地"Thinking"和"Machines"添加过位置编码之后的词向量,然后词向量通过三个权值矩阵WQ,WK,W^V转变成为计算Attention值所需的Query,Keys,Values向量。

Alt

因为咱们再实际使用中,每一个样本,也就是每一条序列数据都是以矩阵的形式输入地,故可以看到上图中,X矩阵是由"Tinking"和"Machines"词向量组成的矩阵,然后跟过变换得到Q,K,V。假设词向量是512维,X矩阵的维度是(2,512),WQ,WK,W^V均是(512,64)维,得到的Query,Keys,Values就都是(2,64)维。

得到Q,K,V之后,接下来就是计算Attention值了。
步骤1: 输入序列中每个单词之间的相关性得分,上篇中说过计算相关性得分可以使用点积法,就是用Q中每一个向量与K中每一个向量计算点积,具体到矩阵的形式:score = Q*K^T,socre是一个(2,2)的矩阵
步骤2: 对于输入序列中每个单词之间的相关性得分进行归一化,归一化的目的主要是为了训练时梯度能够稳定。score = score/sqrt{d_k},dk就是K的维度,以上面假设为例,dk=64
步骤3: 通过softmax函数,将每个单词之间的得分向量转换成[0,1]之间的概率分布,同时更加凸显单词之间的关系。经过softmax后,score转换成一个值分布在[0,1]之间的(2,2)α概率分布矩阵
步骤4: 根据每个单词之间的概率分布,然后乘上对应的Values值,α与V进行点积,Z=softmax(score)⋅V,V的为维度是(2,64),(2,2)x(2,64)最后得到的Z是(2,64)维的矩阵
整体的计算图如下:

Alt

说了这么多好像都只是在说self-attention,那么Multi-Head Attention呢?

Alt

Multi-Head Attention 很简单,就是在self-attention的基础上,对于输入的embedding矩阵,self-attention只使用了一组WQ,WK,W^V来进行变换得到Query,Keys,Values。而Multi-Head Attention使用多组WQ,WK,WV得到多组Query,Keys,Values,然后每组分别计算得到一个Z矩阵,最后将得到的多个Z矩阵进行拼接。Transformer里面是使用了8组不同的WQ,WK,WV。

Alt

从上图中可以看到,在经过Multi-Head Attention得到矩阵Z之后,并没有直接传入全连接神经网络FNN,而是经过了一步:Add&Normalize。

Add&Normalize:

Add

Add,就是在Z的基础上加了一个残差块X,加入残差块X的目的是为了防止在深度神经网络训练中发生退化问题,退化的意思就是深度神经网络通过增加网络的层数,Loss逐渐减小,然后趋于稳定达到饱和,然后再继续增加网络层数,Loss反而增大。可能看到这里,小朋友你一定有很多问号???为什么深度神经网络会发生退化,为什么添加残差块能够防止退化问题,残差块又是什么?这就牵扯到ResNet残差神经网络的知识了,既然是史上最小白系列,坚决不做标题党,一定把每个问题都解释清楚!

ResNet 残差神经网络:

首先解答第一个问题,为什么深度神经网络会发生退化?
举个例子:假如某个神经网络的最优网络层数是18层,但是我们在设计的时候并不知道到底多少层是最优解,本着层数越深越好的理念,我们设计了32层,那么32层神经网络中有14层其实是多余地,我们要想达到18层神经网络的最优效果,必须保证这多出来的14层网络必须进行恒等映射,恒等映射的意思就是说,输入什么,输出就是什么,可以理解成F(x)=x这样的函数,因为只有进行了这样的恒等映射咱们才能保证这多出来的14层神经网络不会影响我们最优的效果。
但现实是神经网络的参数都是训练出来地,要想保证训练出来地参数能够很精确的完成F(x)=x的恒等映射其实是很困难地。多余的层数较少还好,对效果不会有很大影响,但多余的层数一多,可能结果就不是很理想了。这个时候大神们就提出了ResNet 残差神经网络来解决神经网络退化的问题。

残差块是什么?

Alt

上图就是构造的一个残差块,可以看到X是这一层残差块的输入,也称作F(X)为残差,X为输入值,F(X)是经过第一层线性变化并激活后的输出,该图表示在残差网络中,第二层进行线性变化之后激活之前,F(X)加入了这一层输入值X,然后再进行激活后输出。在第二层输出值激活前加入X,这条路径称作shortcut连接。

为什么添加了残差块能防止神经网络退化问题呢?
咱们再来看看添加了残差块后,咱们之前说的要完成恒等映射的函数变成什么样子了。是不是就变成h(X)=F(X)+X,我们要让h(X)=X,那么是不是相当于只需要让F(X)=0就可以了,这里就巧妙了!神经网络通过训练变成0是比变成X容易很多地,因为大家都知道咱们一般初始化神经网络的参数的时候就是设置的[0,1]之间的随机数嘛。所以经过网络变换后很容易接近于0。举个例子:

Alt

假设该网络只经过线性变换,没有bias也没有激活函数。我们发现因为随机初始化权重一般偏向于0,那么经过该网络的输出值为[0.6 0.6],很明显会更接近与[0 0],而不是[2 1],相比与学习h(x)=x,模型要更快到学习F(x)=0。
并且ReLU能够将负数激活为0,过滤了负数的线性变化,也能够更快的使得F(x)=0。这样当网络自己决定哪些网络层为冗余层时,使用ResNet的网络很大程度上解决了学习恒等映射的问题,用学习残差F(x)=0更新该冗余层的参数来代替学习h(x)=x更新冗余层的参数。
这样当网络自行决定了哪些层为冗余层后,通过学习残差F(x)=0来让该层网络恒等映射上一层的输入,使得有了这些冗余层的网络效果与没有这些冗余层的网络效果相同,这样很大程度上解决了网络的退化问题。

到这里,关于Add中为什么需要加上一个X,要进行残差网络中的shortcut你清楚了吗?Transformer中加上的X也就是Multi-Head Attention的输入,X矩阵。

Normalize

为什么要进行Normalize呢?
在神经网络进行训练之前,都需要对于输入数据进行Normalize归一化,目的有二:1,能够加快训练的速度。2.提高训练的稳定性。

为什么使用Layer Normalization(LN)而不使用Batch Normalization(BN)呢?

在这里插入图片描述

先看图,LN是在同一个样本中不同神经元之间进行归一化,而BN是在同一个batch中不同样本之间的同一位置的神经元之间进行归一化。
BN是对于相同的维度进行归一化,但是咱们NLP中输入的都是词向量,一个300维的词向量,单独去分析它的每一维是没有意义地,在每一维上进行归一化也是适合地,因此这里选用的是LN。

在这里插入图片描述
Feed-Forward Networks

全连接层公式如下:
FFN(x)=max(0,xW_1+b_1)W_2+b_2

这里的全连接层是一个两层的神经网络,先线性变换,然后ReLU非线性,再线性变换。
这里的x就是我们Multi-Head Attention的输出Z,还是引用上面的例子,那么Z是(2,64)维的矩阵,假设W1是(64,1024),其中W2与W1维度相反(1024,64),那么按照上面的公式:
FFN(Z)=(2,64)x(64,1024)x(1024,64)=(2,64),我们发现维度没有发生变化,这两层网络就是为了将输入的Z映射到更加高维的空间中(2,64)x(64,1024)=(2,1024),然后通过非线性函数ReLU进行筛选,筛选完后再变回原来的维度。

然后经过Add&Normalize,输入下一个encoder中,经过6个encoder后输入到decoder中,至此Transformer的Encoder部分就全部介绍完了,搞懂了Encoder那么Decoder就so easy啦,基本上结构和Encoder差不多,接下来咱们就进入Decoder部分吧

Transformer的Decoder

在这里插入图片描述

看上图第3部分 Decoder block。Decoder block也是由6个decoder堆叠而成,Nx=6。上图3中的灰框部分就是一个decoder的内部结构,从图中我们可以看出一个decoder由Masked Multi-Head Attention,Multi-Head Attention 和 全连接神经网络FNN构成。比Encoder多了一个Masked Multi-Head Attention,其他的结构与encoder相同,那么咱们就先来看看这个Masked Multi-Head Attention。

Transformer Decoder的输入

Decoder的输入分为两类:
一种是训练时的输入,一种是预测时的输入。
训练时的输入就是已经对准备好对应的target数据。例如翻译任务,Encoder输入"Tom chase Jerry",Decoder输入"汤姆追逐杰瑞"。
预测时的输入,一开始输入的是起始符,然后每次输入是上一时刻Transformer的输出。例如,输入"“,输出"汤姆”,输入"汤姆",输出"汤姆追逐",输入"汤姆追逐",输出"汤姆追逐杰瑞",输入"汤姆追逐杰瑞",输出"汤姆追逐杰瑞"结束。

Masked Multi-Head Attention

与Encoder的Multi-Head Attention计算原理一样,只是多加了一个mask码。mask 表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer 模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。为什么需要添加这两种mask码呢?

1.padding mask
什么是 padding mask 呢?因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是给在较短的序列后面填充 0。但是如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。
具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过 softmax,这些位置的概率就会接近0!

2.sequence mask
sequence mask 是为了使得 decoder 不能看见未来的信息。对于一个序列,在 time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t 时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t 之后的信息给隐藏起来。这在训练的时候有效,因为训练的时候每次我们是将target数据完整输入进decoder中地,预测时不需要,预测的时候我们只能得到前一时刻预测出的输出。
那么具体怎么做呢?也很简单:产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。

上面可能忘记说了,在Encoder中的Multi-Head Attention也是需要进行mask地,只不过Encoder中只需要padding mask即可,而Decoder中需要padding mask和sequence mask。OK除了这点mask不一样以外,其他的部分均与Encoder一样啦~

Add&Normalize也与Encoder中一样,接下来就到了Decoder中第二个Multi-Head Attention,这个Multi-Head Attention又与Encoder中有一点点不一样。

基于Encoder-Decoder 的Multi-Head Attention
Encoder中的Multi-Head Attention是基于Self-Attention地,Decoder中的第二个Multi-Head Attention就只是基于Attention,它的输入Quer来自于Masked Multi-Head Attention的输出,Keys和Values来自于Encoder中最后一层的输出。

跟我一样的牛角尖型选手可能又要发问啦,为啥Decoder中要搞两个Multi-Head Attention呢?
我个人理解是第一个Masked Multi-Head Attention是为了得到之前已经预测输出的信息,相当于记录当前时刻的输入之间的信息的意思。第二个Multi-Head Attention是为了通过当前输入的信息得到下一时刻的信息,也就是输出的信息,是为了表示当前的输入与经过encoder提取过的特征向量之间的关系来预测输出。

经过了第二个Multi-Head Attention之后的Feed Forward Network与Encoder中一样,然后就是输出进入下一个decoder,如此经过6层decoder之后到达最后的输出层。

Transformer的输出

在这里插入图片描述
Output如图中所示,首先经过一次线性变换,然后Softmax得到输出的概率分布,然后通过词典,输出概率最大的对应的单词作为我们的预测输出。

Transformer 工作流程

ransformer的工作流程就是上面介绍的每一个子流程的拼接

  • 输入的词向量首先叠加上Positional Encoding,然后输入至Transformer内
  • 每个Encoder Transformer会进行一次Multi-head self attention->Add & Normalize->FFN->Add & Normalize流程,然后将输出输入至下一个Encoder中
  • 最后一个Encoder的输出将会作为memory保留
  • 每个Decoder Transformer会进行一次Masked Multi-head self attention->Multi-head self attention->Add & Normalize->FFN->Add & Normalize流程,其中Multi-head self attention时的K、V至来自于Encoder的memory。根据任务要求输出需要的最后一层Embedding。
  • Transformer的输出向量可以用来做各种下游任务

GitHub链接:https://github.com/harvardnlp/a

transfomer优缺点

Transformer虽然好,但它也不是万能地,还是存在着一些不足之处,接下来就来介绍一下它的优缺点:
优点:
1.效果好
2.可以并行训练,速度快
3.很好地解决了长距离依赖的问题
缺点:
1.完全基于self-attention,对于词语位置之间的信息有一定的丢失,虽然加入了positional encoding来解决这个问题,但也还存在着可以优化的地方。

Transformer是非常有潜力的模型,在Transformer基础上后来又衍生出来了BERT和GPT这两个NLP神器,而且依旧还存在着许多可以优化的地方。目前NLP在工业上的应用远不及CV广,但是自然语言是人类文明得以延续的重要的信息。没有文字,怎么回首古人的发展历史,没有语言,人类社会又怎么能够和谐运转,你看到的任何图片,听到的任何话语都在大脑里转换成里你自己能理解地文字信息,语言信息,所以NLP的前景依旧是无比巨大地。这是最好的时代,正因为NLP还一直处于探索阶段,所以现在开始学习仍旧不晚,史上最小白系列也写了几期了,我会一直写下去地,希望史上最小白系列能够对于初入NLP的同学有所帮助吧。

GPT(Generative Pre-Training)

(原文链接:https://zhuanlan.zhihu.com/p/69290203)

GPT(Generative Pre-Training),是OpenAI在2018年提出的模型,利用Transformer模型来解决各种自然语言问题,例如分类、推理、问答、相似度等应用的模型。GPT采用了Pre-training + Fine-tuning的训练模式,使得大量无标记的数据得以利用,大大提高了这些问题的效果。

GPT就是利用Transformer进行自然语言各种任务的尝试之一,主要有以下三个要点

  • Pre-Training的方式
  • 单向Transformer模型
  • Fine-Tuning与不同输入数据结构的变化

如果已经理解了Transformer的原理,那么只需要再搞懂上面的三个内容就能够对GPT有更深的认识。

Pre-Training 训练方式

很多机器学习任务都需要带标签的数据集作为输入完成。但是我们身边存在大量没有标注的数据,例如文本、图片、代码等等。标注这些数据需要花费大量的人力和时间,标注的速度远远不及数据产生的速度,所以带有标签的数据往往只占有总数据集很小的一部分。随着算力的不断提高,计算机能够处理的数据量逐渐增大。如果不能很好利用这些无标签的数据就显得很浪费。

所以半监督学习和预训练+微调的二阶段模式整变得越来越受欢迎。最常见的二阶段方法就是Word2Vec,使用大量无标记的文本训练出带有一定语义信息的词向量,然后将这些词向量作为下游机器学习任务的输入,就能够大大提高下游模型的泛化能力。

但是Word2Vec有一个问题,就是单个单词只能有一个Embedding。这样一来,一词多义就不能很好地进行表示。

ELMo首先想到了在预训练阶段为每个词汇集其上下文信息,使用的是基于bi-LSTM的语言模型给词向量带上上下文语义信息:

img

上式分别代表了左右两向的LSTM-RNN,他们共享输入的词向量X以及RNN各层权重S,也就是使用双向RNN两向的输出,来同时预测下一个单词(右向的下一个,左向的上一个),具体结构如下图所示:

img

但ELMo使用的是RNN来完成语言模型的预训练,那么如何使用Transformer来完成预训练呢?

单向Transformer结构

OpenAI GPT采用了单向Transformer完成了这项预训练任务。

img

什么是单向Transformer?在Transformer的文章中,提到了Encoder与Decoder使用的Transformer Block是不同的。在Decoder Block中,使用了Masked Self-Attention,即句子中的每个词,都只能对包括自己在内的前面所有词进行Attention,这就是单向Transformer。GPT使用的Transformer结构就是将Encoder中的Self-Attention替换成了Masked Self-Attention,具体结构如下图所示:

img

由于采用的是单向的Transformer,只能看到上文的词,所以语言模型为:

img

而训练的过程其实非常的简单,就是将句子n个词的词向量(第一个为)加上Positional Encoding后输入到前面提到的Transfromer中,n个输出分别预测该位置的下一个词(预测句子中的第一个词,最后一个词的预测结果不用于语言模型的训练)。

img

由于使用了Masked Self-Attention,所以每个位置的词都不会“看见”后面的词,也就是预测的时候是看不见“答案”的,保证了模型的合理性,这也是为什么OpenAI采用了单向Transformer的原因。

Fine-Tuning与不同输入数据结构的变化

接下来就进入模型训练的第二步,运用少量的带标签数据对模型参数进行微调。

上一步中最后一个词的输出我们没有用到,在这一步中就要使用这一个输出来作为下游监督学习的输入。

img

img

为避免Fine-Tuning使得模型陷入过拟合,文中还提到了辅助训练目标的方法,类似于一个多任务模型或者半监督学习。具体方法就是在使用最后一个词的预测结果进行监督学习的同时,前面的词继续上一步的无监督训练,使得最终的损失函数成为:

img

针对不同任务,需要修改输入数据的格式:

img

  • Classification:对于分类问题,不需要做什么修改

  • Entailment:对于推理问题,可以将先验与假设使用一个分隔符分开

  • Similarity:对于相似度问题,由于模型是单向的,但相似度与顺序无关。所以需要将两个句子顺序颠倒后两次输入的结果相加来做最后的推测

  • Multiple Choice:对于问答问题,则是将上下文、问题放在一起与答案分隔开,然后进行预测

    Post Scriptum

    OpenAI GPT在Transformer的运用和二阶段训练方式上做出了很好的探索,也取得了非常不错的效果,为后面的BERT铺平了道路。

BERT(Bidirectional Encoder Representation from Transformer)双向二阶段训练模型

Google Brain在2018年提出的基于Transformer的自然语言表示框架。是一提出就大火的明星模型。BERT与GPT一样,采取了Pre-training + Fine-tuning的训练方式,在分类、标注等任务下都获得了更好的效果。

BERT与GPT非常的相似,都是基于Transformer的二阶段训练模型,都分为Pre-Training与Fine-Tuning两个阶段,都在Pre-Training阶段无监督地训练出一个可通用的Transformer模型,然后在Fine-Tuning阶段对这个模型中的参数进行微调,使之能够适应不同的下游任务。

虽然BERT与GPT看上去非常的相似,但是它们的训练目标和模型结构和使用上还是有着些许的不同:

  • GPT采用的是单向的Transformer,而BERT采用的是双向的Transformer,也就是不用进行Mask操作;
  • 使用的结构的不同,直接导致了它们在Pre-Training阶段训练目标的不同;

双向Transformer

BERT采用的是不经过Mask的Transformer,也就是与Transformer文章中的Encoder Transformer结构完全一样:

GPT中因为要完成语言模型的训练,也就要求Pre-Training预测下一个词的时候只能够看见当前以及之前的词,这也是GPT放弃原本Transformer的双向结构转而采用单向结构的原因。

BERT为了能够同时得到上下文的信息,而不是像GPT一样完全放弃下文信息,采用了双向的Transformer。但是这样一来,就无法再像GPT一样采用正常的语言模型来预训练了,因为BERT的结构导致每个Transformer的输出都可以看见整个句子的,无论你用这个输出去预测什么,都会“看见”参考答案,也就是“see itself”的问题。ELMo中虽然采用的是双向RNN,但是两个RNN之间是独立的,所以可以避免see itself的问题。

img

Pre-Training阶段

那么BERT想用双向的Transformer模型,就不得不放弃GPT中所采用的语言模型来作为预训练的目标函数。取而代之的,BERT提出了一种完全不同的预训练方法。

  • Masked Language Model (MLM)

在Transformer中,我们即想要知道上文的信息,又想要知道下文的信息,但同时要保证整个模型不知道要预测词的信息,那么就干脆不要告诉模型这个词的信息就可以了。也就是说,BERT在输入的句子中,挖掉一些需要预测的词,然后通过上下文来分析句子,最终使用其相应位置的输出来预测被挖掉的词。这其实就像是在做完形填空 (Cloze)一样。

但是,直接将大量的词替换为标签可能会造成一些问题,模型可能会认为只需要预测相应的输出就行,其他位置的输出就无所谓。同时Fine-Tuning阶段的输入数据中并没有标签,也有数据分布不同的问题。为了减轻这样训练带来的影响,BERT采用了如下的方式:

  1. 输入数据中随机选择15%的词用于预测,这15%的词中,
  2. 80%的词向量输入时被替换为
  3. 10%的词的词向量在输入时被替换为其他词的词向量
  4. 另外10%保持不动

这样一来就相当于告诉模型,我可能给你答案,也可能不给你答案,也可能给你错误的答案,有的地方我会检查你的答案,没的地方我也可能检查你的答案,所以标签对你来说没有什么特殊意义,所以无论如何,你都要好好预测所有位置的输出。

  • Next Sentence Prediction (NSP)

BERT还提出了另外一种预训练方式NSP,与MLM同时进行,组成多任务预训练。这种预训练的方式就是往Transformer中输入连续的两个句子,左边的句子前面加上一个标签,它的输出被用来判断两个句子之间是否是连续上下文关系。采用负采样的方法,正负样本各占50%。

为了区分两个句子的前后关系,BERT除了加入了Positional Encoding之外,还两外加入了一个在预训练时需要学习的Segment Embedding来区分两个句子。这样一来,BERT的输入就由词向量、位置向量、段向量三个部分相加组成。此外,两个句子之间使用标签予以区分。

img

整体Pre-Training的示意图如下:

img

Fine-Tuning阶段

BERT的Fine-Tuning阶段和GPT没有太大区别。因为采用了双向的Transformer所以放弃了GPT在Fine-Tuning阶段使用的辅助训练目标,也就是语言模型。此外就是将分类预测用的输出向量从GPT的最后一个词的输出位置改为了句子开头的位置了。不同的任务Fine-Tuning的示意图如下:

img

Post Scriptum

个人认为,BERT只是GPT模型的一种trade-off,为了在两个阶段都能够同时获得句子上下文的信息,使用了双向Transformer模型。但是为此却要付出失去传统语言模型的代价,转而采用MLM+NSP这种更加复杂的方式进行预训练。

一些变体

任务模型——MT-DNN

MT-DNN (Multi-Task Deep Neural Networks) 依然采用了BERT的二阶段训练方法以及双向Transformer。在Pre-Training阶段,MT-DNN与BERT几乎完全一样,但是在Fine-Tuning阶段,MT-DNN采用了多任务的微调方式。同时采用Transformer输出的上下文Embedding进行单句分类、文本对相似度、文本对分类以及问答等任务的训练。整个结构如下图所示:

img

单向通用模型——GPT-2

GPT-2继续沿用了原来在GPT种使用的单向Transformer模型,而这篇文章的目的就是尽可能利用单向Transformer的优势,做一些BERT使用的双向Transformer所做不到的事。那就是通过上文生成下文文本。

GPT-2的想法就是完全舍弃Fine-Tuning过程,转而使用一个容量更大、无监督训练、更加通用的语言模型来完成各种各样的任务。我们完全不需要去定义这个模型应该做什么任务,因为很多标签所蕴含的信息,就存在于语料当中。就像一个人如果博览群书,自然可以根据看过的内容轻松的做到自动摘要、问答、续写文章这些事。

严格来说GPT-2可能不算是一个多任务模型,但是它确实使用相同的模型、相同的参数完成了不同的任务。那么GPT-2是怎么使用语言模型完成多种任务的呢?

通常我们针对特定任务训练的专用模型,给定输入,就可以返回这个任务相应的输出,也就是

img

那么如果我们希望设计一个通用的模型,这个模型在给定输入的同时还需要给定任务类型,然后根据给定输入与任务来做出相应的输出,那么模型就可以表示成下面这个样子

img

就好像原来我需要翻译一个句子,需要专门设计一个翻译模型,想要问答系统需要专门设计一个问答模型。但是如果一个模型足够聪明,并且能够根据你的上文生成下文,那我们就可以通过在输入中加入一些标识符就可以区分各种问题。比如可以直接问他:(‘自然语言处理’, 中文翻译)来得到我们需要的结果Nature Language Processing。在我的理解中GPT-2更像是一个无所不知的问答系统,通过告知一个给定任务的标识符,就可以对多种领域的问答、多种任务做出合适的回答。GPT-2满足零样本设置 (zero-shot setting), 在训练的过程中不需要告诉他应该完成什么样的任务,预测是也能给出较为合理的回答。

那么GPT-2为了做到上面这些要求,做了哪些工作呢?

  1. 拓宽并加大数据集

首先就是要让模型博览群书,如果训练样本都不够多,那还怎么进行推理?前面的工作都是针对某一个特定问题的,所以数据集都比较片面。GPT-2收集了一个规模更大、范围更广的数据集。同时呢,要保证这个数据集的质量,保留那些拥有高质量内容的网页。最终组成了一个800万个文本,40G的数据集WebText。

  1. 扩大网络容量

书多了脑袋容量也得带一些要不然记不住书里的东西。为了提高网络的容量,使其拥有更强的学习潜力,GPT-2将Transformer堆叠的层数增加到48层,隐层的维度为1600,参数量达到了15亿。

  1. 调整网络结构

GPT-2将词汇表提升到50257,最大的上下文大小 (context size) 从GPT的512提升到了1024,batchsize从512提升为1024。此外还对Transformer做出了小调整,标准化层放到没每个sub-block之前,最后一个Self-attention后又增加了一个标准化层;改变了残差层的初始化方法等等。

Post Scriptum

GPT-2其实最惊人的是其极强的生成能力,而如此强大的生成能力主要还是要归功于其数据质量以及惊人参数量和数据规模。GPT-2的参数量大到用于实验的模型都还处于欠拟合状态,如果接着训练,效果还能进一步提升。

总结

总上面这些关于Transformer工作的发展中,我也整理出了一些关于深度学习发展趋势的个人心得:

  1. 有监督模型向半监督甚至无监督方向发展

数据的规模的增长速度远远超过了数据的标注速度,这也就导致了大量无标签数据的产生。这些无标签的数据并非没有价值,相反,如果找到合适的“炼金术”,将可以从这些海量的数据中获取意想不到的价值。如何利用上这些无标签的数据来改善任务的表现变成了一个越来越无法轻视的问题。

  1. 从少量数据复杂模型到大量数据简单模型

深度神经网络的拟合能力非常的强大,一个简单的神经网络模型就足以拟合任何函数。但无奈使用越简单的网络结构完成同一个任务,对数据量的要求也更高。数据量越是上升,数据质量越是提高,往往对模型的要求就会越会降低。数据量越大,模型就越容易捕捉到符合真实世界分布的特征。Word2Vec就是一个例子,它所使用的目标函数非常的简单,但是由于使用了大量的文本,于是训练出的词向量中就包含了许多有趣的特性。

  1. 从专用模型向通用模型发展

GPT、BERT、MT-DNN、GPT-2都使用了经过预训练的通用模型来继续进行下游的机器学习任务,并不需要对模型本身再做太多的修改。如果一个模型的表达能力足够的强,训练时候使用的数据量足够的大,那么模型的通用性就会更强,就不需要针对特定的任务做太多的修改。最极端的情况就像是GPT-2这个样子,训练时甚至完全不需要知道后续的下游任务是什么,就能够训练出一个通用的多任务模型。

  1. 对数据的规模和质量提高

GPT、BERT、MT-DNN、GPT-2虽然先后刷榜,但是我认为成绩的提升中,数据规模的提升占有比结构调整更大的比重。随着模型的通用化和简单化,为提升模型的性能,今后更多的注意力将会从如何设计一个复杂、专用的模型转移到如何获取、清洗、精化出质量更加出众的、大量的数据上。数据的处理方式调整的作用将会大于模型结构调整的作用。

综上所述,DL竞赛迟早要成为大厂间拼资源、拼算力的较量。可能几年内就会出现一个新的课题:绿色AI,低碳AI,可持续AI。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

healed萌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值