Transformer 是一种用于处理序列数据的深度学习模型架构,最初由 Vaswani 等人在 2017 年的论文《Attention is All You Need》中提出。它彻底改变了自然语言处理(NLP)领域,成为许多高级任务(如机器翻译、文本生成、问答系统等)的基础架构。Transformer 的核心思想是自注意力机制(Self-Attention),而不依赖于传统的 RNN 或 CNN,在机器翻译上效果特别好,横扫NLP领域。
原文链接:Attention is all you need
1. Transformer整体结构
Transformer在数据角度上理解,和RNN是一致的,也和CNN是一致的。Transformer和RNN都保留了编码和解码的结构,这是什么原因呢?Transformer翻译过来叫做“变形金刚”,而编码-解码的过程,也如同变形金刚一样,先拆解为流体一般的变形元素,再变回机器人。Transformer 的结构复杂,分为编码和解码两个过程,每个encoder和decoder都是串联结构,其中编码器将输入序列编码成一个固定维度的表示,而解码器根据这个表示生成输出序列。注意力机制相当于是拆解对照表,计算各个零部件的权重,标明互相间的关系,而前馈网络就是根据权重变一次形状;在decoder还多了一层encoder-decoder attention,组装的时候不仅要考虑自己还要考虑拆解信息。数据如何在这些模块流动?首先,用算法把单词向量化,输入向量先嵌入位置信息,self attention是零件自查表,用softmax函数过滤掉不相关的单词,经过一系列矩阵操作,实现了单词计算,并消除Q,K,V初始值的影响,如下图所示:
将Encoder和Decoder拆开,可以看到完整的结构,如下图所示:
2. 词嵌入
2.1. 编解码
对于机器翻译来说,我们只能针对中文和英文这种纯文本来完成语义的对应,语言的可能性是无穷的,表达的语义也是无法穷尽,所以我们只能通过大量文本的上下文来确定词和词之间的关系。那编码和解码中的“码”到底是什么呢?其实就是把各种语言里面那些符号发音等等形式上的不同剥离掉之后,剩下来的单纯的语言关系。首先,因为需要用计算机来处理,这个语义关系应该是数字化的;其次,它需要表示语义之间的关系,所以这个语义关系码数字化后的数值要能体现出语义之间的关系来才行。假如,我们用高维空间里面的坐标来当作数字化码之后的结果,香蕉🍌对应的点和猴子🐒对应的点距离应该比较近,因为他们的语义比较近。那高维空间里面的码如何得到呢?
对文本里面的最基础的语义单元进行数字化有两种,tokenizer(分词器,标记器)和one hot(独热编码)。标记器和独热编码实际上就是采用不同的策略对TOKEN实施数字化:
- tokenizer:数字化的方式比较简单,就是给不同的token分配一个独立的id,就相当于是把所有的token都投射到了一根一维的数轴上。标记器是把所有token都投射到了一个一维空间。
- 独热编码:它做的事情就是把二进制的每一位对应一个token。独热编码则是为每一个token都分配了一个单独的维度,最后就变成了有多少token,就有多少维度的高维空间。
对于分词器来说,把所有的token都投射到了一根一维的数轴上,空间比较密集,就很难表达出一些复杂的语义;而独热编码空间太过稀疏了,很容易能表现出组合语义,但很难体现出token与token之间的联系(token之间互相正交,内积均为0,且均分布在距离原点为1的高维球面上)。
综合上述两种极端编码情况,我们就可以找到一个维度高但是没那么高的空间,也就是我们所说的潜空间。如何找到这样的潜空间呢?可以基于分词后的ID去升维,也可以基于独热编码去降维。降维相当于是将数据进行压缩,而升维相当于是将压缩后的数据进行还原,降维从直觉上去想相对简单一些。而降维其实是一种空间变换,也就是在线性代数里面就是矩阵与向量相乘。
2.2. Word2Vec
编码就是先把一个文本里的TOKEN都先编成独热码,然后再进行降维。这个过程就相当于是把输入的一句话,根据语义投射到潜空间中,把高维空间里的对象,投射到低维空间,这个过程叫做Embedding。因为是采用矩阵乘法这种方式实现嵌入的,所以把TOKEN投射到潜空间里的那个矩阵就被称作嵌入矩阵。比如,中文和英语完全可以用两套不一样的词汇表,然后分别嵌入到两个独立的潜空间中,然后采用某些算法,把这两个潜空间融合起来;也可以把中文和英文放到一个大的词汇表训练,得到一个大的潜空间。
一个句子经过编码后得到token,然后token经过解码后变成另一个句子,这两个句子应该是一样的。但是,训练应该是经过模型之后计算出来一个结果,这个结果和正确答案是有差异的,然后才能把这个差异去反向传播回去,去修正参数。而这种情况是没有办法进行训练的,因为不论输入的向量是什么,只要前面和后面的矩阵是伪逆关系,那输入输出结果一定是相等的。
如果有五个词向量,把中间一个扣掉,将剩下四个向量相加之后训练出来的是中间扣掉的向量。Word2Vec更像是编词典,不需要激活函数,训练之后体现的是单个TOKEN之间的联系,在生成的潜空间,用其他的词向量去合成目标词向量。
Word2Vec结构如下,不存在激活函数,仅有一层隐藏层。
2.3. Embedding layer
Transformer 的输入并非简单的one-hot vectore,原因包括这种表达方式的结果非常稀疏,非常大,且不能表达 word 与 word 之间的特征。所以这里对词进行 embedding,用较短的向量表达这个 word 的属性。一般在 Pytorch 中,我们都是用 nn.Embedding 来做,或者直接用 one-hot vector 与权重矩阵 W 相乘得到。
nn.Embedding 包含一个权重矩阵 W,对应的 shape 为 ( num_embeddings,embedding_dim )。num_embeddings 指的是词汇量,即想要翻译的 vocabulary 的长度,embedding_dim 指的是想用多长的 vector 来表达一个词,可以任意选择,比如64,128,256,512等。在 Transformer 论文中选择的是512(即 d_model =512)。其实可以形象地将 nn.Embedding 理解成一个 lookup table,里面对每一个 word 都存了向量 vector 。给任意一个 word,都可以从表中查出对应的结果。处理 nn.Embedding 权重矩阵有两种选择:
- 使用 pre-trained 的 embeddings 并固化,这种情况下实际就是一个 lookup table。
- 对其进行随机初始化(当然也可以选择 pre-trained 的结果),但设为 trainable。这样在 training 过程中不断地对 embeddings 进行改进。(嵌入矩阵需要在训练中调整参数)
在 Annotated Transformer 中,class “Embeddings“ 用来生成 word 的embeddings,其中用到 nn.Embedding。具体实现见下:
class Embeddings(nn.Module):
def __init__(self, d_model, vocab):
super(Embeddings, self).__init__()
self.lut = nn.Embedding(vocab, d_model)
self.d_model = d_model
def forward(self, x):
return self.lut(x) * math.sqrt(self.d_model)
3. 注意力机制
3.1. 注意力
对词和词组合后的语义进行理解,靠的就是注意力机制。词嵌入已经解决了单个词单个TOKEN语义的问题,注意力机制要解决的是许多词组合之后整体的语义,这组词向量就组成了数据矩阵。经过注意力机制之后,输入的词向量矩阵都需要经过矩阵相乘之后得到Q, K, V。
注意力的思想,类似于寻址。给定Target(T)中的某个元素Query(Q),通过计算Query(Q)和各个Key(K)的相似性或相关性,得到每个Key(K)对应Value(V)的权重系数(即A,为注意力得分),然后对Value(V)进行加权求和,即得到最终的Attention数值。
需要注意的是,Q和K的转置作内积运算,本质上是求相关性,得到一个包含相关性信息的表——A。如果结果数值为0,则表明为正交关系;如果结果数值为1,则表明为正相关关系;如果结果数值为-1,则表明为负相关关系。
3.2. 交叉注意力
decoder与encoder相比,在注意力结束之后,还会进行一个交叉注意力机制,解码器里的每一层都会拿到编码器的结果进行参考。Transformer在训练过程中,解码部分和编码部分是可以并行进行训练的,最终可以得到编码器部分和解码器部分潜空间中的词向量,损失函数是两个词向量的差异,然后进行反向传播。
而在Transformer的推理过程中,考虑到在机器翻译的过程中,token的数量并非是一一对应的,相同的语义token的数量并不一样。输入一句中文进行翻译,得到的英文结果需要一个一个地去生成,这个过程就用到了RNN的思路。编码器部分需要将一句话全部输入,得到潜空间中的词向量,在解码器部分也是需要输入内容的,这时候我们输入“开始符号”——<BOS>,输入这个符号之后,经过交叉注意力进行计算之后,最后会得到一个结果,这个结果进行升维和softmax计算之后,会得到词汇表中的某个词,重复这个过程,直到收到结束符号之后,整个翻译过程结束。
3.3. 多头注意力
多头注意力机制对应整体结构图中的Multi——Head Attention,多头注意力机制扩展了模型专注于不同位置的能力,有多个查询/键/值权重矩阵集合,Transformer使用八个注意力头,并且每一个都是随机初始化的。和自注意力机制一样,用矩阵X乘以WQ、WK、WV来产生查询、键、值矩阵,但self-attention只是使用了一组WQ、WK、WV来进行变换得到查询、键、值矩阵,而Multi-Head Attention使用多组WQ,WK,WV得到多组查询、键、值矩阵,然后每组分别计算得到一个Z矩阵。
4. 位置编码(Positional Encoding)
由于 Transformer 模型并不具备像 RNN 或 CNN 那样的顺序性,没有内置的序列位置信息,它需要额外的位置编码来表达输入序列中单词的位置顺序,通过将一组固定的编码添加到输入的嵌入向量中,表示输入的相对或绝对位置。
那 RNN 为什么在任何地方都可以对同一个 word 使用同样的向量呢?因为 RNN 是按顺序对句子进行处理的,一次一个 word。但是在 Transformer 中,输入句子的所有 word 是同时处理的,没有考虑词的排序和位置信息。Transformer 加入 “positional encoding” 来解决这个问题,使得 Transformer 可以衡量 word 位置有关的信息。positional encoding 与 word embedding 相加就得到 embedding with position。如果是乘法的话,位置对词向量的影响就太大。
那么具体 ”positional encoding“ 怎么做?为什么能表达位置信息呢?作者探索了两种创建 positional encoding 的方法:
- 通过训练学习 positional encoding 向量
- 使用公式来计算 positional encoding向量
试验后发现两种选择的结果是相似的,所以采用了第2种方法,优点是不需要训练参数,而且即使在训练集中没有出现过的句子长度上也能用。计算 positional encoding 的公式为:
其中,pos 指的是这个 word 在这个句子中的位置 ,i指的是 embedding 维度。比如选择 d_model=512,那么i就从1数到512
为什么选择 sin 和 cos ?positional encoding 的每一个维度都对应着一个正弦曲线,作者假设这样可以让模型相对轻松地通过对应位置来学习。
参考资料:
10分钟带你深入理解Transformer原理及实现 - 知乎https://zhuanlan.zhihu.com/p/80986272blog.csdn.net/leonardotu/article/details/136165819https://blog.csdn.net/leonardotu/article/details/136165819【超详细】【原理篇&实战篇】一文读懂Transformer-CSDN博客https://blog.csdn.net/weixin_42475060/article/details/121101749从编解码和词嵌入开始,一步一步理解Transformer,注意力机制(Attention)的本质是卷积神经网络(CNN)_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1XH4y1T76e/?spm_id_from=333.1391.0.0&vd_source=0dc0c2075537732f2b9a894b24578eed一文了解Transformer全貌(图解Transformer)https://www.zhihu.com/tardis/zm/art/600773858