天天看点

Attention概述及代码实现Attention机制

Attention机制

参考链接:

  1. 【NLP】Attention Model(注意力模型)学习总结(清晰易懂,较全面)
  2. https://jalammar.github.io/illustrated-transformer/(多图,非常经典!)
  3. https://blog.csdn.net/qq_37394634/article/details/102679096(含实现代码)
  4. https://nndl.github.io/
  5. https://github.com/philipperemy/keras-attention-mechanism/tree/0309dbf79da32c0d8d90925660fc4cc7fe53dc8a
  6. https://blog.csdn.net/uhauha2929/article/details/80733255

核心框架(Key-Value Attention):

Attention概述及代码实现Attention机制

将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定Target中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。

Attention概述及代码实现Attention机制
Attention概述及代码实现Attention机制

打分函数:

模型 公式
加性模型 𝑠(𝒙, 𝒒) = v T t a n h ( W x + U q ) v^Ttanh(Wx + Uq) vTtanh(Wx+Uq)
点积模型 𝑠(𝒙, 𝒒) = x T q x^Tq xTq
缩放点击模型

𝑠(𝒙, 𝒒) = x T q D \frac{x^Tq}{\sqrt{D}} D

​xTq​

双线性模型 𝑠(𝒙, 𝒒) = x T W q x^TWq xTWq

理论上,加性模型和点积模型的复杂度差不多,但是点积模型在实现上可以更好地利用矩阵乘积,从而计算效率更高。当输入向量的维度𝐷 比较高时,点积模型的值通常有比较大的方差,从而导致Softmax函数的梯度会比较小。因此,缩放点积模型可以较好地解决这个问题。

双线性模型是一种泛化的点积模型。假设公式中𝑾 = 𝑼T𝑽,双线性模型可以写为𝑠(𝒙, 𝒒) = 𝒙T𝑼T𝑽𝒒 = (𝑼𝒙)T(𝑽𝒒),即分别对𝒙 和𝒒 进行线性变换后计算点积。相比点积模型,双线性模型在计算相似度时引入了非对称性。

多头注意力

多头注意力(Multi-Head Attention)利用多个查询𝑸 = [𝒒1, ⋯ , 𝒒𝑀 ],来并行地从输入信息中选取多组信息,每个注意力关注输入信息的不同部分。

Attention概述及代码实现Attention机制

结构化注意力

在之前介绍中,我们假设所有的输入信息是同等重要的,是一种扁平(Flat)结构,注意力分布实际上是在所有输入信息上的多项分布.但如果输入信息本身具有层次(Hierarchical)结构,比如文本可以分为词、句子、段落、篇章等不同粒度的层次,我们可以使用层次化的注意力来进行更好的信息选择[Yang et al.,2016].此外,还可以假设注意力为上下文相关的二项分布,用一种图模型来构建更复杂的结构化注意力分布[Kim et al., 2017]。

自注意力

如果要建立输入序列之间的长距离依赖关系,可以使用以下两种方法:一种方法是增加网络的层数,通过一个深层网络来获取远距离的信息交互;另一种方法是使用全连接网络.全连接网络是一种非常直接的建模远距离依赖的模型,但是无法处理变长的输入序列.不同的输入长度,其连接权重的大小也是不同的.这时我们就可以利用注意力机制来“动态”地生成不同连接的权重,这就是自注意力模型(Self-Attention Model)。

引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。

为了提高模型能力,自注意力模型经常采用查询-键-值(Query-Key-Value,QKV)模式,其计算过程如图8.4所示,其中红色字母表示矩阵的维度。

Attention概述及代码实现Attention机制

代码实现

  1. 相似度函数采用的是一层全连接层。全连接层的输出经过softmax激活函数计算权重。他对隐层向量的每一维在每个时间步上进行了softmax操作,这里函数的返回值是三维的,也就是说这里只是乘上了权重,但并没有求和。

    见GitHub: Many-to-one attention mechanism for Keras

  2. 参考https://colinraffel.com/publications/iclr2016feed.pdf
    Attention概述及代码实现Attention机制

    在softmax之前还加了tanh激活函数,而且将输出进行了求和,所以输出是二维的。

    自定义Attention层:(若上接 LSTM 则需

    return_sequences=True

    ,即需LSTM输出三维向量)
class AttentionLayer(Layer):
    def __init__(self, **kwargs):
        super(AttentionLayer, self).__init__(** kwargs)

    def build(self, input_shape):
        assert len(input_shape)==3
        # W.shape = (time_steps, time_steps)
        self.W = self.add_weight(name='att_weight', 
                                 shape=(input_shape[1], input_shape[1]),
                                 initializer='uniform',
                                 trainable=True)
        self.b = self.add_weight(name='att_bias', 
                                 shape=(input_shape[1],),
                                 initializer='uniform',
                                 trainable=True)
        super(AttentionLayer, self).build(input_shape)

    def call(self, inputs):
        # inputs.shape = (batch_size, time_steps, seq_len)
        x = K.permute_dimensions(inputs, (0, 2, 1))
        # x.shape = (batch_size, seq_len, time_steps)
        a = K.softmax(K.tanh(K.dot(x, self.W) + self.b))
        outputs = K.permute_dimensions(a * x, (0, 2, 1))
        outputs = K.sum(outputs, axis=1)
        return outputs

    def compute_output_shape(self, input_shape):
        return input_shape[0], input_shape[2]
           

继续阅读