参考:https://blog.youkuaiyun.com/han_xiaoyang/article/details/86560459
https://jalammar.github.io/illustrated-transformer/
以下仅为个人学习笔记
1. 简介
- Google于2017年在论文Attention is All You Need中提出。
论文地址:https://arxiv.org/pdf/1706.03762.pdf - 第三方库:https://github.com/tensorflow/tensor2tensor
pytorch支持:http://nlp.seas.harvard.edu/2018/04/03/attention.html - 特征提取能力:Transformer > LSTM > CNN
1.1 网络结构
- 总体结构:Transformer由Encoders和Decoders组成,每个Encoders包含6个Encoder,每个Decoders包含6个Decoder,总体结构如下图所示:

- Encoder 与 Decoder 的结构:每个Encoder的结构相同,但不会共享权值。自注意力层 (self-Attention)帮助编码器在对每个单词编码时关注输入句子的其他单词。Decoder中的“编码-解码注意力层”用来关注输入句子的相关部分。 每个Encoder与Decoder的结构如下图所示:

- Encoder的输入:每个单词都被嵌入为512维的向量。词嵌入过程只发生在最底层的编码器中。所有的编码器都接收一个向量列表,列表中每个向量的大小为512维。下一个Encoder接收前一个Encoder的输出。向量列表的大小是可以设置的超参数,一般是训练集中最长句子的长度。
- 核心特性:输入序列中每个位置的单词都有自己独特的路径流入编码器。在自注意力层中,这些路径之间存在依赖关系。而前馈层没有这些依赖关系。因此在前馈(feed-forward)层时可以并行执行各种路径。即,每个单词经过自注意力层的编码后,然后各自通过前馈神经网络层,各自通过互相之间没有依赖关系,因此可以并行执行。
1.2 优点
(1) Transformer改进了RNN最被人诟病的训练慢的缺点,利用self-attention机制实现快速并行。
(2) Transformer可以增加到非常深的深度,充分发掘DNN模型的特性,提升模型准确率。
2. self-Attention
- 宏观理解:将所有相关单词的理解融入到正在处理的单词中。可以与循环神经网络处理序列问题进行比对。
2.1 self-Attention的计算过程
为了方便理解,可以先看向量形式的计算过程,即先从一个词的计算过程进行理解。以下,直接从矩阵形式计算过程进行总结,实际在计算机中运算时是以矩阵形式。变量声明:假设所有句子中最长的序列为m,词嵌入维度为n,n=512。
(1) 计算查询矩阵(query vector)、键矩阵(key vector)和值矩阵(value vector)。
- 输入句子的词嵌入矩阵为 X ∈ R m × n X\in R^{m\times n} X∈Rm×n,即每一行代表一个单词的词嵌入向量。
- 三个训练权重矩阵分别为 W Q , W K , W V W^Q,W^K,W^V WQ,WK,WV,其维度均为 n × n ~ , n ~ = 64 n\times \widetilde{n},\widetilde{n}=64 n×n ,n =64。
- 那么得到的矩阵
Q
,
K
,
V
Q,K,V
Q,K,V的维度为
m
×
n
~
m\times \widetilde{n}
m×n
.
其计算过程如下如图所示:

(2) 得到自注意力层的输出。
Z
=
s
o
f
t
m
a
x
(
Q
×
K
T
d
k
)
⋅
V
Z=softmax(\frac{Q\times K^T}{\sqrt{d_k}})\cdot V
Z=softmax(dkQ×KT)⋅V
其计算过程如下图所示:

- 其中 Q × K T Q\times K^T Q×KT 是计算得分矩阵。得分矩阵的意义:拿输入句子中的每个单词对当前单词打分,这些分数决定了在编码当前单词的过程中有多重视句子的其他单词。或者说每个单词对编码当前单词的贡献。
- d k = 8 \sqrt{d_k}=8 dk=8,8是论文中使用的键向量的维数 d k = 64 d_k=64 dk=64 的平方根,这会让梯度更稳定。这里也可以使用其它值,8只是默认值。
- 每个值向量乘以softmax分数的意义:关注语义上相关的单词,并弱化不相关的单词。
2.2 Multi-Headed Attention 机制
- 多头注意力机制:通过多组独立的训练权重矩阵得到多组查询矩阵、键矩阵和值矩阵,从而得到多个不同的
Z
Z
Z 矩阵。论文设置了8组,即有8个注意力头。(此处多提一下,
8
∗
n
~
=
512
8*\widetilde{n}=512
8∗n
=512 与词嵌入向量的维度
n
=
512
n=512
n=512 相对应。)
需要注意的是,前馈层接收的是一个与词嵌入矩阵维度相同的矩阵,因此需要将8个注意力头拼接起来(横向拼接,即 [ Z 0 , Z 1 , ⋯   , Z 7 ] [Z_0,Z_1,\cdots,Z_7] [Z0,Z1,⋯,Z7])再乘以一个 W o W^o Wo 矩阵进行压缩,然后再输入到前馈层。 W o W^o Wo 矩阵也是需要训练的。 - 到目前为止,self-Attention 的整体过程的宏观结构如下图所示:

- 多头注意力机制为 Self-Attention 带来的改善:
(1) 扩展了模型关注不同位置的能力。如果只有一个注意力头,很可能永远被当前词所决定。
(2) 给出了注意力层的多个 “表示子空间” (representation subspaces)。通过训练,8个注意力头将词嵌入投影到不同的子空间,增加了模型的语意表达能力。
3. 使用位置编码表示序列的顺序 (positional encoding)
想一想,根据之前的描述是不是没有考虑单词之间的顺序,为了解决这个问题,Transformer为每个单词添加了位置编码向量 (positional encoding),这些向量的值遵循特定的模式。原始论文中计算位置编码向量的公式见3.5节,这种编码方式的优点是能够扩展到未知的序列长度 (例如,当我们训练出的模型需要翻译远比训练集里的句子更长的句子时)。举例如下图所示:

4. 残差 (Residuals) 和 层-归一化 (Layer-Normalization)
- 在编码器和解码器结构中都有一个细节:在每个 Encoder/Decoder 中的每一个子层周围都一个残差连接,并都跟随着一个 Layer-Normalization,如下图所示:

- Layer-Normalization参考:https://arxiv.org/abs/1607.06450
5. Decoders
以上主要都是基于Encoders来理解的,这部分补充一些关于Decoders的内部细节。
5.1 自注意力层和编码-解码注意力层
- 结构:一个包含2层编码-解码结构的Transformer如下图所示:

- 工作流程:解码器的工作流程宏观上如下图所示:

解码阶段的每个步骤都会输出一个输出序列,直到输出一个特殊的终止符号,它表示transformer的解码器已经完成了它的输出。每个步骤的输出在下一个时间步被提供给底端解码器。需要注意的是,解码器也会给每个单词添加位置编码。
- 自注意力层:在解码器中,自注意力层只被允许处理输出序列中更靠前的那些位置。在softmax步骤前,它会把后面的位置给隐去(把它们设为-inf)。
- 编码-解码注意力层:顶端编码器的输出之后会转化为一个包含向量 K K K(键向量)和 V V V(值向量)的注意力向量集 。这些向量将被每个解码器用于自身的“编码-解码注意力层”,这些层可以帮助解码器关注输入序列的哪些位置。另外,“编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵。
5.2 最终的线性变换和Softmax层
- 线性变换层:解码组件最后会输出一个实数向量,线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到“输出词汇表”大小的向量,向量的每一个维度对应该位置单词的分数。
- softmax层:将线性变换层的分数向量转变成概率向量,并输出概率最高的位置对应的单词。