NLP 教程

NLP 工具库

NLP 神经网络

NLP 笔记

original icon
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.knowledgedict.com/tutorial/nlp-transformer.html

Transformer 模型架构详解


Transformer 模型架构是 Google 在2017年6月发表在 arxiv 上的一篇论文《Attention Is All You Need》中提到的,它主要由谷歌大脑(Google Brain)的一个团队推出,现已逐步取代长短期记忆(LSTM)等 RNN 模型成为了 NLP 问题的首选模型。Transformer 是一个完全基于注意力机制的编解码器模型,它抛弃了之前其它模型引入注意力机制后仍然保留的循环与卷积结构,而采用了自注意力(self-attention)机制,在任务表现、并行能力和易于训练性方面都有大幅的提高。

Transformer 优势

在 Transformer 出现之前,基于神经网络的机器翻译模型多数都采用了 RNN 的模型架构,它们依靠循环功能进行有序的序列操作。虽然 RNN 架构有较强的序列建模能力,但是存在训练速度慢训练质量低等问题。

与基于 RNN 的方法不同,Transformer 模型中没有循环结构,而是把序列中的所有单词或者符号并行处理,同时借助自注意力机制对句子中所有单词之间的关系直接进行建模,而无需考虑各自的位置。具体而言,如果要计算给定单词的下一个表征,Transformer 会将该单词与句子中的其它单词一一对比,并得出这些单词的注意力分数。注意力分数决定其它单词对给定词汇的语义影响。之后,注意力分数用作所有单词表征的平均权重,这些表征输入全连接网络,生成新表征。

由于 Transformer 并行处理所有的词,以及每个单词都可以在多个处理步骤内与其它单词之间产生联系,它的训练速度比 RNN 模型更快,在翻译任务中的表现也比 RNN 模型更好。除了计算性能和更高的准确度,Transformer 另一个亮点是可以对网络关注的句子部分进行可视化,尤其是在处理或翻译一个给定词时,因此可以深入了解信息是如何通过网络传播的。

之后,Google 的研究人员们又对标准的 Transformer 模型进行了拓展,采用了一种新型的、注重效率的时间并行循环结构,让它具有通用计算能力,并在更多任务中取得了更好的结果。

改进的模型(Universal Transformer)在保留 Transformer 模型原有并行结构的基础上,把 Transformer 一组几个各异的固定的变换函数替换成了一组由单个的、时间并行的循环变换函数构成的结构。相比于 RNN 一个符号接着一个符号从左至右依次处理序列,Universal Transformer 和 Transformer 能够一次同时处理所有的符号,但 Universal Transformer 接下来会根据自注意力机制对每个符号的解释做数次并行的循环处理修饰。Universal Transformer 中时间并行的循环机制不仅比 RNN 中使用的串行循环速度更快,也让 Universal Transformer 比标准的前馈 Transformer 更加强大。

Transformer 整体网络结构

以中英翻译任务为例的 Transformer 架构图如下:

transformer 架构图

transformer 架构图

可以看到 Transformer 由 EncoderDecoder 两个部分组成,上面如图 Encoder 和 Decoder 都包含了 6 个 block。至于需要多少个 block 可以任意设置。

工作流程

