前言:

  • 本博客仅为初学者提供一个学习思路,如有错误请大佬指出!
  • 进实验室后的第一次学习汇报就是 Transformer,后来研究方向变了,就渐渐忘了。不巧最近夏令营面试又被面到了,看来得好好复习一下。

参考博客:



1 为什么使用 Transformer?

Transformer 可以克服 RNN 存在的问题:

  • 并行化差: h t h_t ht 依赖 h t − 1 h_{t-1} ht1
  • 长距离依赖问题:梯度消失、梯度爆炸,如: d L d W = d L d y ∗ d y d W \frac{\mathrm{d} L}{\mathrm{d} W} = \frac{\mathrm{d} L}{\mathrm{d} y} * \frac{\mathrm{d} y}{\mathrm{d} W} dWdL=dydLdWdy
  • 无法处理变长的输入序列

在这里插入图片描述

面试官:既然有了 RNN,为什么还需要 LSTM?既然有了 RNN,为什么还需要 Transformer?



2 Attention 注意力机制

在介绍 Transformer 的整体架构(如下图所示)之前,我们先来介绍它所采用的 Attention 注意力机制,后文简称 Attention 机制。要知道原论文的标题就是《Attention Is All You Need》,可见 Attention 机制的地位之高。

在这里插入图片描述

Transformer 对 Attention 机制的描述如下图所示:

在这里插入图片描述

你可能会好奇上图中的 Q , K , V Q, K, V Q,K,V 矩阵都是什么?为什么要用 Q , K , V Q, K, V Q,K,V 去命名?接下来,我们将进行介绍。

对 Attention 机制的介绍会比较长,但个人感觉其中的原理还蛮有意思的。



2.1 什么是 Q、K、V 矩阵?

Q , K , V Q, K, V Q,K,V 矩阵的全称:

  • Q —— Query 查询
  • K —— Key 键
  • V —— Value 值

是不是一股子查字典的味道扑鼻而来!我们可以通过一个搜索引擎的例子来加深理解:

在这里插入图片描述

假设我们想要在 Google 学术中搜索所有 Attention 相关的论文,那么我们的 q u e r y \mathrm{query} query 就应该是 “attention”。搜索引擎会立即根据标题和查询的相似度来给出搜索结果,这里的标题可以理解为关键字 k e y 1 , k e y 2 , k e y 3 \mathrm{key_1, key_2, key_3} key1,key2,key3。也就是说,搜索引擎根据 q u e r y \mathrm{query} query 与各个 k e y \mathrm{key} key 的相似度的高低,按序给出若干搜索结果 v a l u e 1 , v a l u e 2 , v a l u e 3 \mathrm{value_1, value_2, value_3} value1,value2,value3。最终的搜索结果可以看作 v a l u e 1 , v a l u e 2 , v a l u e 3 \mathrm{value_1, value_2, value_3} value1,value2,value3 的按权求和,其中的权重就是 q u e r y \mathrm{query} query 与各个 k e y \mathrm{key} key 的相似程度,即按不同的比例从各个论文中都吸取了一些内容。



2.2 Attention Value 计算流程

在上一节中,我们已经用搜索引擎的例子讲解了 Q , K , V Q, K, V Q,K,V 矩阵的含义。在本节中,我们将继续介绍 Attention 机制中的 Q , K , V Q, K, V Q,K,V 矩阵是如何被使用的。详细的计算流程如下图所示:

在这里插入图片描述
阶段 1:通过 F ( Q , K ) F(Q,K) F(Q,K) 公式来计算 Q Q Q 和各个 K e y Key Key 的相似度,得到分数 s 1 , s 2 , s 3 , s 4 s_1,s_2,s_3,s_4 s1,s2,s3,s4。针对 F ( Q , K ) F(Q,K) F(Q,K) 的具体形式,一般采用的是向量点乘的方式。这是源于向量点乘的几何意义,即向量点乘的结果越大表明两个向量越相似。

阶段 2:使用类 S o f t M a x ( ) \mathrm{SoftMax()} SoftMax() 函数对分数 s 1 , s 2 , s 3 , s 4 s_1,s_2,s_3,s_4 s1,s2,s3,s4 进行归一化:

a i = S o f t M a x ( s i ) = e a i ∑ j = 1 n e a j a_i=SoftMax(s_i)=\frac{e^{a_i}}{\textstyle \sum_{j=1}^{n}e^{a_j}} ai=SoftMax(si)=j=1neajeai

