一、引言
注意力机制(Attention Mechanism)源于对人类视觉的研究,是一种在深度学习模型中模拟人类注意力的机制。它允许模型在处理信息时能够聚焦于当前任务最相关的部分,从而提高模型的性能和泛化能力。本文将从注意力机制的起源、类型、结构图、计算处理过程、主要公式、代码示例以及效果图等方面进行全面介绍。
二、注意力机制的起源
在认知科学中,由于信息处理的瓶颈,人类会选择性地关注所有信息的一部分,同时忽略其他可见的信息。这种机制通常被称为注意力机制。人类视网膜不同的部位具有不同程度的信息处理能力,即敏锐度(Acuity),只有视网膜中央凹部位具有最强的敏锐度。为了合理利用有限的视觉信息处理资源,人类需要选择视觉区域中的特定部分,然后集中关注它。例如,人们在阅读时,通常只有少量要被读取的词会被关注和处理。
注意力机制主要有两个方面:决定需要关注输入的哪部分;分配有限的信息处理资源给重要的部分。注意力机制可以应用于任何类型的输入而不管其形状如何,是在计算能力有限情况下,解决信息超载问题的主要手段的一种资源分配方案。
三、注意力机制的类型
注意力机制在深度学习中有多种类型,主要包括以下几种:
- 自注意力机制(Self-Attention Mechanism):自注意力机制在单个序列的不同位置之间建立联系,以计算同一序列的表示。这种机制在自然语言处理(NLP)和计算机视觉等领域有广泛的应用,特别是在Transformer模型中发挥了重要作用。
- 多头注意力机制(Multi-Head Attention Mechanism):多头注意力机制是自注意力的一个扩展,它将输入序列投影到多个不同的子空间中,并在每个子空间中独立地执行自注意力计算。这样做的目的是让模型能够从不同的表示子空间中捕捉信息,增强模型的表达能力。
- 通道注意力机制(Channel Attention Mechanism):通道注意力机制自适应地重新校准每个通道的权重,可以被视为对象选择过程,从而确定要注意什么。通道注意力机制的代表模型为压缩和激励网络(Squeeze-and-Excitation Networks, SENet)。
- 空间注意力机制(Spatial Attention Mechanism):空间注意力机制旨在提升关键区域的特征表达,本质上是将原始图片中的空间信息通过空间转换模块,变换到另一个空间中并保留关键信息,为每个位置生成权重掩膜(mask)并加权输出,从而增强感兴趣的特定目标区域同时弱化不相关的背景区域。空间注意力的代表模型为空间变换神经网络(Spatial Transformer Networks, STN)。
四、注意力机制的计算处理过程
注意力机制的计算处理过程主要包括以下几个步骤:
- 计算注意力得分:利用打分函数计算当前输入在整个输入序列中的重要性。重要性越高,注意力得分就越高,那么在生成输出的预测值时,就需要给予当前输入更多的关注。
- 权重归一化:得到注意力得分后,用softmax函数进行归一化,得到注意力概率分布。用这个注意力分布作为每个输入受关注程度的权重。
- 加权:对每个输入进行加权,就得到了注意力后的值。
五、主要公式
以下是注意力机制中的一些主要公式:
- 注意力得分计算:
其中,q 是查询向量,ki 是第 i 个键向量,α(q,ki) 是查询和键之间的相关性函数
2. 加性注意力:
3. 缩放点积注意力:
4. 注意力输出计算:
其中,s(kn,q) 是注意力打分函数,vn 是第 n 个值向量。
5. 多头注意力输出计算:
其中,Q=[q1,q2,…,qM] 是多个查询向量集合,⊕ 表示向量拼接。
六、代码示例
下面基于PyTorch的自注意力机制和多头注意力机制给出示例:
- 自注意力机制代码示例:
import torch | |
import torch.nn as nn | |
import torch.nn.functional as F | |
import math | |
class SelfAttention(nn.Module): | |
def __init__(self, embed_dim): | |
super(SelfAttention, self).__init__() | |
self.embed_dim = embed_dim | |
self.query_linear = nn.Linear(embed_dim, embed_dim) | |
self.key_linear = nn.Linear(embed_dim, embed_dim) | |
self.value_linear = nn.Linear(embed_dim, embed_dim) | |
self.final_linear = nn.Linear(embed_dim, embed_dim) | |
def forward(self, x): | |
batch_size, seq_len, embed_dim = x.size() | |
# Calculate queries, keys, and values | |
queries = self.query_linear(x) # (batch_size, seq_len, embed_dim) | |
keys = self.key_linear(x) # (batch_size, seq_len, embed_dim) | |
values = self.value_linear(x) # (batch_size, seq_len, embed_dim) | |
# Compute attention scores | |
attention_scores = torch.matmul(queries, keys.transpose(-2, -1)) / math.sqrt(self.embed_dim) | |
attention_weights = F.softmax(attention_scores, dim=-1) | |
# Compute attention output | |
attention_output = torch.matmul(attention_weights, values) | |
# Apply final linear layer | |
output = self.final_linear(attention_output) | |
return output | |
# Example usage | |
embed_dim = 64 # Embedding dimension | |
seq_len = 10 # Sequence length | |
batch_size = 1 # Batch size | |
# Dummy input tensor with shape (batch_size, seq_len, embed_dim) | |
x = torch.randn(batch_size, seq_len, embed_dim) | |
self_attention = SelfAttention(embed_dim) | |
attention_output = self_attention(x) | |
print(attention_output.shape) # Should be (batch_size, seq_len, embed_dim) |
2. 多头注意力机制代码示例:
import torch | |
import torch.nn as nn | |
import torch.nn.functional as F | |
import math | |
class MultiHeadAttention(nn.Module): | |
def __init__(self, embed_dim, num_heads): | |
super(MultiHeadAttention, self).__init__() | |
self.embed_dim = embed_dim | |
self.num_heads = num_heads | |
self.head_dim = embed_dim // num_heads | |
assert self.head_dim * num_heads |