当前位置: 首页 > news >正文

【深度学习中的注意力机制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


http://www.mrgr.cn/news/55103.html

相关文章:

  • 利用飞腾派进行OpenCV开发
  • 人工智能:塑造未来生活与工作的力量
  • 【JAVA】第一张_Java基础语法
  • RHEL: rpm2cpio: signature hdr data: BAD, no. of bytes(19987) out of range
  • Pencils Protocol 用户特权?持有 DAPP 将获 Scroll 生态空投!
  • opencv出错以及解决技巧
  • AG32 MCU家族添加新成员
  • 汽车电子笔记之-014:一场FIFO的思考引发将汽车电子DTC相关 - 故障发生前后关键数据记录并回读的功能浅研发
  • edge浏览器:你的连接不是专用连接
  • Java获取指定目录下的文件名,并自定义排序
  • 关于鸿蒙学习之遇到的问题——ERROR: Invalid dependency entry
  • 神奇的数据结构 —— 跳表
  • 道路车辆功能安全 ISO 26262标准(6-1)—软件级产品开发
  • Java 异步编程——异步编排(CompletableFuture)
  • 三周精通FastAPI:4 使用请求从客户端(例如浏览器)向 API 发送数据
  • SCTF-2024-wp
  • LabVIEW换流变换器智能巡检系统
  • 流量分类实验
  • JAVA基础【第三篇】
  • JavaScript报错:Uncaught SyntaxError: Unexpected end of input(at test.html:1:16)
  • 上市遭冷遇,AIGC难救七牛云
  • 【Linux 从基础到进阶】应用程序性能调优(Java、Python等)
  • 使用ROS一键部署LNMP环境
  • 测试测试测试07
  • 2024年10月20日
  • 给定一个正整数n随机生成n个字节即生成2n个十六进制数将其组成字符串返回secrets.token_hex(n)