得到注意力分数 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4。个人理解,就是把分数 s s s 的值缩放到 [ 0 , 1 ] [0, 1] [0,1] 区间内,并使得 ∑ i a i = 1 \textstyle \sum_{i}^{} a_i=1 iai=1

阶段 3:令注意力分数 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4 为权重,对各个 V a l u e Value Value 进行加权求和,得到最终的 Attention Value。

图中的 s 代表 score,a 代表 attention score;类 S o f t M a x ( ) \mathrm{SoftMax()} SoftMax() 是因为 Transformer 并不是直接使用的原始 S o f t M a x ( ) \mathrm{SoftMax()} SoftMax() 函数,后文会介绍;这图的配色是真丑啊,我无能为力 😇



2.3 Self-Attention 自注意力机制

实际上在 Transformer 的编码器中,采用的是 Self-Attention 自注意力机制,后文简称 Self-Attention 机制。

区别于上一节介绍的 Attention 机制,Self-Attention 机制进一步要求 Q = K = V Q=K=V Q=K=V。也就是说,针对一个矩阵,让它计算自己与自己的相似度,并且对自己的值进行加权求和。这就是 “自注意力” 一词的由来。

假设我们需要处理 “never give up” 这个短语,那么先要通过词嵌入将字符串转换为词向量矩阵 X X X(否则计算机无法处理),然后再令 Q = K = V = X Q=K=V=X Q=K=V=X 即可。之后,按照上一节介绍的计算流程进行处理,如下图所示:

在这里插入图片描述

由于 Transformer 最开始做的是机器翻译,属于 NLP 领域,所以本文举的例子都是字符串。

现在,让我们回过头来看 Transformer 原文中的图:

在这里插入图片描述

其中 Q , K , V Q,K,V Q,K,V 矩阵的含义已知, M a t M u l \mathrm{MatMul} MatMul 无非就是矩阵乘法, S o f t M a x \mathrm{SoftMax} SoftMax 的含义已知。

注意一

实际操作中 Q , K , V Q,K,V Q,K,V 并不直接等于 X X X,而是:

Q = X W Q , K = X W K , V = X W V Q=XW^Q, K=XW^K, V=XW^V Q=XWQ,K=XWK,V=XWV

其中 W Q , W K , W V W^Q, W^K, W^V WQ,WK,WV 是可以训练的参数矩阵。Transformer 之所以不直接使用 X X X,而是使用通过矩阵乘法生成的三个矩阵,是因为使用三个可训练的参数矩阵,可以增强模型的拟合能力。

上图中没有画出也没有使用该操作,后文的 Multi-Head Attention 多头注意力机制才画了并使用了该操作。

注意二

上图中的 S c a l e \mathrm{Scale} Scale 缩放操作是指:

S o f t M a x ( Q K T d k ) V SoftMax(\frac{QK^T}{\sqrt{d_k}})V SoftMax(dk QKT)V

其中 d k d_k dk 是指 K K K 矩阵的维度。由于 d k d_k dk 越大, Q K T QK^T QKT 运算结果的方差越大,因此通过 S c a l e \mathrm{Scale} Scale 缩放操作让方差变小,从而使训练时的梯度更新更稳定。

上图中的 M a s k ( o p t . ) \mathrm{Mask(opt.)} Mask(opt.) 操作是指因果遮罩,我们后面再讲。标明 ( o p t . ) \mathrm{(opt.)} (opt.) 是因为在编码器中不使用该操作,在解码器中要使用该操作,所以这个操作是可选的而非必须的。



2.3 Multi-Head Attention 多头注意力机制

根据前文的介绍,我们已经一步步地从 Attention 机制走到了 Self-Attention 机制,但这还不是 Transformer 实际采用的注意力机制。Transformer 在 Self-Attention 机制的基础上,进一步得到了 Multi-Head Attention 多头注意力机制,后文简称 Multi-Head Attention 机制。如下图所示:

在这里插入图片描述

其实这个图一点也不复杂,紫色部分的 Scaled Dot-Product Attention 就是我们上一节讲的 Self-Attention 机制,而灰色部分的 Linear 就是我们上一节讲的注意一,即为 Q , K , V Q,K,V Q,K,V 各自乘上一个参数矩阵。区别在于:在 Multi-Head Attention 机制中, Q , K , V Q,K,V Q,K,V 各自将乘上多个参数矩阵。我们接下来将介绍这样做的好处。

