Transformer——Attention 注意力机制

注意力机制

Transformer的注意力机制借鉴了人类的注意力机制。人类通过眼睛的视觉单元去扫描图像,其中的重点区域会被大脑的神经元处理从而获得更多的信息,这是人类长期精华所获得的一种能力。

以论文中的例子来看,红色区域表示我们人脑视觉更为关注的区域。而Attention 机制则是模拟这一人脑机制,让计算机能够正确的从总舵信息中选择出对当前任务更为重要的信息
请添加图片描述

Attention 机制原理

人类视觉注意力机制的原理为:从大量信息中有选择地筛选出少量重要信息并聚焦到这些重要信息上,忽略不重要的信息

计算机的注意力机制模型就是从大量信息(Values)中筛选出少量的重要信息,这个重要信息对于另外一个信息(Query)是重要的。即注意力模型的主要作用就是通过Query从Values中筛选出重要信息

结合下图,Attention可以翻译为如下的描述,其将Query和KV(把value拆分为key-value信息,这两个值看作等同的)映射到输出上。其中Q(query)、K(key)、V(value)都是一个向量,输出 V , V^, V则是所有value的加权,其中权重是由Q和每个K计算出来的。
请添加图片描述

KV 是怎么来的?

对于上述图像来说,我们将其分割为不同的小块,其中每个块的向量化表示则是向量K
在这里插入图片描述

详细计算过程

刚刚提到,输出 V , V^, V是对所有value的加权,是由 Query 和每个 key 计算出来的,计算方法分为三步:

  1. 第一步:计算Q和K的相似度,可以用 F F F来表示: f ( Q , K i ) , i = 1 , 2 , . . . , n f(Q,K_i),i=1,2,...,n f(Q,Ki),i=1,2,...,n
    • 计算方法一般分为四种:
      • 点乘: f ( Q , K i ) = Q T K i f(Q,K_i)=Q^TK_i f(Q,Ki)=QTKi
      • 权重: f ( Q , K i ) = Q T K i W f(Q,K_i)=Q^TK_iW f(Q,Ki)=QTKiW
      • 拼接权重: f ( Q , K i ) = [ Q T K i ] W f(Q,K_i)=[Q^TK_i]W f(Q,Ki)=[QTKi]W
      • 感知器: f ( Q , K i ) = V T t a n h ( W Q + U K i ) f(Q,K_i)=V^Ttanh(WQ+UK_i) f(Q,Ki)=VTtanh(WQ+UKi)
  2. 第二布:将第一步得到的相似度进行SoftMax操作,进行归一化: α i = s o f t m a x ( F ( Q , K i ) d k ) \alpha_i=softmax(\frac{F(Q,K_i)}{\sqrt{d_k}}) αi=softmax(dk F(Q,Ki))
    • 这一步进行归一化是避免得到的相似度F1 = 50F2 = 1 之间的差值多大影响模型效果,归一化之后相似度可能就会变成F1 = 0.8F2 = 0.1
  3. 第三步:针对计算出来的权重 α i \alpha^i αi,对V中的所有values进行加权求和计算,得到Attention 向量: A t t e n t i o n = ∑ i = 1 m α i V i Attention=\sum_{i=1}^{m}\alpha_iV_i Attention=i=1mαiVi

注1:softmax函数原理:https://zhuanlan.zhihu.com/p/503321685
注2:为什么要除 d k \sqrt{d_k} dk :softmax函数的输入由key向量和query向量之间的点积组成,key向量和query向量的维度 越大,点积往往越大, 原文论中12个head对应的大小是64,作者在原论文中采用的补救措施,是将点积除以key和query维度的平方根

Attention计算实战

假设我们现在有下面这么一组数据,现在我们的问题是:腰围57其对应的体重是多少(query)

腰围(key)体重(value)
5140
5643
5848

对于单维度场景,我们认为57 腰围所对应的体重在43~48之间,同时考虑到51 腰围这个key,所以我们的公式可以表示为如下的形式:
f ( 57 ) = ∑ i = 1 3 α i V i = α ( 57 , 51 ) ∗ 40 + α ( 57 , 56 ) ∗ 43 + α ( 57 , 58 ) ∗ 48 f(57) =\sum_{i=1}^{3}\alpha_iV_i= \alpha(57,51)*40+\alpha(57,56)*43+\alpha(57,58)*48 f(57)=i=13αiVi=α(57,51)40+α(57,56)43+α(57,58)48

注: 同样的,对于多维向量,我们采用点乘的方式依然可以得到 f f f

Self-Attention 自注意力机制

Self-Attention是Attenion机制的特化。Self-Attention 同样也有着三个输入Q、K、V:对于Self-Attention,Q、K、V均来自句子X的词向量 x x x的线性转化。
下面我们以“我有一只猫”这个过程来举例:

注:
在真实的Transformer模型中,查询、键和值是通过与不同的权重矩阵相乘得到的,而且通常会使用多头注意力来并行计算多个独立的注意力分布,并将它们的结果拼接起来。

  1. 输入词向量

假设经过位置编码之后我们得到了如下表格所述的词向量:

嵌入向量(模拟值)
[0.1, 0.2]
[0.3, 0.4]
一只[0.5, 0.6]
[0.7, 0.8]
  1. 计算Q、K、V
    在自注意力机制中,我们需要为每个输入向量计算查询(Q)、键(K)和值(V)。然而,在这个简化的例子中,我们假设查询、键和值都与输入嵌入相同。
    Q = K = V = i n p u t Q=K=V=input Q=K=V=input

  2. 计算注意力分数
    对于每个查询(即每个词),我们需要计算它与所有键的点积,然后应用softmax函数来获得归一化的注意力权重。

