理解Attention注意力的本质(附代码讲解与案例)

本文从基础知识出发,详细解读Attention机制在深度学习,尤其是NLP任务中的作用,包括Seq2Seq模型中的Attention、加性Attention与乘性Attention(Bahdanau与Luong Attention),并结合机器翻译案例进行说明。
摘要由CSDN通过智能技术生成

大部分关于attention的文章都是对‘attention is all your need‘这篇文章的讲解,对初学者并不友好,省略了很多先决知识,这篇文章翻译自’Attention Mechanism’,并结合了自己的理解,力求从浅入深地讲解attention机制的本质。
注:阅读本文之前需要对RNN结构有了解
可参考https://cuijiahua.com/blog/2018/12/dl-11.html

什么是注意力?

当我们想起‘注意力’(attention)这个词时,我们知道这意味着它会引导你专注于某个事物并引起更大的注意。像黑体加粗就是一种注意力。注意力机制在深度学习中则意味着在处理数据时我们会对某些因素(factors)给予更多的注意。

在更广的层面上看,attention是网络结构的一个组成,并由它负责管理和量化 相互依赖(inter-dependence)
1.在输入和输出元素之间(General Attention)
2.在输入元素之内(Self-Attention)

我们来看看一个attention在机器翻译中的例子。如果我们有句子 “How was your day”,想把它翻译成法语- “Comment se passe ta journée”。attention会做的就是把输入句子中重要且相关的词映射(map)到输出句子中的词,并且给这些词更高的权重,提升输出预测的准确性。

在翻译的每一步,权重都被赋予到输入词上

上述关于attention的解释比较宽泛与模糊,因为目前有许多种attention。在这里我们只介绍最常用的几种attention,它们常常用于sequence-to-sequence模型。虽然attention机制在计算机视觉有一定的应用,但目前它仍主要用于NLP任务,比如解决机器翻译中长序列的问题。

我们经常看到attention有如下的解释,但这种解释不够细致、深入,忽略了许多的先决知识,对初学者并不友好。
在这里插入图片描述

下面,我们将从本质来讲解推导attention机制

Attention in Sequence-to-Sequence Models

在这里插入图片描述
普通的seq2seq模型通常不能处理长的输入序列,因为在encoder中,只有最后一层的隐藏层才能作为decoder的上下文(context)向量,如图中黑色箭头所示。
而attention直接解决了这个问题因为它保存并利用了encoder的所有隐藏层:它建立了一个特殊的映射,使得每一个encoder的隐藏层都能与decoder的输出有关联。这意味着当decoder生成一个输出时,它可以从这个输入序列中选出特殊的元素,而不是只从最后一层的隐藏层生成输出。

Attention的种类

attention主要有两种:Bahdanau Attention和Luong Attention
在这里插入图片描述

Attention的种类

第一种attention,通常叫做加性注意力(Additive Attention),来源于Dzmitry Bahdanau的论文。这篇文章旨在通过attention给予decoder以相关的输入句子。在该论文中,完整的步骤如下:

1.生成encoder的隐藏层
2.计算Alignment Scores (有些人翻译为相似度)
(注:encoder的最后一层隐藏层可用作decoder的第一层隐藏层)
3.对Alignment Scores进行softmax
4.计算上下文向量
5.对输出解码(decoding)

步骤2-5在每段时间(time step)不断重复直到有某种标志或输出超过了指定的最大长度。
在这里插入图片描述
下面是具体阐述与代码讲解
1. Producing the Encoder Hidden States
首先,我们会用RNN或它的变体(LSTM,GRU)去解码(encode)输入序列。在这里插入图片描述
如图,每一个encoder RNN会对输入生成一个隐藏层状态。而后,我们会把隐藏层状态传给下一层RNN.

class EncoderLSTM(nn.Module):
  def __init__(self, input_size, hidden_size, n_layers=1, drop_prob=0):
    super(EncoderLSTM, self).__init__()
    self.hidden_size = hidden_size
    self.n_layers = n_layers
    
    self.embedding = nn.Embedding(input_size, hidden_size)
    self.lstm = nn.LSTM(hidden_size, hidden_size, n_layers, dropout=drop_prob, batch_first=True)

  def forward(self, inputs, hidden):
    #这里我们假设是语言任务,把输入embed成词向量
    embedded = self.embedding(inputs)
    #使词向量通过encoderLSTM,并返回输出
    output, hidden = self.lstm(embedded, hidden)
    return output, hidden

  def init_hidden(self, batch_size=1):
    return (torch.zeros(self.n_layers, batch_size, self.hidden_size, device=device),
            torch.zeros(self.n_layers, batch_size, self.hidden_size, device=device))

2. 计算 Alignment Scores
下面是前向传播:

class BahdanauDecoder(nn.Module):
  def __init__(self, hidden_size, output_size, n_layers=1, drop_prob=0.1):
    super(BahdanauDecoder, self).__init__()
    self.hidden_size = hidden_size
    self.output_size = output_size
    self.n_layers = n_layers
    self.drop_prob = drop_prob

    self.embedding = nn.Embedding(self.output_size, self.hidden_size)
    
    self.fc_hidden = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
    self.fc_encoder = nn.Linear(self.hidden_size, self.hidden_size, bias=False)
    self.weight = nn.Parameter(torch.FloatTensor(1, hidden_size))
    self.attn_combine = nn.Linear(self.hidden_size * 2, self.hidden_size)
    self.dropout = nn.Dropout(self.drop_prob)
    self.lstm = nn.LSTM(self.hidden_size*2, self.hidden_size, batch_first=True)
    self.classifier = nn.Linear(self.hidden_size, self.output_size)

  def forward(self, inputs, hidden, encoder_outputs):
    encoder_outputs = encoder_outputs.squeeze()
    # Embed input words
    embedded = self.embedding(inputs).view(1, -1)
    embedded = self.dropout(embedded)
    
    # Calculating Alignment Scores
    x = torch.tanh(self.fc_hidden(hidden[
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于注意力机制的代码,我们先来了解一下图注意力机制(Graph Attention Network,简称GAT)。 GAT是一种基于图结构的注意力机制,它在图结构进行节点分类、图分类等任务时,能够自适应地学习每个节点在不同邻居节点上所占的重要性,从而更准确地进行分类。下面是一个简单的GAT实现: ```python import torch import torch.nn as nn import torch.nn.functional as F class GraphAttentionLayer(nn.Module): def __init__(self, in_features, out_features, dropout, alpha, concat=True): super(GraphAttentionLayer, self).__init__() self.in_features = in_features self.out_features = out_features self.dropout = dropout self.alpha = alpha self.concat = concat self.W = nn.Parameter(torch.zeros(size=(in_features, out_features))) nn.init.xavier_uniform_(self.W.data, gain=1.414) self.a = nn.Parameter(torch.zeros(size=(2*out_features, 1))) nn.init.xavier_uniform_(self.a.data, gain=1.414) self.leakyrelu = nn.LeakyReLU(self.alpha) def forward(self, h, adj): Wh = torch.mm(h, self.W) a_input = self._prepare_attentional_mechanism_input(Wh) e = self.leakyrelu(torch.matmul(a_input, self.a).squeeze(2)) zero_vec = -9e15*torch.ones_like(e) attention = torch.where(adj > 0, e, zero_vec) attention = F.softmax(attention, dim=1) attention = F.dropout(attention, self.dropout, training=self.training) h_prime = torch.matmul(attention, Wh) if self.concat: return F.elu(h_prime) else: return h_prime def _prepare_attentional_mechanism_input(self, Wh): N = Wh.size()[0] Wh_repeated_in_chunks = Wh.repeat_interleave(N, dim=0) Wh_repeated_alternating = Wh.repeat(N, 1) all_combinations_matrix = torch.cat([Wh_repeated_in_chunks, Wh_repeated_alternating], dim=1) return all_combinations_matrix.view(N, N, 2 * self.out_features) ``` 在这个代码,我们定义了一个名为GraphAttentionLayer的类,它继承于nn.Module类。在它的__init__方法,我们定义了一些必要的参数,包括输入特征维度、输出特征维度、dropout率、LeakyReLU函数的负斜率系数以及是否将节点特征与注意力机制的输出进行拼接。W和a是需要学习的参数,其W是线性变换的权重矩阵,a是注意力机制的权重矩阵。我们使用xavier_uniform_方法对这两个参数进行初始。 在forward方法,我们首先将节点特征矩阵h与权重矩阵W相乘,得到Wh。然后,我们通过_prepare_attentional_mechanism_input方法将Wh转换为用于注意力计算的输入矩阵a_input。接着,我们将a_input与注意力权重矩阵a相乘,得到每个节点与其邻居之间的注意力系数e。我们使用LeakyReLU函数将e的负值裁剪掉。然后,我们对每个节点的邻居节点计算softmax,得到它们之间的注意力权重。我们使用dropout对注意力权重进行随机失活,以防止过拟合。最后,我们将注意力权重与Wh相乘,得到每个节点的新特征h_prime。如果concat参数为True,我们将h_prime与原始节点特征进行拼接并使用ELU函数作为输出;否则,我们直接返回h_prime作为输出。 需要注意的是,这个代码的实现是基于PyTorch框架的,如果你使用其他的深度学习框架,可能需要做一些调整。同时,这个代码只是GAT的一个简单实现,如果你想深入学习GAT,还需要阅读相关论文并了解更多细节。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值