多头是什么?

我们假设 head 为 2 即 h = 2 h=2 h=2,也就是把原来一个参数矩阵 W W W,劈开为两个参数矩阵 W 1 , W 2 W_1, W_2 W1,W2,如下图所示:

在这里插入图片描述

其中词向量矩阵的维度为 3 × d m o d e l 3\times d_{model} 3×dmodel,两个参数矩阵合起来的维度为 d m o d e l × d m o d e l d_{model}\times d_{model} dmodel×dmodel,单个参数矩阵的维度为 d m o d e l × d q d_{model}\times d_{q} dmodel×dq,其中 h × d q = d m o d e l h\times d_{q} = d_{model} h×dq=dmodel,如右上角虚线框所示(注意:由于我这里拿的是 W Q W^Q WQ 举例,因此维度写的是 d q d_{q} dq)。可以看出,Multi-Head Attention 机制就是把 1 1 1 个大小为 d m o d e l × d m o d e l d_{model}\times d_{model} dmodel×dmodel 的参数矩阵,劈开为了 h h h 个大小为 d m o d e l × d q d_{model}\times d_{q} dmodel×dq 的参数矩阵。

针对 X X X W 1 , W 2 W_1,W_2 W1,W2 之间的矩阵乘法:根据矩阵乘法的原理可知, X X X 分别和 W 1 , W 2 W_1,W_2 W1,W2 相乘与 X X X W 1 W 2 W_1W_2 W1W2 相乘的结果是一样的。因此为了简化操作,我们可以先不将 W 1 W_1 W1 W 2 W_2 W2 劈开,上图也体现了这一点。

下图展示了上图中 S o f t M a x \mathrm{SoftMax} SoftMax 的具体过程:

在这里插入图片描述

S o f t M a x \mathrm{SoftMax} SoftMax 这一步,我们必须将 Q 1 Q 2 Q_1Q_2 Q1Q2 K 1 K 2 K_1K_2 K1K2 劈开,然后让 Q 1 Q_1 Q1 去乘 K 1 T K^T_1 K1T,让 Q 2 Q_2 Q2 去乘 K 2 T K^T_2 K2T。相应地,得到 h = 2 h=2 h=2 个权值矩阵。最后,再拿 h = 2 h=2 h=2 个权值矩阵分别去乘 V 1 V_1 V1 V 2 V_2 V2 矩阵,得到最终的 Z 1 Z_1 Z1 Z 2 Z_2 Z2 矩阵。

个人思考:只让 Q 1 Q_1 Q1 去乘 K 1 T K^T_1 K1T,只让 Q 2 Q_2 Q2 去乘 K 2 T K^T_2 K2T,是否属于一种局域而非全局的自注意力?

为什么使用多头?

在这里插入图片描述
如果 h = 1 h= 1 h=1,那么最终可能得到的是一个各个位置只集中于自身位置的权值矩阵;如果 h = 2 h= 2 h=2,那么就还有可能得到另一个注意力权重分配稍微合理的权值矩阵; h = 3 h= 3 h=3 同理。因此,作者提出多头这一做法,用于克服「模型在对当前位置的信息进行编码时,过度将注意力集中于自身的位置」的问题。

至此,关于注意力机制的介绍结束 🥳



3 Transformer 模型架构

我们在前文已经介绍完了 Transformer 的重头戏部分,下面我们从左到右、从下到上来介绍 Transformer 的整体架构:

在这里插入图片描述



3.1 Positional Encoding 位置编码

为什么使用位置编码?

  • ① 对于任何一门语言,单词在句子中的位置以及排列顺序是非常重要的,它们不仅是一个句子的语法结构的组成部分,更是表达语义的重要概念。一个单词在句子中的位置或者排列顺序不同,可能会导致整个句子的意思发生偏差。
  • ② Transformer 抛弃了 RNN、CNN 作为序列学习的基本模型,而是完全采用 Attention 机制取而代之,从而导致词序信息丢失,模型没有办法知道每个单词在句子中的相对位置信息和绝对位置信息。

RNN 自带循环结构,因此天然能够捕捉词序信息。

如何进行位置编码?
在这里插入图片描述

其实就是让词向量 + + + 位置编码,位置编码的计算公式如下:

