结合李宏毅老师机器学习2021——Transformer课程和网上查阅的资料,总结一下对Transformer的理解
Transformer是什么?
从宏观角度来看,Transformer是一种基于Self-Attention机制的Seq2seq模型(序列模型),是用于机器翻译的,由编码器和解码器组成(自己总结的)。所以在学习Transformer前,需要先弄明白Seq2seq、编码器 / 解码器、Self-Attention(见本人之前的csdn博客)是什么。
- Seq2seq模型:
这是一个序列到序列的模型,输入一个序列,输出另一个序列,通常可用于NLP任务,例如机器翻译、语音识别等等。这个Seq2seq模型包含了一个编码器和一个解码器(换言之,有编码器和解码器的模型就可以认为是Seq2seq模型的范畴)。因此呢,Seq2seq模型有很多种变形,例如编码器 / 解码器可以是RNN,LSTM、也可以是CNN,还可以是Self-Attention等等。
但是要特别注意,Seq2seq和RNN / LSTM等是不同层面的东西,Seq2seq模型专指输入和输出均为序列的模型,LSTM 等可以用作其编码器和解码器的一种实现方法。但 RNN / LSTM 并不是Seq2seq模型的子集,它们也可以用来做别的问题。 - 编码器 / 解码器:
所谓编码,就是将输入序列转化成一个固定长度的向量;解码,就是将之前生成的固定向量再转化成输出序列。具体实现的时候,编码器和解码器都不是固定的,可选的有RNN / BiRNN / GRU / LSTM等等都是可以的,你可以自由组合。比如说,你在编码时使用BiRNN,解码时使用RNN,或者在编码时使用RNN,解码时使用LSTM等等。(最基础的是编码解码都是RNN)
怎么理解Transformer的流程图?
Transformer虽好,但流程蛮复杂,如果去看明白这张图呢?
- 首先左边的是编码器,右边的是解码器。我们将一段序列(向量组)输入到编码器中。在输入时要注意加上位置信息(Positional Encoding)。这段向量组经过多头自注意力机制后输出新的向量组,然后将这个新输出的向量组与旧的输入的向量组相加(残差网络),相加后做一个层归一化(注意是层归一化)。然后在经过一个全连接层,并继续做Add & Norm。这就是编码器的任务。其实都很好理解,主要是得明白self-attention。
- 然后再看解码器。解码器与编码器是类似的。毕竟直觉上来说,编码器与解码器如果是镜像关系可能更容易train。首先我们将一个begin信号输入到解码器中,意思是“我要开始解码啦”,当然这个信号也需要加上Positonal Encoding,然后解码器每解出一个新的“码”,就将新的“码”当做输入,输送给解码器,进行解下一个码,就这么循环下去一直解就行。这里还有许多注意的细节,例如:
注意观察解码器比编码器中间多了一层。这一层的作用是用来接收此前编码器计算出来的 K 和 V 矩阵。其实这个很容易理解,我解码器是用来解编码器的,那我肯定要有编码器的信息呀。编码器的K和V矩阵代表了什么?K和V矩阵其实本质就是编码器的输入数据(因为通过输入数据计算出来的K和V矩阵),然后这个 K、V 矩阵与解码器中第一层Self- Attention的Q矩阵一起输入到中间的Self-Attention中。
另外还要注意,第一层的Self-Attention是Mask的,这个什么意思如果忘了去再看看李宏毅老师的PPT。
这篇博客比较好,可以作为参考:https://zhuanlan.zhihu.com/p/338817680
Transformer的优点?
- Transformer 与 RNN /LSTM 等不同,它可以比较好地并行训练。
- Transformer 与 CNN 不同(有一些是基于CNN的Seq2seq模型),尽管CNN也可以进行并行训练,但是它的内存占用很大,相反 Transformer 的矩阵维度较少。更重要的是,Transformer 可以处理变长的序列样本,而CNN不行。
备注:其实归根结底,这是 Self-Attention 相较于 RNN / LSTM / CNN 等传统模型的优点(因为Transformer是基于Self-Attention的) - Transformer 不像 RNN / LSTM / CNN 等模型一样,需要较强的 domain knowledge (领域知识),其几乎可以对任意非结构化数据(图片、文本、音频)成立。这个其实也很好理解,例如CNN是专门进行图像处理设计的,需要对图像的本质有很深刻的理解。
Transformer有关的其他问题
Transformer是如何处理可变长度数据的?
-
首先要明白数据的怎么表示的,比如我有一句话“我爱中国”,“我”这个向量是一个one-hot,“爱”这个向量也是one-hot,假设共有8000个常用汉字,那么就是一个8000维的独热向量。这四个字在一起就是一个向量组,这个向量组里包含了4个向量。
-
弄白了这个之后我们再看什么叫做可变长度数据?这个可变长度,变得是什么?答:变的是向量组的长度,而不是向量的维度。什么意思呢,就是那个8000维是不会变的(因为你每个向量都要做矩阵运算啊,Self-Attention里求KVQ啊,所以肯定维度得一样才行),但是向量的个数是可以任意的。可以是“我爱中国”,也可以是“我爱你中国”,都是OK的。
-
所以Transformer是可以处理可变长度的,但是RNN、CNN是固定长度的,是不可以输入任意多的向量的,输入向量的个数是被固定死的。
-
但是,这时候又有一个容易被误解的地方了。就是我们经常会看到一份程序中,假设有的句子是10个字,有的句子(最长的句子)是20个字,我们一般是以20个字为标准来处理的,那个10个字的,我们通过padding方法补0,补齐到20个字。OK,既然Transformer可以处理任意长度的,为啥还要把非任意长度的补齐呢?
因为我们往往是通过batch输入的啊!一下子输入一个batch,因此,同一个batch里的句子,必须要一样的长度,不同的batch的长度可以不同,同一个batch的长度得相同。这个是batch决定的!一定要搞清楚这一点。 -
这里再补充一点,如果是batch预测或者训练,要求batch内数据长度保持一致。一般有两种做法,一种是直接padding到固定长度(通常是512,bert里是512),多退少补,即超过最大长度就截断,不够的就补上一个标志位。这样的好处是实现简单,缺点是如果补标志位太多的话,有些效率低下。还有一种做法是每个batch padding到当前batch的最大长度,这样比较省资源,甚至可以做下按长度排序这种操作
Transformer中,为什么是 LayerNorm ,而不是 BatchNorm ?
-
先给出明确的答案,可以用BatchNorm,但是效果往往不如LayerNorm好、训练难度大。为什么呢?且为什么序列问题就用LayerNorm,图像问题大多用BatchNorm?
-
首先解释为什么LayerNorm效果比BatchNorm更好。这里面有两个原因:
第一,要从序列模型本质入手。比如说一个语言模型,我们关注的是一句话中的相似程度(或者叫差异程度),比如一句话说“我爱中华民族”,另一句话说“今天打王者又输了”,这两句话都在一个batch里,但是我们没有必要去讨论这两句话的联系,我们关心的是一句话不同token的内在联系。因此没必要去做BatchNorm,反而LayerNorm会更好。(总结来说,词之间的信息是储存在同一个句子里的。因而用LayerNorm更合理。)
第二,不同的数据样本可能尺寸并不一样,尽管一个batch中都是一样的长度。但是结合我们之前说的 “有的句子(最长的句子)是20个字,我们一般是以20个字为标准来处理的,那个10个字的,我们通过padding方法补0,补齐到20个字。” 因此一个Batch中对应位置的分量不一定有意义,它可能是padding的结果。虽然序列长度一致了,但是好多embedding是没有意义的,有意义的embedding不应该和它们的分布一致,如果BN会导致有意义的embedding损失信息,所以embedding你就自己和自己归一化吧。
-
其次解释为什么序列问题就用LayerNorm,图像问题大多用BatchNorm?
有了上面的基础后,这个也很好理解了,图像数据都是【B,C,W,H】排列的,不同数据样本在每个维度的每个位置都是有值的,这样不同的batch均值、方差都是有意义的。而不同的序列是通过padding补齐的,做batchnorm是是没有意义的。因此图像问题就是BN。
BERT是什么?
bert是一种预训练模型,首先要搞清楚这个概念。
bert论文全名是Bidirectional Encoder Representations from Transformers,不难发现,其模型结构是Transformer的Encoder层。因此它具有Transformer的性质,例如变长度输入(变的是向量组的长度,而不是向量的长度,参考上面有关Transformer的解释)
如何训练bert?
第一种方法:随机mask掉部分词汇,让机器去学习
为了解决只能利用单向信息的问题,BERT使用的是Mask语言模型而不是普通的语言模型。Mask语言模型有点类似与完形填空——给定一个句子,把其中某个词遮挡起来,让人猜测可能的词。这里会随机的Mask掉15%的词,然后让BERT来预测这些Mask的词,通过调整模型的参数使得模型预测正确的概率尽可能大,这等价于交叉熵的损失函数。这样的Transformer在编码一个词的时候会(必须)参考上下文的信息。
但是这有一个问题:在Pretraining Mask LM时会出现特殊的Token [MASK],但是在后面的fine-tuning时却不会出现,这会出现Mismatch的问题。因此BERT中,如果某个Token在被选中的15%个Token里,则按照下面的方式随机的执行:
- 80%的概率替换成[MASK],比如my dog is hairy → my dog is [MASK]
- 10%的概率替换成随机的一个词,比如my dog is hairy → my dog is apple
- 10%的概率替换成它本身,比如my dog is hairy → my dog is hairy
第二种方法:预测两个句子是否连接在一起(Next Sentence Prediction)
Next Sentence Prediction(NSP)的任务是判断句子B是否是句子A的下文。如果是的话输出’IsNext‘,否则输出’NotNext‘。训练数据的生成方式是从平行语料中随机抽取的连续两句话,其中50%保留抽取的两句话,它们符合IsNext关系,另外50%的第二句话是随机从预料中提取的,它们的关系是NotNext的。这个关系保存在图4中的[CLS]符号中。
后来证明这种方面没啥卵用,但是第一种方法很有用,有助于训练。
备注:
需要特别注意的是,bert在训练时用的是Transformer的Encoder+MLP,其中MLP作用是预测被掩盖的单词是什么。
在测试时只是用Encoder,没有MLP,根据不同的任务,再添加合适的MLP或者其他神经网络层。因为bert的本意只是通过编码器,学到句子间的语义编码信息,所以我们只需要在得到的语义编码信息基础上微调模型就行了,例如下图。