《Attention is all you need》
摘要
目前而言,序列模型都是基于Seq2Seq,用Encoder提取语义信息C,再从语义信息Decoder成另一个序列,其中Encoder和Decoder都是非常复杂的RNN或者CNN组成。
对于语义信息C,由于在解码的过程中,如果只有一个语义C导致不管解码哪一个位置时,对Encoder部分所有的位置采取了同样的权重。
因而融合注意力机制是目前为止比较好的解决方案了(当然还有很多花里胡哨的)。
Seq2Seq模型中大多用了RNN模型作为输入的Encoder和输出的Decoder。RNN天然的时序结构注定了不能在GPU上实现高度并行。怎么办?Google团队提出了Transformer模型。
其实已经有很多工作想取代RNN在NLP的地位,比如堆叠的膨胀卷积模型等。如果理解了这个模型,对于Transformer理解并不难。
引言
是的,RNN模型有很多缺点,Google很牛逼,提出了Transformer
模型
inpus
乍一看很复杂,仔细看,就两点。
(1)自注意力
(2)前馈网络
Encoder-Decoder
(1)当inputs序列,即一句话的token_id,经过Input Embedding时,对每一个token进行look for table投影成512维的向量。同时,对inputs每一个位置进行编码,同样Embedding成512维度的向量。
Position Encoding如下
Positional Encoding
原文中指明了,pos是位置,i是维度。我的理解是当前维度是偶数时正弦函数,当前维度是奇数时,是余弦函数。
import numpy as np
import matplotlib.pyplot as plt
import math
res = []
for pos in range(1, 100, 1):
pos_i = []
for i in range(1, 512, 1):
if (i % 2 == 0):
pos_i.append(math.sin(pos / math.pow(10000, i / 512)))
else:
pos_i.append(math.cos(pos / math.pow(10000, (i-1) / 512)))
res.append(pos_i)
plt.imshow(np.array(res))
plt.colorbar()
plt.show()
因为postion_embedding和token_embedding都是512维,可以将这两个向量对应维度进行相加,相当于融合了位置信息。有一些经典的论文CNN做文本,会将Position concat到后面去。
Encoder
做完上一步,相当于得到512维的嵌入表示,这个嵌入表示融合词特征和位置特征。
接下来,是多头的注意力层。
暂时不考虑多头,先考虑注意力机制怎么实现。
初始化全连接的矩阵 维度为[512,64]
对于输入序列
对,其维度为[1,512],乘以矩阵,维度为[512,64],得到的向量为,维度为[1,64]。同理
对,其维度为[1,512],乘以矩阵,维度为[512,64],得到的向量为,维度为[1,64]。同理
对,其维度为[1,512],乘以矩阵,维度为[512,64],得到的向量为,维度为[1,64]。同理
首先将向量乘以向量,[1,64]*[64,1]得到一个值。这个,乘以。相当于给加了一个权重。
同理,将向量乘以向量,为增加权重
同理,将向量乘以向量,为增加权重
这样,对于,得到了,都是[1,64]。加其累加在一起,得到=[1,64]。
同理,对于,得到=[1,64]
同理,对于,得到=[1,64]
可以看到对于每一个token,都从[1,512]投影到[1,64]。这个和RNN(hidden=64)模型异曲同工。
还有Scaled,其实就是再除以了。论文中有比较,乘性的Attention不如加性的Attention好,原因可能是得到的向量乘积值太大了。用规范一下,效果和加性的attention一致。
多头
文章中指出,这种一组,,不够,多几组效果好。
于是维护了8组,,。分别执行同样的操作,相当于每一个token此使有8个[1,64]的。将最后的维度concat起来,得到[1,64*8] = [1,512]维度的向量。这就是多头,表示不止有一组Attention得到的,其实有8个。
怎么理解?
我们将其与卷积联系在一起,如果一组,,相当于一个卷积核,能够提取一个特征[1,64],那么8组,,相当于8个卷积核,能够提取八组特征。这个极大的扩展了模型的复杂度,能够学习到更多文本特征。
其实巧妙的地方不在于先从512维度压缩到64,再从64维度展开到512,更重要的一点在于可以利用残差网络。
残差
残差网络的提出,让深度神经网络成为可能。对于任何一个模型,我们希望对于输入,能学到函数,即。如果是多层网络,很难学到F映射。尤其是网络层数加深,梯度消失更难以训练。因而不希望学习。而是学习。即学习。所以将之前的直接连到后面,去学习,即残差。
对于模型而言,就是将输入和输出连接同时送到下一层。
Add Norm
因此,多头注意力得到的输入[1,512]token,和输入[1,512]直接相加[1,512]。再对这一层进行层归一化。
Feed Forward
前馈网络层,就是全连接,这边论文中所述是两层。
第一层[1,512] * [512,512*4] = [1,2048]
Relu
第二层[1,2048] * [2048,512] = [1,512]
6 encoder
这样的encoder有6层。得到的输出
【未完持续】