P E ( p o s , 2 i ) = sin ⁡ ( p o s 1000 0 2 i / d m o d e l ) P E ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 1000 0 2 i / d m o d e l ) \begin{alignat}{2} PE(pos,2i) &= \sin (\frac{pos}{10000^{2i/d_{model}}}) \\ PE(pos,2i+1) &= \cos (\frac{pos}{10000^{2i/d_{model}}}) \end{alignat} PE(pos,2i)PE(pos,2i+1)=sin(100002i/dmodelpos)=cos(100002i/dmodelpos)

其中 p o s pos pos 表示单词在句子中的绝对位置,比如:“有” 在 “我有一只猫” 中的 p o s pos pos 1 1 1,假设从 0 0 0 开始计数。 d m o d e l d_{model} dmodel 表示每个词向量的维度, i i i 表示一个词向量中的第 i i i 维,而 2 i 2i 2i 表示这是一个偶数维度, 2 i + 1 2i+1 2i+1 表示这是一个奇数维度。也就是说,偶数维度根据公式 (1) 来计算位置编码,奇数维度根据公式 (2) 来计算位置编码。

Q:为什么是让位置编码和词向量相加,而不是拼接?
A:相加或拼接都是可以的。只是因为词向量本身已经有 512 512 512 维了,如果再拼接一个 512 512 512 维的位置向量变为 1024 1024 1024 维,会导致训练速度下降。



3.2 模型训练过程

Transformer 的训练过程如下图所示:
在这里插入图片描述
对于 “我” 字,由于上一轮没有预测结果,因此模型纯靠输出的编码矩阵去预测 “我” 字的翻译结果 “I”;对于 “有” 字,由于上一轮的预测结果是 “I”,因此模型依靠输出的编码矩阵和 “I” 去预测 “有” 字的翻译结果 “have”;以此类推。

但在实际的训练过程中,通常采用了一种名为 t e a c h e r - f o r c i n g \mathrm{teacher\text{-}forcing} teacher-forcing 的训练方式。具体是指,不使用上一次的输出作为下一次的输入,而是直接使用上一次输出对应的标准答案(ground truth)作为下一次的输入,如下图所示:

在这里插入图片描述
这又引出了一个新问题:当我们翻译到 “有” 的时候,我们应该只能知道上一轮的翻译结果 “I”,而不应该知道后面的翻译结果 “have a cat”。因此 Transformer 采用了因果遮罩机制,对解码器的输入矩阵进行了处理。

个人理解:你可以把这个翻译过程理解为同声传译,只要讲话人不说出下一个字,我们就不知道该如何翻译。



3.3 Masked 因果遮罩

解码器中的 Masked Multi-Head Attention 用的就是因果遮罩。

这是为了让前面位置的信息无法关注到后面位置的信息,比如:翻译 “我” 的时候,无法关注到 “有一只猫” 的翻译结果 “have a cat”,但是它能看到自己的翻译结果 “I”;翻译 “有” 的时候,无法关注到 “一只猫” 的翻译结果 “a cat”,但是它能看到前面的翻译结果以及自己的翻译结果 “I have”。具体操作如下图所示:

在这里插入图片描述
其中让 Q K T QK^T QKT 右上角的元素为 − ∞ -\infty ,经过 S o f t M a x \mathrm{SoftMax} SoftMax 后变为 0 0 0,即权重为 0 0 0,从而不会被关注到。



3.4 Output 输出

Transformer 的输出结构如下图所示:

在这里插入图片描述
解码器的输出先经过一次线性变换,再通过 S o f t M a x \mathrm{SoftMax} SoftMax 得到概率分布。最后根据词典,选择概率最大的单词作为预测的输出。

这个地方也被面试的老师问到过 😇



4 Transformer 的细节

4.1 Add & Norm

两次面试都有被问到这个问题。

什么是 Add?

下图中蓝色虚线指向的就是 A d d \mathrm{Add} Add 操作:
在这里插入图片描述

也就是在 Multi-Head Attention 的输出 Z Z Z 的基础上加上原始输入 X X X

X + Z = X + M u l t i - H e a d   A t t e n t i o n ( X ) X+Z=X+\mathrm{Multi\text{-} Head\ Attention}(X) X+Z=X+Multi-Head Attention(X)

简单理解,为了防止注意力机制让模型学得更烂了,所以还是把原始输入也带上吧 😇

为什么使用 Add?

深度神经网络在训练过程中可能出现退化现象。退化指的是随着网络层数的增加,损失函数的值先减小后增大,导致网络性能不再提升甚至下降。这种现象发生的原因在于,增加的层数并没有有效地增强网络的表达能力,反而可能引入了不必要的复杂性。

