Open wtysos11 opened 3 years ago
论文阅读
Transformer架构原文。
基于Encoder-Decoder的改进完成的简单网络架构。
Encoder部分,由6个独立的层组成,每一个层由两个子层组成。第一个子层是包含multi-head self-attention的机制,第二个子层使用简单的全连接层。使用跳层连接和层内正则化的技术,这样每层的输出为LayerNorm(x+Sublayer(x)),其中Sublayer(x)为使用子层实现的结果。
所有的子层,包括压缩层,其输出数据的维数为512.
Decoder部分,同样由6个独立层组成。除了Encoder部分包含的两个子层之外,还有第三个子层Masked multi-head attention。同样采用了layer normalization与sub-layers。
Decoder部分的第一个multi-head attention做了一些修改,避免取得非法的位置(因为未来的信息理论上应该是不知道的,我是这样理解的)。即对于Decoder的信息,每一个循环应该只能多拿到一个位置的信息。
attention函数可以被描述为将一个query和一个key-value对的集合映射到一个输出上,且这些全部都是向量。
输出结果为value的加权平均值,其权重根据query与对应key的关系计算。
这是作者称呼其内部实现的attention机制的名称。输入包含d_k维度的query和key向量,以及d_v维度的value。通过点积来计算query和key,并进行正则化+softmax来得到每一个value的权重。
在实践中,所有的query是同步计算的。我们会将所有query vector整合成一个矩阵Q,同样把所有的key和value整合成对应的矩阵K和V。然后按照上一段所说,计算出矩阵的输出。
目前(2017年)最常用的两种注意力机制计算函数是additive attention和dot-product attention。我们只使用了点乘注意力函数,除了加上一个缩放系数。加性注意力机制使用前向神经网络来计算compatibiblity function。这两种在时间复杂度上类似,但是点乘注意力机制更加快速,而且实践中空间有效性会更高,因为它大量使用了快速的矩阵优化代码。
然而,在d_k的数值比较小的时候,加性注意力机制表现更好, 因为它不用进行最终计算结果的放缩。进行放缩的原因是因为在d_k的数值特别大的时候,它很可能会使得softmax函数超出区域,使得梯度消失,因此需要对其进行一定的放缩来保证梯度的值足够大,保证算法的收敛速度。
在使用单一的注意力函数之外,我们发现将query、key和value分别重复h次进行线性映射后再进行线性映射是更有效的。在每一个进行过线性映射之后的query、key和value上我们并行地执行attention function,产生输出,并进行拼接。最终将所有的拼接值进行线性映射。
multi-head attention允许模型将不同子空间在不同位置的不同表示信息连接起来。通过一个single attention head来完成最终的线性映射。
Transformer在三种不同的方式中使用Multi-head attention
除了注意力子层之外,每一层还包含了一个全连接层。这个全连接层由两个线性组合加上一个ReLU激活函数。
$FFN(x) = max(0,xW_1+b_1)W_2+b_2$
线性组合在不同的位置上表现的是一样的,但是在不同的层中使用的是不同的参数。另一种描述这个的形式是使用kernel size为1的两个卷积函数,输入和输出的维数均为512。
我们使用了学习到的线性组合和softmax函数来转换decoder的输出,用来预测下一个token的概率。在我们的模型中,两个embedding层中的矩阵权重和pre-softmax线性转换的权重是相同的。
由于我们的模型中是没有包含任何卷积与循环结构,因此为了让我们的模型更好地利用序列的顺序信息,我们必须将一些关于相对位置或者绝对位置的信息注入到序列中。
因此,在输入数据的时候,Encoder和Decoder都会对其进行处理。positional encoding与embedding的输出数据维数是相同的,因此直接将两者相加即可完成。
positional encoding的方式有很多,在本文中使用不同频率的sin和cos函数进行,具体略过。使用dimension信息决定采用哪个频率的函数,使用pos信息决定采用函数的哪一个点。
我不太清楚具体的实现,但这个值取得是很大的,我觉得应该是单调的。
原文地址:https://huggingface.co/blog/encoder-decoder
本文的目的是为了给出更细节的解释来产品transformer-based encoder-decoder架构是怎样对S2S问题进行建模的。主要关注的是架构所定义的数学模型以及这个模型是如何被用在推断中。
NLP关注的是,给定序列$X_1,...,X_n$,如何预测出对应的输出单词序列$Y_1,Y_2,...,Y_m$
从数学上来说,Decoder部分定义了一个条件概率,即给定隐层状态c,其结果为目标序列$Y{1:m}$的条件概率$p\theta{dec}(Y_{1:m}|c)$,通过贝叶斯公式可以将其拆解成条件概率的连乘,即
$p\theta{dec}(Y{1:m}|c) = \prod{i=1}^{m}p\theta{dec}(yi|Y{0:i-1},c)$
因此,如果架构能够对下一个给定目标向量的条件概率建模,给出所有的条件概率$p\theta_{dec}(yi|Y{0:i-1},c)$,就可以在给定隐层c的情况下通过条件概率连乘的方式对目标向量序列的分布进行建模。
基于RNN的decoder模型是如何建模$p\theta_{dec}(yi|Y{0:i-1},c)$?
从计算的角度来看,模型会顺序的将隐层状态$c_{i-1}$以及之前的目标向量$y_i$映射到现在的隐层状态$c_i$和一个logit vector $l_i$上。并使用一个softmax函数来将logit vector $l_i$转换成下一个向量的条件概率$p(y_i|l_i) = Softmax(l_i)$
(这个在原文提到更多,我没太看明白,而且也不重要,就不详细写了)
从这里可以看到,下一个向量$yi$是直接由$y{i-1}$与隐层状态$c{i-1}$产生的,而隐层$c{i-1}$又是受到前面所有目标向量$y0,...,y{i-2}$的影响,因此RNN-based decoder隐式地对条件概率$p\theta_{dec}(yi|Y{0:i-1},c)$进行了建模。
由于$Y{1:m}$的输入空间是非常大的,所以在推断过程中,必须依赖decoding方法来有效地从$p\theta{dec}(yi|Y{0:i-1},c)$中利用概率信息。
在RNN-based的encoder-decoder中很重要的一个特性是特殊向量的定义,也即EOS和BOS的定义。EOS一般代表输入向量的最后一个单词,来通知模型。当EOS被输入的时候,generation部分工作就完成了。BOS向量则代表decoder的输入向量输入到模型的第一个单词,表示开始Decoder。
基于RNN的工作有两个问题,第一个,RNN容易受到梯度消失问题的影响,因此难以捕捉long-range dependencies(LSTM部分解决了这个问题,但其实还是会有);第二个,RNN内生的嵌套结构不利于并行执行。
2017年提出了Transformer模型,使用了residual attention block。其优点就在于能够处理输入序列$X_{1:n}$的同时不需要建立循环结构。这使得Transformer能够并行执行,因此在大规模的时候效率更高。
本质上还是需要找到长度为n的输入序列到长度为m的输出序列之间的映射。下面文章介绍了如何找到这样一种映射的方式。
与前文相同,Transformer-based的方法同样是用条件概率来完成的。$p{\theta{dec} \theta{enc}}(Y{1:m}|X_{1:n})$
这个的Encoder部分将输入的序列转换为隐藏层状态$f{\theta{enc}:X{1:n}\to X{1:n}}$,然后Decoder部分再对条件概率部分进行建模$p{\theta{dec}}(Y{1:n}|X{1:n})$
同样通过贝叶斯,可以将这个拆分成循环结构,即$p{\theta{dec}}(Y{1:n}|X{1:n}) = \prod{i=1}^{m}p{\theta_{dec}}(yi|Y{0:i-1},X{1:n})$(与前面RNN-based Encoder-Decoder的区别就在于隐层状态c被换成了Encoder输出向量X{1:n})
然后Decoder就可以将encoder的隐层状态向量$X{1:n}$以及之前的目标向量$Y{0:i-1}$映射到logit vector $l_i$,然后再使用这个logit vector预测出下一个值。与RNN-based不同,目标向量$y_i$的映射关系是显示定义为前面所有向量的条件概率。这样,就可以auto-regressively地产生目标向量的后续状态。
Transformer-based的架构中,Encoder部分是由residual encoder block组成的,每一个encoder block是由bidirectional的self-attention layer组成,跟随着两个全连接层。从简单的角度来说,可以暂时忽略LayerNormalization,并将这两个全连接层视为单纯的vector2vector的工具。
在encoder中,attention层将输入的向量转换为更具有表示性的向量$x''$,把输入从一个context-independent的向量表示转变为context-dependent的向量表示。后续的encoder block继续改善这个向量表示,直到到达encoder的最后一层。
这个算是老生常谈了,我之前也听过挺多次的。每一层会训练出三个矩阵$W_q$,$W_v$,$W_k$,这三个矩阵会被应用于所有的输入向量$x_i$,为每个向量产生三个对应的特征向量q,k,v,其中query和key的维数相同(都是n,与输入向量维数相同),value的维数是另外一个维数(但在本文中也是n,原文中应该是不同的)。
最后使用softmax处理query和key的点乘,然后将结果与value相乘后结合跳层连接产生最终结果。原文有一张很好地图,我附在下面
参考资料:
关于Attention的不错资料The Illustrated Transformer
Transformer的改进:
在学习过程中的一个突发奇想,dot-product attention的思想本质上是加权平均和,将不同的输入值与中间的某个值对应。那收到N-BEATS的启发,我能不能直接用傅里叶级数的方式实现中间这个注意力。就是说,将注意力的方向从时域转为频域。
想了很久,不转频域也不行。如果不转频域的话时域感觉没什么想法。问题是频域该怎么做,我最原始的想法就是用深度残差网络来做,低频高权值、高频低权值,然后去拟合起来。或者把频域特征与注意力机制结合起来(这怎么结合?可能要从底层考虑了)
目标上肯定只能放在抗干扰上,着重强调网络环境的复杂性或者新闻特性。但说实话很多网络流量本身也没有周期性,也很难进行预测。或者说深度残差做叠加,叠加最底层用Transformer拟合残差,中间叠加块用AR形式的傅里叶或者小波变换。测试数据集可以选择用wiki产生的网络流量数据(都挺可怕的)、以及时间序列异常检测中用到的数据。
开脑洞材料:
复现:
一些技巧:
频域资料
paper: