Transformer详解
前言
在17年,自然语言处理领域还在被RNN统治,当时的seq2seq任务还是用带encoder-decoder结构的RNN。然而RNN天然具有一个缺点:计算效率低。
随后的transformer也是encoder-decoder结构,但是其中信息关联采用了attention机制,而不是RNN的循环机制。
transformer一经提出,就横扫了以往的各种RNN变体,随后,人工智能社区陷入了万物transformer的时代,甚至引领了cv领域一段时间。
随后因为transformer(实际上是其中的attention)计算效率高,能极大缩短训练时间,大公司开始搜集更多的数据,用更多的算力,去训练更大的transformer,结果不经意间开启了大模型时代。目前的LLM几乎都是transformer的变体,通过学习transformer来入门大模型是很自然的。
这篇笔记从以下几个方面详细介绍transformer:
- 什么是seq2seq?
- 什么是attention,attention到底比RNN好在哪?
- 把transformer看成黑盒,训练任务是什么?
- transformer模型结构:
- word embedding && positional embedding
- self-attention && multi-head attention && cross attention
- layer normalization
- FFN|MLP
- 论文中的一些笔记
背景
什么是seq2seq?
在现实世界,有一种场景,输入一个长度为\(l_i\)的序列,输出一个长度\(l_j\)的序列。
在NLP中,一段话按照单词为单位转换成一个序列。
例如,翻译任务:”机/器/学/习“ -> ”machine/learning“,长度为4的序列被翻译成了长度为2的序列;或者对话,”太/阳/从/哪/边/升/起“->”东/边“,输入长度为7的序列,输出长度2的序列。
这类任务就被称为seq2seq任务,这类模型也可以称为seq2seq模型。
为什么要划分出这类任务,自然是因为传统的模型不能处理不等长度的序列。简单说明一下,典型的神经网络如下图,这里把每个单词变成一个数值\(x_i\),要训练的参数是输入结点和中间结点之间的权重\(w_{ij}\)。如果输入结点增加,就会多出来一些未知参数。
为了解决这个问题,不把单词看成数值,而是变成固定长度\(d\)的向量\(\bold{x}_i\)。这样就可以把一段\(l\)个单词的句子看成\(X=[\bold{x}_1,...,\bold{x}_{l}]^T \in R^{l\times d}\),然后全连接层的权重就是\(W^{d\times d}\),这样全连接层就是每个单词(一个向量)依次进行线性变换。
我们知道序列之间存在着相互关系,例如一个单词的含义在不同的句子中可能也会不同。上面的简单的全连接中,单词之间是完全独立的,不会进行信息交换,所以也就不会捕获序列中单词之间的关系。
怎么捕获单词之间的关系——RNN
循环神经网络(Recurrent Neural Networks, RNN)提供了一种方法。如下图所示。
每个单词(向量)在处理时,还要接受上一个单词处理后的中间结果。这样每个单词都能获得前面所有单词的信息。然后为了能处理变长序列,上面每层模块共享参数,或者说就是同一个模块。有关RNN的讲解,我是看的完全解析RNN, Seq2Seq, Attention注意力机制 - 知乎 (zhihu.com)。
上面的模型只是能处理变长的序列,但是并不能处理seq2seq任务,因为上面的模型明显只能输出等长的序列。想要做seq2seq,需要调整成下面的结构。
举个例子:”机/器/学/习“->”machine“,在预测”machine“的时候,参考了”机/器/学/习“的信息,随后预测”learning“,模型接下来还会预测,预测到”“符号,表示预测终止。
RNN的缺点
基于RNN的encoder-decoder模型(简称RNN)虽然可以处理seq2seq任务,但是有很多缺点:
- RNN基于时序,并行性差。也就是要一个个去处理单词。
- 容易丢失远距离的信息。单词信息在链上会逐渐衰减。
当时有工作采用了CNN的方式来解决”丢失远距离信息“的问题,但是在长序列上,CNN需要增加卷积层才能看到整个序列。
Transformer
Attention
参考大佬的文章动图轻松理解Self-Attention(自注意力机制) - 知乎 (zhihu.com)。
我这里描述一下过程:
现在有一个序列\(X=[\bold{x}_1,...,\bold{x}_{l}]^T \in R^{l\times d}\),这些token(就是单词对应的向量)经过三个线性变换映射成三个序列:\(Q=XW_q,K=XW_k,V=xW_v\),其中\(W_q,W_k,W_v\in R^{d\times d}\),因此\(Q,K,V\in R^{l\times d}\)。
然后计算\(Softmax(\frac{QK^T}{\sqrt{d}})\)得到一个得分矩阵\(S\in R^{l\times l}\)。得分矩阵中的元素\(s_{ij}\)表示\(q_i\)和\(k_j\)之间的相似度,这个相似度是用\(q_ik_j^T\)计算得到的。这个值越高,就表明\(x_i\)与\(x_j\)的关系较紧密,那么当我们处理\(x_i\)时,就要多考虑\(x_j\)。怎么多考虑,就是把这个得分当作是权重,也就是\(S·V\in R^{l\times d}\)。这个结果\(V_{out}\)还要再经过一个全连接层,也就是\(V_{out}W_o+b_o\)
上面线性代数的部分,如果基础不牢很容易看不懂,我当时就没看懂。可以参考我下面一篇文章,会详细进行计算。
attention的计算可以并行。因此极大提高了计算效率。总的来说,在并行时间内,只做了四个矩阵计算。
模型结构
Input Embedding
上图中的Inputs是原始句子分词后的one-hot编码序列,设为\(X=[x_1,...,x_l]^{T}\),其中\(x_i\)是one-hot编码,例如有一个大小为\(V\)的词表,\(x_i\)对应的单词在词表中的序号为\(j\),那么\(x_i[j]=1\),其余为0。因此\(X\in R^{l\times V}\)
而Input Embedding可以看作是一个不带偏差的线性层,即\(W_E \in R^{V\times d}\),其中\(d\)表示映射后的向量维度。映射过程可以看成\(T=XW_E,T\in R^{l\times d}\)。
因为\(X\)中每一行都是一个单词对应的one-hot编码(向量),这个向量乘\(W_E\)的时候,其实就是按对应位置选择\(W_E\)的某一行向量。
所以也可以把\(W_E\)看成一个向量的查询表,那么\(X\)中的元素也不必是one-hot编码,也可以是一个数字,这个数字就是单词在词表中的序号。这样\(x_i=j\),那么映射过程就变成了T=W_E[X]
。
总之,我们得到了\(T_E=[t_1,...,t_l]^T\in R^{l\times d}\)。
Input Embedding层可以是训练的,也可以是固定的。如果是可训练的,该层就是一个无偏差的线性层,transformer使用的是这种。
Positional Embedding
序列中天然具有时序信息,在前一步的input embedding中,每个单词之间的处理都是独立的,此时还没有包含时序信息。并且attention也不像rnn结构天然具有能处理时序。因而在上一步得到的\(T_E\)中每个位置还要加上一个能够表示当前位置的信息(一个数值),这就是positional embedding。
位置信息有两种,绝对位置信息和相对位置信息。
transformer使用的是绝对位置信息,就是说固定位置的信息是固定的,例如位置3的位置信息永远是0.1(举个例子)。
transformer使用的是Sinusoidal编码。整个过程是,先将文本分词然后embedding,然后计算positional矩阵,将embedding加上这个矩阵,然后进入attention。编码矩阵计算如下:
\(p_k=\begin{cases} p_{k,2i}=\sin(k/10000^{2i/d}) \\ p_{k,2i+1}=\cos(k/10000^{2i/d}) \end{cases}\)
于是得到位置编码\(P=[p_1,...,p_l]^T\in R^{l\times d}\),然后\(T=T_E+P\)。
Multi-Head Attention
CNN具有多通道的优点,每个通道识别不同的pattern,论文提出了multi-head attention,可以模拟CNN的多通道。
从文字描述来看,过程是这样:
- 有多个QKV转换矩阵,假设有两个head,那么\(W_q\)矩阵就有两个,分别是\(W_{q1},W_{q2}\in R^{d\times d/2}\),于是得到两个query:\(Q_1,Q_2\in R^{l\times d/2}\)。KV同理。
- 现在每个头都有单独的QKV,例如头1有\(Q_1,K_1,V_1\)。
- 然后在head内做attention:\(V_{out1}=Softmax(\frac{Q_1K_1^T}{\sqrt{d}})·V_1\in R^{l\times d/2}\),同理\(V_{out2}\in R^{l\times d/2}\)。
- 将两个输出拼接,\(V_{out}=concat(V_{out1},V_{out2})\in R^{l\times d}\),然后经过一个输出层\(T_{out}=V_{out}W_o\in R^{l\times d}\)
实际上可以转换成:
- 有一个\(W_q\in R^{d\times d},Q=TW_q\)。KV同理。
- 现在把\(Q\)划分为多个head,设置head数为h,这样维度从\([l,d]\)变换为\([l,h,d/h]\)。为了后续在每个头内执行attention,还要变换到\([h,l,d/h]\)。KV同理。
- 然后\(V_{out}=Softmax(\frac{QK^T}{\sqrt{d}})·V\),维度为\([h,l,d/h]\)。
- 最后再将\([h,l,d/h]\)变换为\([l,d]\),然后经过输出层。
Add&Norm
假设输入attention的是\(T_0\),输出的是\(T_{out}=Attention(T_0)\),那么Add表示\(T_1=T_0+T_{out}\)。这是为了不丢失原始信息。
Norm指Layer Normalization。
Batch Norm是在一个批量中的所有样本的特征的一个维度上做Norm。在NLP中,是对每个句子的第一个(第二个、三个...)词的切片,一个矩阵,然后对这个矩阵的特征进行缩放。例如一个batch中的每个句子的第一个token的第一个维度。
Layer Norm是在一个样本中的所有特征之间做Norm。在NLP中,是对每个句子进行切片。是对一个句子的一个token内进行缩放。
如果要对\(T=[t_1,...,t_l]^T\)做layer normalization,每个元素独立处理。
例如\(t_1=[t_{11},...,t_{1d}]^{T}\),那么正则化就是\(\hat{t}_{1i}=\frac{t_{1i}-\mu}{\sqrt{\sigma^2+\epsilon}}\)。
FeedForward
一个带隐层的神经网络,一共两个线性层,隐层的维数为\(4d\),激活函数为ReLU。公式为:\(FFN(T)=\max(0,TW_1+b_1)W_2+b_2\)。
其中\(W_1\in R^{d\times 4d},W_2\in R^{4d\times d}\)。
Cross Attention
decoder中的第二个attention层就是cross attention。在self-attention中,QKV都是由X线性变换得到的,而cross attention中,Q是由X线性变换得到,而KV则是由Y线性变换得到的。
Embeddings && Output Linear
transformer中有两个embedding层,encoder和decoder各一个,这两层共享参数。并且模型最后输出的结果还要经过一个输出层,该层的目的是为了将d维的向量映射成V维的向量,该向量经过softmax后可以看成一个概率分布,表示预测单词的各概率。
Masked Attention
不管是RNN还是transformer,在做seq2seq任务时都是采用逐个词预测的方式,直到预测到终止符。
在训练时,为了提高计算效率,采用了并行预测的方式。举个例子:”机/器/学/习“->”machine/learning“的训练过程分为三步,这三步同时进行:
- ”机/器/学/习“->”machine“
- ”机/器/学/习/machine“->”learning“
- ”机/器/学/习/machine/learning“->”“
怎么实现这个并行过程,就是用到了mask机制。
在attention中会计算\(QK^T\),mask是一个01矩阵,维度是\([l,l]\)。然后将\(QK^T\)和mask两个矩阵做计算,这个计算是:如果mask一个位置的元素是1,那么就将\(QK^T\)中对应位置的元素替换为无限小,如果是0就不变。
替换完后会进行softmax,这样被替换为无限小的部分softmax就会变成0。
Mask影响了什么
彻底理解mask才能彻底理解decoder的细节。
添加了mask后,decoder输入" / machine / learning",它们对应的输出对应于”machine / learning / “。其中bos是begin of seqence,eos是end of seqence。
在decoder中,每个位置输入对应的输出是下一个单词的预测。decoder中每个单词只能看到前面的信息。
在计算损失的时候,是将每个位置的输出(softmax后的一个概率分布),也就是多个概率分布拼接起来,然后和多个one-hot编码的拼接做cross entropy。
其他
- 在Attention中的\(\frac{QK^T}{\sqrt{d}}\)中,除以\(\sqrt{d}\)的目的是为了让softmax更平滑。softmax的一方面可以将一个向量变成一个概率分布。另一方面会将小的数字概率变得更小,大的数字概率变得更大,在\(QK_T\)中,计算结果会因为d的增加而增加,为了减小维度d的影响,所以要除以\(\sqrt{d}\)。
- 暂时还想不到。
参考资料:
[1409.2329] Recurrent Neural Network Regularization (arxiv.org)
完全解析RNN, Seq2Seq, Attention注意力机制 - 知乎 (zhihu.com)
[1706.03762] Attention Is All You Need (arxiv.org)
NLP中 batch normalization与 layer normalization - 知乎 (zhihu.com)