考虑一个神经网络,其实际最佳层数可能是 18 18 18 层。然而,我们可能基于理论假设认为更深层的网络会更好,因此可能会设计一个 32 32 32 层的网络。在这样的网络中,后 14 14 14 层实际上并不增加任何有用的表达能力,反而可能干扰到网络的性能。为了避免这种情况,我们需要确保这额外的 14 14 14 层能够实现恒等映射:

F ( X ) = X F(X)=X F(X)=X

即其输出恰好等于输入。然而,神经网络的参数是通过训练获得的,而确保这些参数能够精确地实现 F ( X ) = X F(X)=X F(X)=X 的恒等映射是极具挑战性的。为了解决这一问题,大神们提出了残差神经网络 ResNet 以克服神经网络退化的挑战。

拓展:残差块

ResNet 中的一个残差块如下图所示:

在这里插入图片描述

其中 X X X 是输入值, F ( X ) F(X) F(X) 是经过一次线性变换和一次激活的输出,也被称为残差。在第二次线性变换之后,第二次激活之前,让 F ( X ) F(X) F(X) 加上输入值 X X X,这条路径被称为 s h o r t c u t \mathrm{shortcut} shortcut 连接。

这里了解一下概念即可,如果我真要学 ResNet,我会看论文原文 😇

为什么 Add 能够防止网络退化?

执行 A d d \mathrm{Add} Add 操作后,原本的神经网络层的输出值由 F ( X ) F(X) F(X) 变为 H ( X ) H(X) H(X)

H ( X ) = F ( X ) + X H(X)=F(X)+X H(X)=F(X)+X

而要想让 H ( X ) = X H(X)=X H(X)=X 以实现恒等映射,只需要让 F ( X ) = 0 F(X)=0 F(X)=0 即可。通过训练,让神经网络的输出变为 0 0 0 比变为 X X X 要容易得多。这是因为神经网络的初始参数通常为 [ 0 , 1 ] [0,1] [0,1] 之间的随机数,所以输入值 X X X 经过神经网络的变换后很容易接近于 0 0 0,即输出 F ( X ) = 0 F(X)=0 F(X)=0,如下图所示:

在这里插入图片描述
在这个简单的神经网络中只有线性变换,没有偏置项也没有激活函数。可以看出,由于随机初始化的参数接近于 0 0 0,因此该网络的输出值为 ( 0.6 , 0.6 ) (0.6,0.6) (0.6,0.6),非常接近于 ( 0 , 0 ) (0,0) (0,0) 而非输入值 ( 2 , 1 ) (2,1) (2,1)。因此,相较于让模型学习出 F ( X ) = X F(X)=X F(X)=X,学习出 F ( X ) = 0 F(X)=0 F(X)=0 更加容易。

除此之外,由于 ResNet 中采用的 ReLU 激活函数能够将负数激活为 0 0 0,因此也能够帮助模型更快地学习出 F ( X ) = 0 F(X)=0 F(X)=0,从而解决了学习恒等映射的问题。如此一来,神经网络能够自行决定哪些层为冗余层,并通过学习残差 F ( X ) = 0 F(X)=0 F(X)=0 来实现恒等映射,使得含有冗余层的网络的效果与不含冗余层的网络的效果相同,在很大程度上解决了网络的退化问题。

注意:我这里说的神经网络的原始输出是 F ( X ) F(X) F(X),加入残差连接后的输出是 H ( X ) H(X) H(X)。由于 + X +X +X 是我们手动完成的,因此不需要被训练,需要被训练的是 F ( X ) F(X) F(X)。我们之前的训练目标是让 F ( X ) F(X) F(X) 等于 X X X,加入残差连接后的训练目标是让 F ( X ) F(X) F(X) 等于 0 0 0

什么是 Norm?

神经网络训练前,通常会对输入数据进行归一化处理,这一步骤旨在实现两个目标:

  • 一是提升训练速度;
  • 二是增强训练过程的稳定性。

为什么使用 LN 而非 BN?

层归一化 LN 和批量归一化 BN 的区别如下图所示:

在这里插入图片描述
LN 是在同一样本的不同位置的神经元之间进行归一化,BN 是在不同样本的同一位置的神经元之间进行归一化。BN 针对的是相同维度的特征,但由于 NLP 领域的输入通常是词向量,单独分析其任一维度是没有意义的,因此更适合采用 LN 方法。



4.2 留个坑



Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