以第一个词“我”为例,计算过程如下:

注意力分数(我) = softmax([
    Q() · K(),
    Q() · K(),
    Q() · K(一只),
    Q() · K()
])

= softmax([
    [0.1, 0.2] · [0.1, 0.2],
    [0.1, 0.2] · [0.3, 0.4],
    [0.1, 0.2] · [0.5, 0.6],
    [0.1, 0.2] · [0.7, 0.8]
])

= softmax([0.05, 0.14, 0.26, 0.38])

假设softmax后的结果为 [0.1, 0.2, 0.3, 0.4],这些就是“我”这个词对其他词的注意力权重。
  1. 加权求和
    最后,我们使用计算得到的注意力权重对值向量进行加权求和,得到每个词的自注意力输出。
输出向量(我) = [
    0.1 * V() + 0.2 * V() + 0.3 * V(一只) + 0.4 * V()
]

= [
    0.1 * [0.1, 0.2] + 0.2 * [0.3, 0.4] + 0.3 * [0.5, 0.6] + 0.4 * [0.7, 0.8]
]

= [0.46, 0.58]

SelfAttention可以很好的帮我们解决机器不能理解语句之间语义的问题。以“我有一只猫”这句话为例,Self-attention的作用可以体现在以下几个方面:

  • 捕捉元素之间的依赖关系:在这句话中,“我”、“有”、“一只”和“猫”这四个元素之间存在依赖关系。通过Self-attention,模型可以计算出这些元素之间的注意力分数,从而理解它们之间的关系。例如,“我”和“有”之间的关系可能比较紧密,因为它们构成了一个主谓结构,而“一只”和“猫”之间的关系也比较紧密,因为它们构成了一个数量短语。通过捕捉这些依赖关系,模型可以更好地理解这句话的含义。
  • 实现长距离依赖建模:虽然这句话比较短,但在处理更长的序列时,Self-attention的优势就更加明显了。传统的循环神经网络(RNN)在处理长序列时容易出现梯度消失或爆炸的问题,导致无法对长距离依赖进行建模。而Self-attention机制可以直接计算序列中任意两个元素之间的关系,无论它们之间的距离有多远,因此可以很好地处理长序列并实现长距离依赖建模。
  • 降低计算复杂度:Self-attention机制通过矩阵计算和并行计算等技术实现高效的自注意力计算,从而降低计算复杂度并提高模型的训练和推理速度。

Masked Self-Attention

Masked Self-Attention(掩码自注意力机制)是自注意力机制的一个变种,它在某些特定情况下非常有用,比如在处理序列数据时,我们希望模型只关注到序列中的某些部分,而忽略其他部分。其在自注意力的基础上增加了一个掩码操作,这个掩码用于遮挡(或忽略)序列中的某些元素,使得它们在计算注意力分数时不被考虑。

在“我有一只猫”这个例子中,如果我们使用掩码自注意力机制,并且假设我们想要模型在处理“有”这个词时只关注到“我”,而忽略后面的词,我们就可以通过掩码来实现这一点(掩码: 1100 1100 1100)。具体来说,我们可以在计算注意力分数时,将“有”与“一只”和“猫”之间的分数设置为一个非常小的值(比如负无穷),这样在计算softmax函数时,这些分数就会接近于零,从而被忽略。

Masked Self-Attention 实战

我们还是以“我有一只猫”来进行举例,首先假设初始词向量如下:

我:    [0.5, 0.2, -0.1]
有:    [0.3, -0.4, 0.2]
一只:  [-0.1, 0.5, 0.3]
猫:    [0.2, 0.1, -0.3]

接下来,我们将计算注意力分数。但在计算之前,我们需要为每个位置定义一个掩码。掩码可以是一个二进制矩阵,其中1表示可关注的位置,0表示被掩码掉的位置。在这个例子中,如果我们正在计算“猫”,那么掩码矩阵将会是这样的:

我     有     一只   猫
1      1      1      1

然后我们进入自注意力计算过程:

  1. 计算Q、K、V,还是假设这三者一致:
Q = K = V = [
  [0.5, 0.2, -0.1],   # 我
  [0.3, -0.4, 0.2],   # 有
  [-0.1, 0.5, 0.3],   # 一只
  [0.2, 0.1, -0.3]    # 猫
]
  1. 计算未掩码的注意力分数
# 这里我们只计算了最后一个词“猫”对其他词的注意力分数
猫对我   = [0.2, 0.1, -0.3] · [0.5, 0.2, -0.1]^T = 0.2*0.5 + 0.1*0.2 + (-0.3)*(-0.1)
猫对有   = [0.2, 0.1, -0.3] · [0.3, -0.4, 0.2]^T
猫对一只 = [0.2, 0.1, -0.3] · [-0.1, 0.5, 0.3]^T
  1. Softmax
猫对我   = 0.4
猫对有   = 0.3
猫对一只 = 0.3
  1. 概率加权V矩阵中的向量
猫的新表示 = 0.4 * [0.5, 0.2, -0.1] + 0.3 * [0.3, -0.4, 0.2] + 0.3 * [-0.1, 0.5, 0.3]