目录
- 1. Scaled Dot-Product Attention
- 2. 多头注意力机制框图
- (1)计算公式
- (2)具体计算过程
- (3)具体代码
深度学习中的注意力机制(Attention Mechanism)是一种模仿人类视觉和认知系统的方法,它允许神经网络在处理输入数据时集中注意力于相关的部分。通过引入注意力机制,神经网络能够自动地学习并选择性地关注输入中的重要信息,提高模型的性能和泛化能力。
下图 展示了人类在看到一幅图像时如何高效分配有限注意力资源的,其中红色区域表明视觉系统更加关注的目标,从图中可以看出:人们会把注意力更多的投入到人的脸部。文本的标题以及文章的首句等位置。
1. Scaled Dot-Product Attention
在实际应用中,经常会用到 Attention 机制,其中最常用的是Scaled Dot-Product Attention,它是通过计算query和key之间的点积 来作为 之间的相似度。
Scaled 指的是 Q和K计算得到的相似度 再经过了一定的量化,具体就是 除以 根号下K_dim;
Dot-Product 指的是 Q和K之间 通过计算点积作为相似度;
Mask 可选择性 目的是将 padding的部分 填充负无穷,这样算softmax的时候这里就attention为0,从而避免padding带来的影响.
2. 多头注意力机制框图
多头注意力机制是在 Scaled Dot-Product Attention 的基础上,分成多个头,也就是有多个Q、K、V并行进行计算attention,可能侧重与不同的方面的相似度和权重。
(1)计算公式
(2)具体计算过程
①计算注意力得分:根据Query和Key计算两者的相似性或相关性。常见方法:求两者的向量点积(内积)。
②对注意力得分进行softmax归一化处理。
③输出:根据权重系数对value进行加权求和。
(3)具体代码
import torch
import torch.nn as nn
import numpy as np
import torch.nn.functional as F
class MultiHeadAttention(nn.Module):
#embedding_dim:输入向量的维度,num_heads:注意力机制头数
def __init__(self, embedding_dim, num_heads):
super(MultiHeadAttention, self).__init__()
self.num_heads = num_heads #总头数
self.embedding_dim = embedding_dim #输入向量的维度
self.d_k= self.embedding_dim// self.num_heads #每个头 分配的输入向量的维度数
self.softmax=nn.Softmax(dim=-1)
self.W_query = nn.Linear(in_features=embedding_dim, out_features=embedding_dim, bias=False)
self.W_key = nn.Linear(in_features=embedding_dim, out_features=embedding_dim, bias=False)
self.W_value = nn.Linear(in_features=embedding_dim, out_features=embedding_dim, bias=False)
self.fc_out = nn.Linear(embedding_dim, embedding_dim)
#输入张量 x 中的特征维度分成 self.num_heads 个头,并且每个头的维度为 self.d_k。
def split_head(self, x, batch_size):
x = x.reshape(batch_size, -1, self.num_heads, self.d_k)
return x.permute(0,2,1,3) #x (N_size, self.num_heads, -1, self.d_k)
def forward(self, x):
batch_size=x.size(0) #获取输入张量 x 的批量(batch size)大小
q= self.W_query(x)
k= self.W_key(x)
v= self.W_value(x)
#使用 split_head 函数对 query、key、value 进行头部切分,将其分割为多个注意力头。
q= self.split_head(q, batch_size)
k= self.split_head(k, batch_size)
v= self.split_head(v, batch_size)
##attention_scorce = q*k的转置/根号d_k
attention_scorce=torch.matmul(q, k.transpose(-2,-1))/torch.sqrt(torch.tensor(self.d_k, dtype=torch.float32))
attention_weight= self.softmax(attention_scorce)
## output = attention_weight * V
output = torch.matmul(attention_weight, v) # [h, N, T_q, num_units/h]
output = out.permute(0,2,1,3).contiguous() # [N, T_q, num_units]
output = out.reshape(batch_size,-1, self.embedding_dim)
output = self.fc_out(output)
return output