Transformer 的工作流程大体如下:

  1. 第一步:获取输入句子的每一个单词的表示向量 XX 由单词的 Embedding(Embedding 就是从原始数据提取出来的 Feature) 和单词位置的 Embedding 相加得到。

    Transformer 的输入表示

    以 bert-base-chinese 为例子,内部的 embedding 模块里除了如上的 word_embeddings 和 position_embeddings 子模块,还有 token_type_embeddings 子模块;token_type_embeddings 层主要有两个作用,一是区分不同句子或段落,另一个是丰富词嵌入信息。

    如下是打印的 bert-base-chinese 的 embeddings 模块:

    (embeddings): BertEmbeddings(
      (word_embeddings): Embedding(21128, 768, padding_idx=0)
      (position_embeddings): Embedding(512, 768)
      (token_type_embeddings): Embedding(2, 768)
      (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      (dropout): Dropout(p=0.1, inplace=False)
    )
  2. 第二步:将得到的单词表示向量矩阵 (如上图所示,每一行是一个单词的表示 x) 传入 Encoder 中,经过 6 个 Encoder block 后可以得到句子所有单词的编码信息矩阵 C,如下图。单词向量矩阵用 \(X_{n \times d}\)表示, n 是句子中单词个数,d 是表示向量的维度 (论文中 d=512)。每一个 Encoder block 输出的矩阵维度与输入完全一致

    Transformer Encoder 编码句子信息

    Transformer Encoder 编码句子信息

  3. 第三步:将 Encoder 输出的编码信息矩阵 C 传递到 Decoder 中,Decoder 依次会根据当前翻译过的单词 1 ~ i 翻译下一个单词 i+1,如下图所示。在使用的过程中,翻译到单词 i+1 的时候需要通过 Mask(掩盖)操作遮盖住 i+1 之后的单词。

    Transofrmer Decoder 预测

    Transofrmer Decoder 预测

    上图 Decoder 接收了 Encoder 的编码矩阵 C,然后首先输入一个翻译开始符 <Begin>,预测第一个单词 "I";然后输入翻译开始符 <Begin> 和单词 "I",预测单词 "have",以此类推。这是 Transformer 使用时候的大致流程,接下来是里面各个部分的细节。

Transformer 的输入

Transformer 中单词的输入表示 x单词 Embedding(Word Encoding)和位置 Embedding(Positional Encoding)相加得到。

Transformer 的输入表示

Transformer 的输入表示

单词 Embedding

Token Embedding 有很多种方式可以获取,例如可以采用 Word2Vec、Glove 等算法预训练得到,也可以在 Transformer 中训练得到

位置 Embedding

Transformer 中除了单词的 Embedding,还需要使用位置的 Embedding 表示单词出现在句子中的位置。因为 Transformer 不采用 RNN 的结构,而是使用全局信息,不能利用单词的顺序信息,而这部分信息对于 NLP 来说非常重要。所以 Transformer 中使用位置 Embedding 保存单词在序列中的相对或绝对位置。

位置 Embedding 用 PE 表示,PE 的维度与单词 Embedding 是一样的。PE 可以通过训练得到,也可以使用某种公式计算得到。在 Transformer 中采用了后者,计算公式如下:

\(PE(pos, 2i) = sin({pos \over 10000^{2i/d_{model}}})\)

\(PE(pos, 2i+1) = cos({pos \over 10000^{2i/d_{model}}})\)

其中,pos 表示单词在句子中的位置,从 0 开始,即 pos 取 0,1,2,3...T-1,T 为文字的长度,dmodel 表示 PE 的维度(与词 Embedding 一样),2i 表示偶数的维度,2i+1 表示奇数维度(即 2i≤d, 2i+1≤d)。

pos = 3dmodel = 128 时,Positional Encoding(或者说是 pos embedding)的计算结果为:

\([sin({3 \over 10000^{0/128}}), cos({3 \over 10000^{1/128}}), sin({3 \over 10000^{2/128}}), cos({3 \over 10000^{3/128}}), ... , sin({3 \over 10000^{126/128}}),cos({3 \over 10000^{127/128}})]\)

每一个字所计算出来的 Positional Encoding 并不是一个值而是一个向量,他的长度和这个字的 word embedding 的长度一致。

使用这种公式计算 PE 有以下的好处:

  1. 使 PE 能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20 个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以计算出第 21 位的 Embedding。
  2. 可以让模型容易地计算出相对位置,对于固定长度的间距 k,PE(pos+k) 可以用 PE(pos) 计算得到。因为 Sin(A+B) = Sin(A)Cos(B) + Cos(A)Sin(B), Cos(A+B) = Cos(A)Cos(B) - Sin(A)Sin(B)。

Self-Attention(自注意力机制)

Transformer Encoder 和 Decoder

Transformer Encoder 和 Decoder

上图是论文中 Transformer 的内部结构图,左侧为 Encoder block,右侧为 Decoder block。红色圈中的部分为 Multi-Head Attention,是由多个 Self-Attention 组成的,可以看到 Encoder block 包含一个 Multi-Head Attention,而 Decoder block 包含两个 Multi-Head Attention(其中有一个用到 Masked)。Multi-Head Attention 上方还包括一个 Add & Norm 层,Add 表示残差连接(Residual Connection)用于防止网络退化,Norm 表示 Layer Normalization,用于对每一层的激活值进行归一化。

因为 Self-Attention 是 Transformer 的重点,所以我们重点关注 Multi-Head Attention 以及 Self-Attention,首先详细了解一下 Self-Attention 的内部逻辑。

Self-Attention 结构

Self-Attention 结构

Self-Attention 结构

上图是 Self-Attention 的结构,在计算的时候需要用到矩阵 Q(查询),K(键值),V(值)。在实际中,Self-Attention 接收的是输入(单词的表示向量x组成的矩阵X)或者上一个 Encoder block 的输出。而Q,K,V 正是通过 Self-Attention 的输入进行线性变换得到的。

Q, K, V 的计算

Self-Attention 的输入用矩阵 X 进行表示,则可以使用线性变阵矩阵 WQ,WK,WV 计算得到 Q,K,V。计算如下图所示,注意 X,Q,K,V 的每一行都表示一个单词。

Q, K, V 的计算

Q, K, V 的计算

Self-Attention 的输出

得到矩阵 Q,K,V 之后就可以计算出 Self-Attention 的输出了,计算的公式如下:

Self-Attention 的输出

Self-Attention 的输出

公式中计算矩阵 Q 和 K 每一行向量的内积,为了防止内积过大,因此除以 dk 的平方根。Q 乘以 K 的转置后,得到的矩阵行列数都为 n,n 为句子单词数,这个矩阵可以表示单词之间的 attention 强度。下图为 Q 乘以 KT,1234 表示的是句子中的单词。

Q乘以K的转置的计算

Q 乘以 K 的转置的计算

得到 QKT之后,使用 Softmax 计算每一个单词对于其他单词的 attention 系数,公式中的 Softmax 是对矩阵的每一行进行 Softmax,即每一行的和都变为 1。

对矩阵的每一行进行 Softmax

对矩阵的每一行进行 Softmax

得到 Softmax 矩阵之后可以和 V 相乘,得到最终的输出 Z。

Self-Attention 输出

Self-Attention 输出

上图中 Softmax 矩阵的第 1 行表示单词 1 与其他所有单词的 attention 系数,最终单词 1 的输出 Z1 等于所有单词 i 的值 Vi 根据 attention 系数的比例加在一起得到,如下图所示:

Zi 的计算方法

Zi 的计算方法

Multi-Head Attention

在上一步,我们已经知道怎么通过 Self-Attention 计算得到输出矩阵 Z,而 Multi-Head Attention 是由多个 Self-Attention 组合形成的,下图是论文中 Multi-Head Attention 的结构图。

Multi-Head Attention

Multi-Head Attention

从上图可以看到 Multi-Head Attention 包含多个 Self-Attention 层,首先将输入 X 分别传递到 h 个不同的 Self-Attention 中,计算得到 h 个输出矩阵 Z。下图是 h=8 时候的情况,此时会得到 8 个输出矩阵 Z。

多个 Self-Attention

多个 Self-Attention

得到 8 个输出矩阵 Z1 到 Z8 之后,Multi-Head Attention 将它们拼接在一起(Concat),然后传入一个 Linear 层,得到 Multi-Head Attention 最终的输出 Z。

Multi-Head Attention 的输出

Multi-Head Attention 的输出

可以看到 Multi-Head Attention 输出的矩阵 Z 与其输入的矩阵 X 的维度是一样的。

Encoder 结构

Transformer Encoder block

Transformer Encoder block

上图红色部分是 Transformer 的 Encoder block 结构,可以看到是由 Multi-Head Attention、Add & Norm、Feed Forward、Add & Norm 组成的。刚刚已经了解了 Multi-Head Attention 的计算过程,现在了解一下 Add & Norm 和 Feed Forward 部分。

Add & Norm

Add & Norm 层由 Add 和 Norm 两部分组成,其计算公式如下:

Add & Norm 公式

Add & Norm 公式

其中 X 表示 Multi-Head Attention 或者 Feed Forward 的输入,MultiHeadAttention(X) 和 FeedForward(X) 表示输出(输出与输入 X 维度是一样的,所以可以相加)。

Add 指 X+MultiHeadAttention(X),是一种残差连接,通常用于解决多层网络训练的问题,可以让网络只关注当前差异的部分,在 ResNet 中经常用到:

残差连接

残差连接

Norm 指 Layer Normalization,通常用于 RNN 结构,Layer Normalization 会将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛。

Feed Forward

Feed Forward 层比较简单,是一个两层的全连接层,第一层的激活函数为 Relu,第二层不使用激活函数,对应的公式如下。

Feed Forward

残差连接

X 是输入,Feed Forward 最终得到的输出矩阵的维度与 X 一致。

组成 Encoder

通过上面描述的 Multi-Head Attention,Feed Forward,Add & Norm 就可以构造出一个 Encoder block,Encoder block 接收输入矩阵 X(n×d),并输出一个矩阵 O(n×d)。通过多个 Encoder block 叠加就可以组成 Encoder。

第一个 Encoder block 的输入为句子单词的表示向量矩阵,后续 Encoder block 的输入是前一个 Encoder block 的输出,最后一个 Encoder block 输出的矩阵就是编码信息矩阵 C,这一矩阵后续会用到 Decoder 中。

Encoder 编码句子信息

Encoder 编码句子信息

Decoder 结构

Transformer Decoder block

Transformer Decoder block

上图红色部分为 Transformer 的 Decoder block 结构,与 Encoder block 相似,但是存在一些区别:

  • 包含两个 Multi-Head Attention 层。
  • 第一个 Multi-Head Attention 层采用了 Masked 操作。
  • 第二个 Multi-Head Attention 层的 K, V 矩阵使用 Encoder 的编码信息矩阵 C 进行计算,而 Q 使用上一个 Decoder block 的输出计算。
  • 最后有一个 Softmax 层计算下一个翻译单词的概率。

第一个 Multi-Head Attention

Decoder block 的第一个 Multi-Head Attention 采用了 Masked 操作,因为在翻译的过程中是顺序翻译的,即翻译完第 i 个单词,才可以翻译第 i+1 个单词。通过 Masked 操作可以防止第 i 个单词知道 i+1 个单词之后的信息。下面以“我有一只猫” 翻译成 “I have a cat” 为例,了解一下 Masked 操作。

下面的描述中使用了类似 Teacher Forcing 的概念。在 Decoder 的时候,是需要根据之前的翻译,求解当前最有可能的翻译,如下图所示。首先根据输入 “<Begin>” 预测出第一个单词为 “I”,然后根据输入 “<Begin> I” 预测下一个单词 “have”。

Decoder 预测

Decoder 预测

Decoder 可以在训练的过程中使用 Teacher Forcing 并且并行化训练,即将正确的单词序列(<Begin> I have a cat)和对应输出(I have a cat <end>)传递到 Decoder。那么在预测第 i 个输出时,就要将第 i+1 之后的单词掩盖住,注意 Mask 操作是在 Self-Attention 的 Softmax 之前使用的,下面用 0 1 2 3 4 5 分别表示 “<Begin> I have a cat <end>”。

  1. 第一步:是 Decoder 的输入矩阵和 Mask 矩阵,输入矩阵包含 “I have a cat”(0, 1, 2, 3, 4)五个单词的表示向量,Mask 是一个 5×5 的矩阵。在 Mask 可以发现单词 0 只能使用单词 0 的信息,而单词 1 可以使用单词 0, 1 的信息,即只能使用之前的信息。

    输入矩阵与 Mask 矩阵

    输入矩阵与 Mask 矩阵

  2. 第二步:接下来的操作和之前的 Self-Attention 一样,通过输入矩阵 X 计算得到 Q,K,V 矩阵。然后计算 Q 和 KT 的乘积 QKT

    Q 乘以 K 的转置

    Q 乘以 K 的转置

  3. 第三步:在得到 QKT 之后需要进行 Softmax,计算 attention score,我们在 Softmax 之前需要使用 Mask 矩阵遮挡住每一个单词之后的信息,遮挡操作如下:

    Softmax 之前 Mask

    Softmax 之前 Mask

    得到 Mask QKT 之后在 Mask QKT 上进行 Softmax,每一行的和都为 1。但是单词 0 在单词 1, 2, 3, 4 上的 attention score 都为 0。

  4. 第四步:使用 Mask QKT 与矩阵 V 相乘,得到输出 Z,则单词 1 的输出向量 Z1 是只包含单词 1 信息的。

    Mask 之后的输出

    Mask 之后的输出

  5. 第五步:通过上述步骤就可以得到一个 Mask Self-Attention 的输出矩阵 Zi,然后和 Encoder 类似,通过 Multi-Head Attention 拼接多个输出 Zi,然后计算得到第一个 Multi-Head Attention 的输出 Z,Z 与输入 X 维度一样。

第二个 Multi-Head Attention

Decoder block 第二个 Multi-Head Attention 变化不大,主要的区别在于其中 Self-Attention 的 K, V 矩阵不是使用 上一个 Decoder block 的输出计算的,而是使用 Encoder 的编码信息矩阵 C 计算的。

根据 Encoder 的输出 C 计算得到 K,V,根据上一个 Decoder block 的输出 Z 计算 Q(如果是第一个 Decoder block 则使用输入矩阵 X 进行计算),后续的计算方法与之前描述的一致。

这样做的好处是在 Decoder 的时候,每一位单词都可以利用到 Encoder 所有单词的信息(这些信息无需 Mask)。

Softmax 预测输出单词

Decoder block 最后的部分是利用 Softmax 预测下一个单词,在之前的网络层我们可以得到一个最终的输出 Z,因为 Mask 的存在,使得单词 0 的输出 Z0 只包含单词 0 的信息,如下:

Decoder Softmax 之前的 Z

Decoder Softmax 之前的 Z

Softmax 根据输出矩阵的每一行预测下一个单词:

Decoder Softmax 预测

Decoder Softmax 之前的 Z

这就是 Decoder block 的定义,与 Encoder 一样,Decoder 是由多个 Decoder block 组合而成。

Transformer 总结

  • Transformer 与 RNN 不同,可以比较好地并行训练。
  • Transformer 本身是不能利用单词的顺序信息的,因此需要在输入中添加位置 Embedding,否则 Transformer 就是一个词袋模型了。
  • Transformer 的重点是 Self-Attention 结构,其中用到的 Q,K,V 矩阵通过输出进行线性变换得到。
  • Transformer 中 Multi-Head Attention 中有多个 Self-Attention,可以捕获单词之间多种维度上的相关系数 attention score。