【深度学习中的注意力机制2】11种主流注意力机制112个创新研究paper+代码——多头注意力机制(Multi-Head Attention, MHA)
【深度学习中的注意力机制2】11种主流注意力机制112个创新研究paper+代码——多头注意力机制(Multi-Head Attention, MHA)
【深度学习中的注意力机制2】11种主流注意力机制112个创新研究paper+代码——多头注意力机制(Multi-Head Attention, MHA)
文章目录
- 【深度学习中的注意力机制2】11种主流注意力机制112个创新研究paper+代码——多头注意力机制(Multi-Head Attention, MHA)
- 1. 起源与提出
- 2. 原理
- 2.1 线性变换
- 2.2 并行计算
- 2.3 拼接结果
- 2.4 最终线性变换
- 3. 发展
- 4. 代码实现
- 5. 代码解释
- 6. 总结
欢迎宝子们点赞、关注、收藏!欢迎宝子们批评指正!
祝所有的硕博生都能遇到好的导师!好的审稿人!好的同门!顺利毕业!
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文:
可访问艾思科蓝官网,浏览即将召开的学术会议列表。会议入口:https://ais.cn/u/mmmiUz
1. 起源与提出
多头注意力机制(Multi-Head Attention, MHA)是Transformer模型中提出的一种增强型注意力机制,由Vaswani et al. 在2017年提出的论文《Attention is All You Need》中引入。该机制建立在缩放点积注意力(Scaled Dot-Product Attention)的基础上,旨在通过多个独立的注意力头来捕捉不同子空间中的特征信息。
在传统的缩放点积注意力中,只有一个注意力头(single-head attention)对整个输入序列进行操作,这可能导致信息的表达能力不足。而多头注意力通过将输入进行多个不同子空间的线性投影,能够从不同的角度对输入进行关注,有效提升模型捕捉特征的能力。
2. 原理
多头注意力的核心思想是并行地执行多个独立的缩放点积注意力,每个注意力头处理不同的子空间,然后将这些注意力头的输出拼接起来,形成最终的结果。这样做的好处是,模型可以在多个子空间中同时学习不同的特征,从而捕获更多的上下文信息。
多头注意力机制的步骤如下:
2.1 线性变换
- 将输入的Query(Q)、Key(K)、Value(V)通过不同的线性层分别映射为多个子空间,通常是将其分为多个头部,每个头部关注输入序列的不同部分。
2.2 并行计算
- 对每个头部分别进行缩放点积注意力的计算。
2.3 拼接结果
- 将所有头部的注意力输出结果拼接在一起,形成一个新的张量。
2.4 最终线性变换
- 通过最后一层线性变换将拼接结果映射回原始的维度。
公式如下:
其中, h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) head_i=Attention(QW^Q_i,KW^K_i,VW^V_i) headi=Attention(QWiQ,KWiK,VWiV), W i Q W^Q_i WiQ, W i K W^K_i WiK, W i V W^V_i WiV是不同的线性变换矩阵, W O W^O WO是最后的线性变换矩阵。
3. 发展
多头注意力机制极大地增强了Transformer的表示能力,使其不仅能在自然语言处理中表现出色,还能够在图像处理、多模态任务、时间序列分析等领域中取得突破。
在NLP中,模型如BERT、GPT等都采用了多头注意力来学习句子和词汇之间的复杂关系。在图像处理领域,多头注意力也被应用在Vision Transformer(ViT)等模型中,替代卷积操作进行图像特征提取。
4. 代码实现
以下是一个简单的多头注意力机制的实现,基于PyTorch框架:
import torch
import torch.nn as nnclass MultiHeadAttention(nn.Module):def __init__(self, d_model, num_heads):super(MultiHeadAttention, self).__init__()assert d_model % num_heads == 0, "d_model必须能被num_heads整除"self.d_model = d_modelself.num_heads = num_headsself.depth = d_model // num_heads # 每个头部的深度# 定义用于Q, K, V的线性变换self.wq = nn.Linear(d_model, d_model)self.wk = nn.Linear(d_model, d_model)self.wv = nn.Linear(d_model, d_model)# 输出的线性层self.dense = nn.Linear(d_model, d_model)def split_heads(self, x, batch_size):"""将d_model维度拆分为num_heads个部分,并交换维度"""x = x.view(batch_size, -1, self.num_heads, self.depth)return x.transpose(1, 2) # [batch_size, num_heads, seq_len, depth]def forward(self, Q, K, V, mask=None):batch_size = Q.size(0)# 线性变换 Q, K, VQ = self.wq(Q) # [batch_size, seq_len, d_model]K = self.wk(K) # [batch_size, seq_len, d_model]V = self.wv(V) # [batch_size, seq_len, d_model]# 拆分为多个头部Q = self.split_heads(Q, batch_size) # [batch_size, num_heads, seq_len, depth]K = self.split_heads(K, batch_size) # [batch_size, num_heads, seq_len, depth]V = self.split_heads(V, batch_size) # [batch_size, num_heads, seq_len, depth]# 计算缩放点积注意力attention_scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.depth, dtype=torch.float32))if mask is not None:attention_scores = attention_scores.masked_fill(mask == 0, -1e9)attention_weights = nn.Softmax(dim=-1)(attention_scores)attention_output = torch.matmul(attention_weights, V)# 交换维度并拼接所有头部的输出attention_output = attention_output.transpose(1, 2).contiguous()attention_output = attention_output.view(batch_size, -1, self.d_model) # [batch_size, seq_len, d_model]# 最后通过线性变换映射回原始维度output = self.dense(attention_output)return output# 示例输入
batch_size = 2
seq_len = 5
d_model = 16 # 模型维度
num_heads = 4 # 注意力头的数量# 随机初始化Q, K, V
Q = torch.rand(batch_size, seq_len, d_model)
K = torch.rand(batch_size, seq_len, d_model)
V = torch.rand(batch_size, seq_len, d_model)# 实例化多头注意力层
multi_head_attention = MultiHeadAttention(d_model, num_heads)
output = multi_head_attention(Q, K, V)print("输出:", output)
5. 代码解释
class MultiHeadAttention(nn.Module)
:
- 定义一个多头注意力类,继承自
torch.nn.Module
。
__init__(self, d_model, num_heads)
:
- 初始化函数接收两个参数:
d_model
是输入的模型维度,num_heads
是多头注意力的头数。
assert d_model % num_heads == 0
:
- 确保
d_model
可以被num_heads
整除,以便将d_model均匀分配给每个头。
self.wq, self.wk, self.wv
:
- 定义Query、Key和Value的线性变换,分别将输入映射到不同的子空间。
self.split_heads(x, batch_size)
:
- 将输入张量的维度分割成num_heads个子空间。
- 输入维度形状为
[batch_size, seq_len, d_model]
,经过变换后形状变为[batch_size,num_heads, seq_len, depth]
,其中depth = d_model // num_heads
。
forward(self, Q, K, V, mask=None)
:
- 线性变换Q、K、V: 将输入的Q、K、V通过线性层分别映射到对应的维度。
- 拆分为多个头部: 使用
split_heads
函数将Q、K、V拆分为多个头部,便于并行计算注意力。 - 缩放点积注意力: 计算Q和K的点积并进行缩放,然后通过softmax得到注意力权重。
- 加权求和: 使用注意力权重对V加权求和,得到注意力输出。
- 拼接并线性变换: 拼接所有头部的输出,并通过线性层映射回原始维度。
使用示例:
- 随机生成输入Q、K、V,维度为
[batch_size, seq_len, d_model]
。 - 调用
multi_head_attention(Q, K, V)
来获取输出结果。
6. 总结
多头注意力机制通过并行多个独立的注意力头,大大提升了模型捕捉特征的能力。它在Transformer模型中起到了核心作用,并被广泛应用于自然语言处理和图像处理等领域。
欢迎宝子们点赞、关注、收藏!欢迎宝子们批评指正!
祝所有的硕博生都能遇到好的导师!好的审稿人!好的同门!顺利毕业!
大多数高校硕博生毕业要求需要参加学术会议,发表EI或者SCI检索的学术论文会议论文:
可访问艾思科蓝官网,浏览即将召开的学术会议列表。会议入口:https://ais.cn/u/mmmiUz