《Attention Is All You Need》阅读笔记
论文标题
《Attention Is All You Need》
- XXX Is All You Need 已经成一个梗了,现在出现了很多叫 XXX Is All You Need 的文章,简直标题党啊,也不写方法,也不写结果,有点理解老师扣论文题目了。
作者
这个作者栏太夸张了。八个作者全部标星,均等贡献。甚至专门写了一段介绍每个人的工作。
初读
摘要
-
大概介绍结构:
没有用之前的循环或者卷积,完全使用注意力机制
-
秀结果:在机器翻译任务上表现很好,
- 在 WMT 2014 英德语翻译任务中实现了 28.4 BLEU,提高了 2 BLEU以上。
- 在WMT 2014 英法翻译任务中实现了 41.0 BLEU
-
训练很快:
并行性更高,英法翻译那个只用了 8 张卡 3.5 天(没见过世面的我依然觉得很久的哇)。
结论
-
依然是结构简介:
用多头自注意力取代了编码器-解码器架构中最常用的循环层。
-
依然是强调结果:
对比之前用循环或者卷积的架构,Transformer 又快又好。WMT 2014 的英法和英德都达到了最先进的水平。
-
展望一下注意力的未来:
作者很看好注意力机制,并计划将注意力机制扩展到多模态,图像、音频和视频等。还计划研究生成低时序化方向。
-
还公布了代码,好耶。
再读
Section 1 Introduction
导言很简短,像是对摘要的扩写。
-
第一段:提一嘴时序模型现有方法
时序模型和那种编码器-解码器结构之前的统治者一直都是 RNN ,尤其是 LSTM 和 GRU。
-
第二段:简要介绍了循环网络缺点
循环的把之前步的隐藏态作为下一步的输入,要想记住比较靠前的东西就需要比较长的序列,但是长了就会占用很多内存,而且没有并行性。虽然已经在提高模型性能了,但是并行性依然不够。
-
第三段:注意力机制现有应用
注意力机制以及在时序模型里有用到了,好处是不太考虑输入与输出序列之间的距离。
-
第四段:Transformer 闪亮登场
- 完全依赖于注意力机制来绘制输入和输出之间的全局依赖关系。
- 运行更多的并行化,8 张 P100 上跑 12 个小时就能在翻译方面达到最新水平。
Section 2 Background
-
第一段:当前目标之一 —— 减少顺序计算
-
引入卷积替换循环以减少顺序计算,并行计算所有输入和输出位置的隐藏表示。
-
Extended Neural GPU
-
ByteNet
-
ConvS2S
-
-
引入卷积的缺点:将两个任意输入或输出位置的信号关联起来所需的操作随着位置之间的距离增加而增加,使远距离位置之间的依赖关系学起来很难。
-
ConvS2S 的增加是线性的
-
ByteNet 的增加是对数的
-
-
Transformer 的增加则被减小到恒定数量。
- 代价是平均注意力加权位置降低了有效分辨率 [TODO]。
- 引入了多头注意力抵消了上述代价。
-
-
第二段:提一嘴自注意力是啥
- 是一种将单个序列的不同位置联系起来以计算序列的表示的注意机制。
- 已经用在各种任务上了。
-
第三段:提一嘴端到端记忆网络
端到端记忆网络基于循环注意力机制,在简单的语言问答和建模任务中表现很好。
-
第四段:Transformer 再次闪亮登场
是 第一个 完全 使用自注意力的模型。
Section 3 Model Architecture
Transformer 遵循大多数都在用的编码器-解码器结构,使用自回归(过去时刻的输出作为下面的输入,此即为自回归)、自注意力、逐点运算(point-wise)、全连接层。
Encoder and Decoder Stacks 编解码器堆栈
-
Encoder 编码器
-
N = 6 N=6 N=6 个相同的块
-
每块有 2 个子层
- 第一层是多头自注意力层
- 第二层是基于位置的前馈网络
- 两层都上残差连接
- 最后加个层归一化 [TODO]
-
简言之,每个块的子层的输出都为: L a y e r N o r m ( x + S u b l a y e r ( x ) ) \mathrm{LayerNorm}(x+\mathrm{Sublayer}(x)) LayerNorm(x+Sublayer(x))
-
为了促进残差连接,子层以及嵌入层产生的都是维度为 512 的输出 [TODO]。
-
-
Decoder 解码器
- 也是 N = 6 N=6 N=6 个相同的块
- 每块有 3 个子层,从结构上看相当于在编码器的两层之间插了一层
- 第一层添加了掩码 [TODO]
- 插入的之一层对编码器的输出执行多头注意力
- 一样用了残差和层归一化
Attention 注意力机制
为了压缩论文长度,这波压缩也太极限了。属于是懂的人一看就心领神会,不懂人看了也是一脸懵,简称懂得都懂。
Scaled Dot-Product Attention 缩放点积注意力
缩放点积注意力详细见前篇笔记《10.3 注意力评分函数》,内容几乎一致,此处不赘述。此小节大体内容:
- 介绍点积注意力
- 介绍缩放点积注意力
- 介绍为什么缩放
为了简单选择了最简单的点积注意力,缩放一下使概率映射更平滑。
Multi-Head Attention 多头注意力
多头注意力详细见前篇笔记《10.5 多头注意力》,内容几乎一致,此处不赘述。
为了引入可学习的参数以及实现类似卷积多通道的效果引入多头注意力。
本文模型用了 8 头注意力,每个头 64 维。
Applications of Attention in our Model
- 解码器块的第二个子层的 Q 来自上一层的输出,K 和 V 来自编码器的输出。
- 编码器块的注意力子层 Q、K 和 V 均来自上层的输出。
- 解码器块的第一个子层用上了遮掩。
Position-wise Feed-Forward Networks 基于位置的前馈网络
实际上就是用一个 MLP 作用在最后一个维度。也就是对每一个词分别用同一个 MLP 过一遍,就好比 KNN 里 1 × 1 1\times 1 1×1 的卷积核的作用。
本文用的 MLP 内层维度升到 2048,外层输出为 512 维。
Embeddings and Softmax
两个嵌入层和预 softmax 层线性变换之间共享相同的权重矩阵。
为了放大权重以期与位置编码在大小上匹配,还需要给这些权重乘以 d \sqrt{d} d。
Positional Encoding
位置编码详细见前篇笔记《10.6 自注意力和位置编码》,内容几乎一致,此处不赘述。
自注意力因为并行计算而放弃了顺序操作,为了使用序列的顺序信息,通过在输入表示中添加位置编码来注入绝对的或相对的位置信息。位置编码可以通过学习得到也可以直接固定得到。
这里用三角函数的设计是很精妙的,上面的笔记中也有所记录但是我仍未完全理解。
Section 4 Why Self-Attention
这一部分通过对比一些指标诠释使用自注意力的必要性,主要是三个指标:
-
层计算复杂度
层计算复杂度是每个层的总计算复杂度,这个当然是越低越好。
-
顺序计算数
顺序计算数是当前运算的前序运算数,即下一步计算需要等前面多少步计算完成。因为越低越好,越低并行度越高。
-
最大路径长度
最大路径长度表示信息从一个数据点走到另一个数据点需要走多远,在这里能够表征得到两个位置之间的关系需要的计算量,越近计算量越低,越容易学到长程依赖性(即比较远的信息之间的关联)。
这三个参数的计算方法以及比较详细见前篇笔记《10.6 自注意力和位置编码》,内容几乎一致,此处不赘述。
总之,多方比较的结果是自注意力就是好使。
Section 5 Training
Training Data and Batching
- WMT 2014 英语-德语 数据集
- 450 万个句子
- 使用字节对编码(BPE)[TODO],有 3.7 万个双语共享的词表
- WMT 2014 英语-法语 数据集
- 36 M 个句子
- 拆分标记了 3200 个单词词汇
- 句子对按近似序列的长度分批排列,每个训练批次包含一组句子对
- 2.5 万个源 tokens 和 2.5 万个目标 tokens
Hardware and Schedule
-
硬件配置:
一台带有 8 个 NVIDIA P100 GPU 的机器
-
训练耗时
-
基础模型:
每个 batch 大约需要 0.4 秒,总共 100000 batch ,花费 12 小时训练。
-
大型模型:
每个 batch 大约需要 1.0 秒。总共 300000 batch,花费 3.5 天训练。
-
Optimizer
使用 Adam 优化器,参数设置:
- β 1 = 0.9 \beta_1 = 0.9 β1=0.9
- β 2 = 0.98 \beta_2 = 0.98 β2=0.98
- ϵ = 1 0 − 9 \epsilon = 10^{-9} ϵ=10−9
- 学习率可变
这里的学习率蛮有意思,是根据公式可变的:
l
r
a
t
e
=
d
m
o
d
e
l
−
0.5
⋅
min
(
s
t
e
p
_
n
u
m
−
0.5
,
s
t
e
p
_
n
u
m
⋅
w
a
r
m
u
p
_
s
t
e
p
s
−
1.5
)
lrate=d^{-0.5}_{model}\cdot\min{(step\_num^{-0.5},step\_num\cdot warmup\_steps^{-1.5})}
lrate=dmodel−0.5⋅min(step_num−0.5,step_num⋅warmup_steps−1.5)
- d m o d e l − 0.5 d^{-0.5}_{model} dmodel−0.5 是模型宽度的 − 0.5 -0.5 −0.5 次方,也就是在那些向量越长的时候学习率越小。
- w a r m u p _ s t e p s = 4000 warmup\_steps=4000 warmup_steps=4000
Regularization
使用了三种类型的正则化:
-
Residual Dropout
在每个层,进入残差之前,使用了 P d r o p = 0.1 P_{drop}=0.1 Pdrop=0.1 的 dropout。
在嵌入位置编码的时候也用了同样的 dropput
-
Label Smoothing
使用了 ϵ l s = 0.1 \epsilon_{ls}=0.1 ϵls=0.1 的标签平滑*[TODO]*。这么做会损失困惑度,但是提高了准确性和 BLEU 分数。
Section 6 Results
试了一系列参数
参数字典:
- N N N 表示块数
- d m o d e l d_{model} dmodel 表示模型宽度,即 tokens 转换为向量后的长度。
- d f f d_{ff} dff 表示 MLP 中间隐藏层的输出维度
- h h h 表示多头注意力的头数
- d k d_k dk 表示 key 的维度
- d v d_v dv 表示 value 的维度
- P d r o p P_{drop} Pdrop 表示 dropout 的丢弃率
- ϵ l s \epsilon_{ls} ϵls 表示标签平滑的参数
- t r a i n s t e p s train steps trainsteps :表示 batch 数
三读
TODO List
- 如何理解“平均注意力加权位置降低了有效分辨率”?
- 什么是层归一化?
- 512 的维度为什么能促进残差连接?
- 解码器块第一个子层为什么添加掩码?
- 什么是字节对编码(BPE)?
- 标签平滑 Label Smoothing 是干啥?
如何理解“平均注意力加权位置降低了有效分辨率”?
这里的分辨率可能指的是对特征值别的精细度。
分辨率低是说在加权平均时,所有部分的信息都会被混合在一起,模型可能会忽略或者淡化那些权重较小(即被模型认为不太重要)的部分的信息。
多头注意力的作用是即使某个部分在一个注意力头中的权重较小,它也可能在另一个注意力头中得到足够的关注。有点类似与卷积最后多通道的输出,每个通道或者说这里的每个头都可以关注不同的特征。借此去抵消精细度下降的问题。
什么是层归一化?
层归一化详细见前篇笔记《10.7 Transformer》,内容几乎一致,此处不赘述。
简言之,过去用的批量归一化对每个特征/通道里的元素进行归一化,不适合序列长度会变的 NLP 应用。
层规范化则是对每个样本里的元素进行归一化。
解码器块第一个子层为什么添加掩码?
那个掩码的作用是在训练的时候遮掉后面的内容,防止后面的真实值在前向传播中影响预测。
什么是字节对编码(BPE)?
主要目的是为了数据压缩,算法描述为字符串里频率最常见的一对字符被一个没有在这个字符中出现的字符代替的层层迭代过程。
简单的说,比如英语里有复数、时态之类不同的变换,在这里编码时都归为同一个词。这样最后的字典可以小一点。而且此处的字典是英语和德语公用的,也就是说编码器和解码器可以共用。
标签平滑 Label Smoothing 是干啥?
softmax 分类时概率靠近 1 才会判定正确,这需要输出接近于无限大才能使 softmax 值接近 1,这样就比较难训练。标签平滑做的就是把这个标准降一下,比如在这里 ϵ l s = 0.1 \epsilon_{ls}=0.1 ϵls=0.1 的标签平滑就是把这个判定值降到了 0.9,现在逼近0.9就会判断为正确。
不过正如文中所讲,这样操作会增加模型的不确定性。但是也许这世界本身就是不确定的,Label Smoothing 增加困惑度但是提高了准确性和 BLEU 分数。
个人感想
就论文而言,应该是受限于篇幅限制,写的很简略,大部分地方都是一笔带过。要是没有提前学过而是干看论文的话应该会很难看明白。
就 Transformer 而言,Transformer 之于 NLP 感觉就像 CNN 之于 CV,给 NLP 提供了一个范式,才有了后面在 Transformer基础上 堆出来的 BERT、GPT。现在 Transformer 又推广到了其他各个图像、音频等各个领域,它能同时应用于多个领域也就使多模态更好做了一些。