注意力机制能够学习输入序列的不同部分的相关性,从而使模型能够更好地理解和处理输入信息。
今天就让我们把它拆解开看一下它是如何运行的。
Transformer是在这篇论文中提出的:https://arxiv.org/abs/1706.03762
官方版TensorFlow实现:https://github.com/tensorflow/tensor2tensor
哈佛大学NLP组Pytorch实现:http://nlp.seas.harvard.edu/2018/04/03/attention.html
在本文中,我们会逐个概念进行介绍,希望能帮助没接触过Transformer的人能够更容易的理解。
从整体看
我们先把整个Transformer模型看作是一个黑盒。在机器翻译中,它可以把句子从一种语言翻译成另一种语言。
打开这个黑盒,我们首先可以看到一个编码器(encoder)模块和一个解码器(decoder)模块,以及二者之间存在某种关联。
再往近看一下,编码器模块是6个encoder组件堆在一起,同样解码器模块也是6个decoder组件堆在一起。(为什么选6个呢?没有什么原因,论文原文就是这么写的,你也可以换成别的层数)
6个编码器组件的结构是相同的(但是他们之间的权重是不共享的),每个编码器都可以分为2个子层。
编码器的输入首先会进入一个自注意力层,这个注意力层的作用是:当要编码某个特定的词汇的时候,它会关注句子中的其他词汇。之后会进行详细讲解。
自注意力层的输出会传递给一个前馈神经网络,进行非线性变换,增加模型的表达能力和学习能力。
解码器组件也含有前面编码器中提到的两个层,区别在于这两个层之间还夹了一个注意力层,多出来的这个自注意力层的作用是让解码器能够注意到输入句子中相关的部分(和seq2seq中的attention一样的作用)。
注意,对于一些只有解码器的模型,例如GPT,就没有Encoder-Decoder Attention。
图解张量
现在我们已经了解了模型的主要结构。接下来我们要看张量或者向量是如何在这些组件之间流动的,也就是在一个已经训练好的Transformer模型中,输入是怎么变为输出的呢?
与其它NLP任务一样,我们首先需要把输入文本转换成Token,然后将每个Token通过词嵌入(embedding)转化为对应的向量。
注意,将token转换成词嵌入向量是通过一个词嵌入矩阵完成的,通常也包括一个位置矩阵,对于一些大模型,例如ChatGPT,Bert等,它们通常会提供预训练好的词嵌入矩阵和位置矩阵,以及相应的tokenization方法和字典,这样能保证训练和推理时使用相同的tokenization方法和字典,这样才能保证输入和输出的一致性。
在原文中每个词的嵌入向量是512维,这里为了便于理解,就用这几个格子进行表示。
最底下的那个编码器接收的是嵌入向量,之后的编码器接收的是前一个编码器的输出。
注意,使用不同的词嵌入方法,词嵌入向量的维度也是不一样的。
Word2Vec 中 Skip-Gram 和 CBOW 模型词向量的默认维度是100或300维。
GloVe 词向量常见的维度有50维、100维、200维和300维。
BERT 中词向量的维度等于其transformer block的隐层大小,通常是768或1024。
ELMo 使用双层LSTM结构学习词向量,每个LSTM输出向量的维度不同,最终拼接为1024维。
输入词的个数也是个超参数,一般来说是训练集中最长的那个句子的长度。
GPT1:512个单词
GPT2:1024个单词
GPT3:2048个单词
ChatGPT:4096个单词
当我们的输入序列经过词嵌入之后得到的向量会依次通过编码器组件中的两