transformer
arXiv:1706.03762
1. 问题提出
全连接神经网络(FCN),可以很好的处理输入为1个向量(特征向量)的情况,但是如果输入是一组向量,FCN处理起来不太方便
以词性标记的问题为例
对于处于同一个句子中的相同的2个单词saw
,词性不同,前者为动词(V),后者为名词(N)
如果尝试使用FCN去解决这个问题,将每个单词转化为向量输入FCN,对于相同的2个单词,FCN的输出应该是相同的,不能根据单词在句子中所处的不同位置做出判断,FCN只关注外表
Sequence-to-Sequence,输入是序列,输出也是序列,没有固定的数量关系,输出序列的数量是由模型决定的
解决seq2seq问题的基本的框架是Encoder-Decoder,以机器翻译作为例子直观理解
-
Encoder
编码器,接受输入语言A的某个句子序列,通过Encoder产生这个语言A这个句子对应的语义信息
-
Decoder
解码器,根据Encoder生成的语义信息,使用Decoder生成目标语言B对应的句子
另一种理解,机器翻译Encoder-Decoder模型模拟人工进行翻译的情形,人读懂语言A某个句子的意思(语义信息)之后,根据这个句子意思,使用语言B将这个句子的意思表达出来
2. Self-Attention
2.1 定义
整体结构如下
这样的结构可以叠加多层
Self-attention内部结构如下
输入原始向量\(\vec{a}\),经过Self-attention后输出经过处理的向量\(\vec{b}\),是考虑所在向量序列的上下文的输出
2.2 工作原理
2个向量的关联程度\(\alpha\)计算如下,即attention score
分别计算\(a^1\)和\(a^1\)、\(a^2\)、\(a^3\)、\(a^4\)的关联程度\(\vec{\alpha_1}\),再经过softmax得到\(\vec{\alpha_1^\prime}\)
再求出\(\vec{v}\),和刚刚求得的\(\vec{\alpha_1^\prime}\)作内积(加权求和),即得输入\(\vec{a^1}\)考虑上下文之后得最终输出\(\vec{b^1}\)
以上处理是对向量\(\vec{a^1}\)输出\(\vec{b^1}\)的处理过程,同理对\(\vec{a^2}\)、\(\vec{a^3}\)、\(\vec{a^4}\)也做类似的处理,可得\(\vec{b^2}\)、\(\vec{b^3}\)、\(\vec{b^4}\)
2.3 矩阵表示
由输入向量序列得到Q、K、V矩阵
attention score计算
输出计算
整体结构如下
2.4 直观理解
- 理解1:针对某一个具体得问题,对于向量序列中的某一个向量,比如\(\vec{a^1}\),如果\(\vec{a^1}\)和另外一个向量\(\vec{a^i}\)的关联程度比较大,则计算出来的attention score就比较大,加权求和得到最后的输出向量,就和\(\vec{a^i}\)比较相近
- 理解2:q(query)、k(key)、v(value)
- q,可以理解为要查询当前向量,想要或者其和序列中哪个向量关系更紧密
- k,可以理解为对其他向量提取了一个关键字,用于和q计算关联程度
- v,可以理解为其他向量对于最后输出向量的贡献值,(k,v可以结合起来考虑,类比键值对的概念理解)
2.5 multi-head Self-attention
为什么需要multi-head Self-attention?
一组权重\(W^q\)、\(W^k\)、\(W^v\),对应了输入序列中的一中关系,可能存在多种关系,所有需要多组参数,称之为multi-head
对multi-head Self-attention的理解
原论文描述
Instead of performing a single attention function with dmodel-dimensional keys, values and queries,
we found it beneficial to linearly project the queries, keys and values h times with different, learned
linear projections to dk, dk and dv dimensions, respectively. On each of these projected versions of
queries, keys and values we then perform the attention function in parallel, yielding dv-dimensional
output values. These are concatenated and once again projected, resulting in the final values, as
depicted in Figure 2.
在网上看到一种说法是:“将QKV均分成h份”(h表示多头注意力机制的头数),按照原文的理解应该是对QKV进行h次线性映射(linearly project),为了减少头
的维度和计算量,采用的设计是\(d_k=d_v=d_{model}/h=64\),这样只需要4次映射(\(W^Q,W^K,W^V,W^O\))(可理解为,同时进行8个头的映射,增强并行计算),具体流程如下
-
step1:Linearly Project
输入原始QKV,经\(W^Q,W^K,W^V\)映射得\(Q^\prime,K^\prime,V^\prime\),对\(Q^\prime,K^\prime,V^\prime\)进行切分,分别得8个头的QKV
-
step2:Scaled Dot-Product Attention
将8个头的QKV送入自注意力层,得到各自的输出
-
step3:Concat
对8头输出进行拼接
-
step4:Linear
经\(W^O\)对拼接后的结果再进行映射,得到最终输出
2.6 Cross Attention
Decoder的Self-attention的输出作为q,Encoder输出向量序列作为k、v,作attention运算,再送入后面的流程进行处理
对注意力机制的理解,参考https://blog.csdn.net/malefactor/article/details/78767781
因此,下图从Encoder过来是2个输入(k和v),从Decoder过来是1个输入(q)
3. 整体结构
4. Encoder
针对原始输入序列,产生中间信息(不同的问题,产生不同的中间信息,在机器翻译问题中,产生的是语义信息),为Decoder服务
整体结构如下
工作过程如下
- 对于输入序列,首先进行Self-attention和residual处理
- 对上一步输出进行layer normalization处理
- 对上一步输出送入FC和residual处理
- 最后再进行layer normalization处理产生block输出,可作为下一个block的输入
5. Decoder
根据Encoder生成的中间信息,产生输出序列
整体结构如下
工作过程如下
对Decoder输入一个开始标志(BEGIN),Decoder就开始运行,运行过程参考词语接龙理解
- 根据开始标志和中间信息,产生第一个输出\(\vec{o_1}\)
- 根据中间信息和\(\vec{o_1}\),产生第二个输出\(\vec{o_2}\)
- 以此类推,直到产生的输出是结束标志,输出结束
Masked Self-attention
对于Autoregressive型的Transformer,Decoder需要将上一次产生的输出作为下一次的输入,因此对于Decoder部分第一项Self-attention处理来说,当前输入向量之后没有东西,只能对当前输入向量之前的向量作Self-attention处理,称之为Masked Self-attention
Masked Self-attention示意图如下,\(\vec{a^2}\)只能考虑对\(\vec{a^1}\)和\(\vec{a^2}\)作Self-attention,\(\vec{a^3}\)只能考虑对\(\vec{a^1}\)、\(\vec{a^2}\)、\(\vec{a^3}\)作Self-attention处理
除了Masked Self-attention之外的流程,和Encoder是相类似的
6. Positional Encoding
上述Self-attention并没有考虑当前输入向量在整个输入向量序列中的位置关系,考虑对输入向量加上一个位置向量
位置向量\(e^i\)可以是手工设计的,也可以是从数据中学习出来的
7. Self-attention vs RNN
RNN也用来处理向量序列输入,和Self-attention相比,最主要的区别是RNN不能并行处理,输出之间存在依赖关系,而Self-attention可以用矩阵的方式表达,是可以并行处理的。此外,如果RNN要考虑第一个向量和最后一个向量之间的关系,要传递很多次memory,比较难,而Self-attention任意两个向量之间是通过计算attention score衡量联系程度的,所以远距离向量之间的关系比较容易得出。
进一步学习
- 各种训练的tips
- 阅读论文
- 各种应用