Self-Attention 及Multi-Head Attention

Transformer是2017年Google在Computation and Language上发表的,当时主要是针对自然语言处理领域提出的(之前的RNN模型记忆长度有限且无法并行化,只有计算完 t_{i} 时刻后的数据才能计算t_{i+1} 时刻的数据,但Transformer都可以做到)。在这篇文章中作者提出了Self-Attention的概念,然后在此基础上提出Multi-Head Attention。

self-attention或者transformer的相关资料,基本上都是贴的原论文中的几张图以及公式

Self-Attention 及Multi-Head Attention_第1张图片

Self-Attention 

假设输入的序列长度为2,输入就两个节点 x_{1}x_{2} ,然后通过Input Embedding也就是图中的 f(x) 将输入映射到a_{1}, a_{2} 。紧接着分别将a_{1} , a_{2}  分别通过三个变换矩阵W_{q}, W_{k} , W_{v}(这三个参数是可训练的,是共享的)得到对应的 q^{i}, k^{i}, v^{i}(这里在源码中是直接使用全连接层实现的,这里为了方便理解,忽略偏执)。

Self-Attention 及Multi-Head Attention_第2张图片

其中

  • q 代表query,后续会去和每一个k 进行匹配
  • k 代表key,后续会被每个q 匹配
  • v 代表从a 中提取得到的信息
  • 后续q 和k 匹配的过程可以理解成计算两者的相关性,相关性越大对应v 的权重也就越大

假设a_{1}=\left ( 1,1 \right )a_{2} =\left ( 1,0 \right )W_{q} =\binom{1 , 1}{0, 1} 那么:

                q^{1} =\left ( 1,1 \right )\binom{1 , 1}{0, 1} = \left ( 1,2 \right )      q^{2} = \left ( 1,0 \right )\binom{1 , 1}{0, 1} = \left ( 1,1 \right )

Transformer是可以并行化的,所以可以直接写成:

                                 \binom{q^{1}}{q^{2}} =\binom{1,1}{1,0}\binom{1,1}{0,1}= \binom{1,2}{1,1}   \binom{1,2}{1,1}

同理我们可以得到\binom{k^1}{k^2}\binom{v^1}{v^2},那么求得的\binom{q^1}{q^2}就是原论文中的Q ,\binom{k^1}{k^2}就是K\binom{v^1}{v^2}就是V 。接着先拿q^{1}和每个k进行match, 点乘操作,接着除以\sqrt{d}得到对应的α ,其中d代表向量k^{i}的长度
,在本示例中等于2,除以\sqrt{d}的原因在论文中的解释是“进行点乘后的数值很大,导致通过softmax后梯度变的很小”,所以通过除以\sqrt{d}来进行缩放。比如计算\alpha _{1,i}

                                Self-Attention 及Multi-Head Attention_第3张图片

 同理拿q^{2}去匹配所有的k能得到\alpha _{2, i},统一写成矩阵乘法形式:

                                              Self-Attention 及Multi-Head Attention_第4张图片

接着对每一行即 (\alpha_{1, 1}, \alpha_{1, 2})(\alpha_{2, 1}, \alpha_{2, 2})分别进行softmax处理得到 (\hat\alpha_{1, 1}, \hat\alpha_{1, 2}) 和 (\hat\alpha_{2, 1}, \hat\alpha_{2, 2}),这里的 \hat{\alpha}相当于计算得到针对每个 v 的权重。 到这我们就完成了 {\rm Attention}(Q, K, V)公式中{\rm softmax}(\frac{QK^T}{\sqrt{d_k}})部分。

 上面已经计算得到\alpha,即针对每个v的权重,接着进行加权得到最终结果:

                                           

统一写成矩阵乘法形式:

                                                                  

self-attention

 到这,Self-Attention的内容就讲完了。总结下来就是论文中的一个公式:

              Attention\left ( Q, K,V\right ) = softmax\left ( \frac{QK^{T}}{\sqrt{d_{k}}} \right )V

Multi-Head Attention

