注意力机制以及应用

注意力机制以及应用

  • 注意力机制的由来
    • encoder-decoder
    • 简单原理说明
    • global和hard以及local
    • CNN中的attention
    • self-attention
  • 实际运用

Attention成为了越来越来模型里绕不过去的坎,好像不过怎么样都加一个,那么注意力机制到底是什么以及计算流程和具体应用有哪些呢,今天来简单罗列一下。

注意力机制的由来

可以粗略地把注意力机制类比成一个可以专注于输入内容的某一子集(或特征)的神经网络,着力于占比不大但是格外重要的部分。

encoder-decoder

想要说明注意力机制的话首先要说明一下一种模型结构,就是nlp领域常用的编码-解码器架构(seq2seq的说话侧重点是输入输出的数据形式,虽然实际上这类问题常用编码-解码器结构,但是他们是不一样的)。
注意力机制以及应用_第1张图片
简单来说就是输入数据经过一个网络运算后得到一个语义向量c然后让解码器对其处理得到最后的输出。最大的局限性也就在于编码器和解码器之间的唯一联系就是一个语义向量C。有两点有待改进:1.c的长度限制了信息的表达;2.后输入的数据会覆盖带先输入的数据,除非记录每一个c(比如机器翻译的文章《Neural Machine Translation by Jointly Learning to Align and Translate》中引入attention就是为解码时每一步关注不同的c,充分利用序列信息)。

简单原理说明

注意力机制利用大致为输入一个query得到一个注意力,标志模型中输出对输入的侧重点,其流程如下。

  • 用i时刻的解码器的隐状态 H i H_i Hi去一一和输入产生的编码器每个隐状态 h j h_j hj进行对比,即通过函数 F ( h j , H i ) F(h_j,H_i) F(hj,Hi)来获得目标单词 Y i Y_i Yi和每个输入单词对应的对齐可能性,这个F函数在不同论文里可能会采取不同的方法
  • 将权值进行归一化,得到直接可用的权重
  • 根据注意力分布来计算输入信息的加权平均

global和hard以及local

随着新思想不断提出注意力也有了新的细化。

  • global或者说soft注意力是考虑全局的一种注意力,比较常见的Attention方式,对所有编码器的输出权重概率(softmax),每个编码器的输出都有一个对应的权重,是一种全局的计算方式。
  • hard和上面的全局相反,每次仅选择一个相关的某个编码器的输出进行计算,这种缺点是不可微,没有办法进行反向传播,只能借助强化学习等手段进行训练。
  • local综合了上面两种,对一个窗口区域进行计算。先用Hard方式定位到某个地方,以这个点为中心可以得到一个窗口区域,在这个小区域内用Soft方式来算Attention。

CNN中的attention

在CNN中,可以在卷积或者池化操作中加如注意力矩阵,用来和数据相乘。

self-attention

而Self Attention顾名思义,指的不是Target(输入)和Source(输出)之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制。它分别在source端和target端进行,仅与source input或者target input自身相关的Self Attention,捕捉source端或target端自身的词与词之间的依赖关系;然后再把source端的得到的self Attention加入到target端得到的Attention中,捕捉source端和target端词与词之间的依赖关系。

实际运用

下面是实际使用注意力的一个实例代码。
首先定义注意力层

class Attention(nn.Module):
	#
	#传入的Q,K,V大小分别为[64,1,256],[64,5,256],[64,5,256]
    def __init__(self, feature_size):
        super().__init__() 
        #两倍因为Q和K需要拼接到一块
        self.linear = nn.Linear(2*feature_size, feature_size)
        self.v = nn.Linear(feature_size, 1)
            
    def forward(self, Q, K, V, attn_mask=None):
    	#q扩展seq_len大小
        Q_expand = Q.expand(-1, K.size(1), -1)
        #拼接
        cat = torch.cat((Q_expand, K), 2)
        #拼接后是256+256,所以上面声明的也就是512的fc层,输出64x5x256
        energy = F.tanh(self.linear(cat))
        #输出64*5
        attn_weights = self.v(energy).squeeze(2)
        if attn_mask is not None:
            attn_weights.masked_fill_(attn_mask, -float('inf'))
        #第一维softmax
        soft_attn_weights = F.softmax(attn_weights, 1)
        #64x(256x5与5x1)在去掉第二维,得64x256 
        context = torch.bmm(V.transpose(1, 2), soft_attn_weights.unsqueeze(2)).squeeze(2)
        return context, soft_attn_weights

然后添加到具体要用的模型中,并且注意在前向传播函数里面使用。

#实际模型中定义注意力层,这里是在一个双向LSTM中使用,size*2
self.attention = Attention(self.lstm_size*2)
#在forward里面计算,h_n记得对格式进行处理
attn_output, attn_weights = self.attention(h_n, lstm_output, lstm_output)
#可以随着计算结果一起返回注意力权重,以便后续使用
return label_output, attn_weights

你可能感兴趣的:(DL,神经网络)