【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper+代码——加性注意力(Additive Attention)
【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper+代码——加性注意力(Additive Attention)
文章目录
- 【深度学习中的注意力机制6】11种主流注意力机制112个创新研究paper+代码——加性注意力(Additive Attention)
- 1. 加性注意力的起源与提出
- 2. 加性注意力的原理
- 3. 发展
- 4. 代码实现
- 5. 代码逐句解释
欢迎宝子们点赞、关注、收藏!欢迎宝子们批评指正!
祝所有的硕博生都能遇到好的导师!好的审稿人!好的同门!顺利毕业!
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文:
可访问艾思科蓝官网,浏览即将召开的学术会议列表。会议入口:https://ais.cn/u/mmmiUz
1. 加性注意力的起源与提出
加性注意力(Additive Attention)是由Bahdanau et al. 在其2015年关于机器翻译的论文中提出的。这一注意力机制被应用于神经机器翻译(NMT)模型中,旨在提高翻译任务中序列对序列(Seq2Seq)模型的性能,尤其是解决长距离依赖问题。传统的Seq2Seq模型仅依赖于编码器的最终隐藏状态来生成翻译,这在处理长文本时容易丢失输入的细节信息。加性注意力通过在解码过程中对编码器隐藏状态进行加权求和,显著提升了模型性能。
加性注意力是一种较早提出的注意力机制,与随后流行的点积注意力不同,加性注意力通过一个可学习的网络计算注意力分数,而不是直接计算向量之间的点积。加性注意力的提出标志着注意力机制在深度学习领域中的广泛应用,尤其是在处理长序列数据时的应用。
2. 加性注意力的原理
加性注意力的核心思想是通过学习一个函数来计算查询(Query)和键(Key)之间的相似性,然后根据相似性对值(Value)进行加权。
具体步骤如下:
1) 输入:
- Query:解码器中的当前隐藏状态。
- Key 和 Value:编码器中的隐藏状态(通常是一系列时间步的隐藏状态序列)。
2) 计算注意力分数: 通过将Query和Key进行非线性变换,再经过加性函数求得注意力分数。这个过程使用了一个可学习的权重矩阵,将查询和键分别映射到一个共同的表示空间,计算它们的相似性。
3) softmax归一化: 将上述得到的注意力分数通过softmax函数进行归一化,得到注意力权重。
4) 加权求和: 使用得到的注意力权重对值(Value)进行加权求和,生成最终的加权上下文向量。
公式如下:
这里, W q W_q Wq 和 W k W_k Wk是可学习的权重矩阵, e i j e_{ij} eij 是注意力分数, v j v_j vj是Value。
3. 发展
加性注意力是最早被提出的注意力机制之一,并在神经机器翻译中取得了显著的成果。后来,随着注意力机制的发展,点积注意力(如Transformer中的缩放点积注意力)因其更高效的计算方式而逐渐取代了加性注意力。然而,加性注意力仍然在某些场景中被使用,尤其是在需要更细致的相似性计算的任务中。
在性能方面,加性注意力与点积注意力的主要区别在于计算复杂度。加性注意力通过一个可学习的神经网络计算注意力分数,计算复杂度为 O ( d ) O(d) O(d),而点积注意力直接计算点积,复杂度为 O ( d 2 ) O(d^2) O(d2),这使得加性注意力在某些场景下具有优势。
4. 代码实现
下面是一个使用加性注意力机制的简化实现,基于PyTorch框架。
import torch
import torch.nn as nn
import torch.nn.functional as Fclass AdditiveAttention(nn.Module):def __init__(self, query_dim, key_dim, hidden_dim):super(AdditiveAttention, self).__init__()# 定义线性层,用于将查询和键映射到同一空间self.query_layer = nn.Linear(query_dim, hidden_dim)self.key_layer = nn.Linear(key_dim, hidden_dim)# 定义一个线性层,用于计算注意力分数self.energy_layer = nn.Linear(hidden_dim, 1)def forward(self, query, keys, values):# query: [batch_size, query_dim]# keys: [batch_size, seq_len, key_dim]# values: [batch_size, seq_len, value_dim]# 计算查询和键的投影query_proj = self.query_layer(query) # [batch_size, hidden_dim]keys_proj = self.key_layer(keys) # [batch_size, seq_len, hidden_dim]# 将查询扩展到和键的时间步相同的维度query_proj = query_proj.unsqueeze(1).expand_as(keys_proj) # [batch_size, seq_len, hidden_dim]# 计算 e_ij = tanh(W_q q + W_k k)energy = torch.tanh(query_proj + keys_proj) # [batch_size, seq_len, hidden_dim]# 计算注意力分数,并去掉最后一维attention_scores = self.energy_layer(energy).squeeze(-1) # [batch_size, seq_len]# 通过softmax得到注意力权重attention_weights = F.softmax(attention_scores, dim=1) # [batch_size, seq_len]# 加权求和值context = torch.bmm(attention_weights.unsqueeze(1), values).squeeze(1) # [batch_size, value_dim]return context, attention_weights# 测试加性注意力
batch_size = 2
query_dim = 5
key_dim = 5
value_dim = 6
seq_len = 10
hidden_dim = 20# 随机生成查询、键和值
query = torch.randn(batch_size, query_dim)
keys = torch.randn(batch_size, seq_len, key_dim)
values = torch.randn(batch_size, seq_len, value_dim)# 实例化加性注意力
additive_attention = AdditiveAttention(query_dim, key_dim, hidden_dim)# 前向传播
context, attention_weights = additive_attention(query, keys, values)print("上下文向量:", context)
print("注意力权重:", attention_weights)
5. 代码逐句解释
1. 导入库:
import torch
import torch.nn as nn
import torch.nn.functional as F
导入PyTorch库,其中torch
用于张量操作,nn
包含神经网络模块,F
提供常用函数如softmax。
2. 定义加性注意力类:
class AdditiveAttention(nn.Module):def __init__(self, query_dim, key_dim, hidden_dim):super(AdditiveAttention, self).__init__()# 定义线性层,用于将查询和键投影到同一维度self.query_layer = nn.Linear(query_dim, hidden_dim)self.key_layer = nn.Linear(key_dim, hidden_dim)# 定义计算注意力能量的线性层self.energy_layer = nn.Linear(hidden_dim, 1)
这里定义了AdditiveAttention
类,继承自nn.Module
。query_layer
和key_layer
分别是将查询和键投影到同一维度的线性层,energy_layer
用于计算注意力能量分数。
3. 前向传播函数:
def forward(self, query, keys, values):query_proj = self.query_layer(query) # [batch_size, hidden_dim]keys_proj = self.key_layer(keys) # [batch_size, seq_len, hidden_dim]# 扩展查询的维度,使其与键对齐query_proj = query_proj.unsqueeze(1).expand_as(keys_proj)# 计算注意力能量:e_ij = tanh(W_q q + W_k k)energy = torch.tanh(query_proj + keys_proj) # [batch_size, seq_len, hidden_dim]# 通过线性层计算注意力分数,并去掉最后一维attention_scores = self.energy_layer(energy).squeeze(-1) # [batch_size, seq_len]# 使用softmax归一化得到注意力权重attention_weights = F.softmax(attention_scores, dim=1) # [batch_size, seq_len]# 计算上下文向量,通过加权求和值context = torch.bmm(attention_weights.unsqueeze(1), values).squeeze(1) # [batch_size, value_dim]return context, attention_weights
forward
函数负责计算加性注意力的前向传播过程。首先,将查询和键分别通过线性层映射到相同的维度。- 然后,计算注意力能量,并使用softmax进行归一化,得到注意力权重。
- 最后,使用这些注意力权重对值进行加权求和,生成上下文向量。
4. 测试模型:
# 测试加性注意力
query = torch.randn(batch_size, query_dim)
keys = torch.randn(batch_size, seq_len, key_dim)
values = torch.randn(batch_size, seq_len, value_dim)# 实例化加性注意力
additive_attention = AdditiveAttention(query_dim, key_dim, hidden_dim)# 前向传播
context, attention_weights = additive_attention(query, keys, values)print("上下文向量:", context)
print("注意力权重:", attention_weights)
在这里,使用随机生成的张量query
、keys
和values
来测试加性注意力的输出。
欢迎宝子们点赞、关注、收藏!欢迎宝子们批评指正!
祝所有的硕博生都能遇到好的导师!好的审稿人!好的同门!顺利毕业!
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文:
可访问艾思科蓝官网,浏览即将召开的学术会议列表。会议入口:https://ais.cn/u/mmmiUz