刚刚已经聊完了Self-Attention模块,接下来再来看看Multi-Head Attention模块,实际使用中基本使用的还是Multi-Head Attention模块。原论文中说使用多头注意力机制能够联合来自不同head部分学习到的信息。Multi-head attention allows the model to jointly attend to information from different representation subspaces at different positions.其实只要懂了Self-Attention模块Multi-Head Attention模块就非常简单了。
首先还是和Self-Attention模块一样将a^{i}分别通过W^q, W^k, W^v 得到对应的q^i, k^i, v^i ,然后再根据使用的head的数目h进一步把得到的q^i, k^i, v^i 均分成h份。比如下图中假设h = 2 然后q^1
 拆分成 q^{1,1}q^{1,2},那么q^{1,1}就属于head1, q^{1,2}属于head2。

 multi-head

 论文中不是写的通过W^Q_i, W^K_i, W^V_i映射得到每个head的Q_i, K_i, V_i

                      head_{i} = Attention\left ( QW_{i}^{Q},KW_{i}^{K},VW_{i}^{V}\right )

在github上看的一些源码中就是简单的进行均分,其实也可以将W^Q_i, W^K_i, W^V_i设置成对应值来实现均分,比如下图中的Q通过 W^Q_1 就能得到均分后的Q_1 。

multi-head

 通过上述方法就能得到每个head_i 对应的Q_i, K_i, V_i参数,接下来针对每个head使用和Self-Attention中相同的方法即可得到对应的结果。

                    Attention\left ( Q_{i}, K_{i},V_{i}\right ) = softmax\left ( \frac{Q_{i}K_{i}^{T}}{\sqrt{d_{k}}} \right )V_{i}

 接着将每个head得到的结果进行concat拼接,比如下图中b_{1,1} (head_1得到的b_1)和 b_{1,2}head_{2}
 得到的b_1)拼接在一起,b_{2,1}head_1得到的 b_2 )和b_{2,2}head_2得到的b_2)拼接在一起。

multi-head

 接着将拼接后的结果通过W^O(可学习的参数)进行融合,如下图所示,融合后得到最终的结果b_1, b_2 。

在这里插入图片描述
到这,Multi-Head Attention的内容就讲完了。总结下来就是论文中的两个公式:

      MultiHead(Q,K,V)=Concat(head_1, ...,head_h)W^O

     where head_i = Attention(QW_{i}^{Q},KW_{i}^{K},VW_{i}^{V} )

Positional Encoding

如果仔细观察刚刚讲的Self-Attention和Multi-Head Attention模块,在计算中是没有考虑到位置信息的。假设在Self-Attention模块中,输入 a_1, a_2, a_3得到b_1, b_2, b_3 。对于a_1而言,a_2a_3离它都是一样近的而且没有先后顺序。假设将输入的顺序改为a_1,a_3,a_2,对结果b_1是没有任何影响的。下面是使用Pytorch做的一个实验,首先使用n.MultiheadAttention创建一个Self-Attention模块num_heads=1,注意这里在正向传播过程中直接传入QKV,接着创建两个顺序不同的 QKV变量t1和t2(主要是将q^2, k^2, v^2q^3, k^3, v^3的顺序换了下),分别将这两个变量输入Self-Attention模块进行正向传播。

import torch
import torch.nn as nn


m = nn.MultiheadAttention(embed_dim=2, num_heads=1)

t1 = [[[1., 2.],   # q1, k1, v1
       [2., 3.],   # q2, k2, v2
       [3., 4.]]]  # q3, k3, v3

t2 = [[[1., 2.],   # q1, k1, v1
       [3., 4.],   # q3, k3, v3
       [2., 3.]]]  # q2, k2, v2

q, k, v = torch.as_tensor(t1), torch.as_tensor(t1), torch.as_tensor(t1)
print("result1: \n", m(q, k, v))

q, k, v = torch.as_tensor(t2), torch.as_tensor(t2), torch.as_tensor(t2)
print("result2: \n", m(q, k, v))

对比结果可以发现,即使调换了q^2, k^2, v^2 和q^3, k^3, v^3的顺序,但对于b_1 是没有影响的。
Self-Attention 及Multi-Head Attention_第5张图片
为了引入位置信息,在原论文中引入了位置编码positional encodingsTo this end, we add "positional encodings" to the input embeddings at the bottoms of the encoder and decoder stacks.如下图所示,位置编码是直接加在输入的a=\left \{ a _1 ,...,a _n \right \}中的,即pe=\left \{ pe _1 ,...,pe _n \right \}
a=\left \{ a _1 ,...,a _n \right \}拥有相同的维度大小。关于位置编码在原论文中有提出两种方案,一种是原论文中使用的固定编码,即论文中给出的sine and cosine functions方法,按照该方法可计算出位置编码;另一种是可训练的位置编码,作者说尝试了两种方法发现结果差不多(但在ViT论文中使用的是可训练的位置编码)。
positional encoding
 

           

你可能感兴趣的:(Pytorch学习笔记,transformer,深度学习,自然语言处理)