1.1注意力机制的基本原理:
-
计算注意力权重:
注意力权重是通过计算输入数据中各个部分之间的相关性来得到的。这些权重表示在给定上下文下,数据的某个部分相对于其他部分的重要性。 -
加权求和:
使用这些注意力权重对输入数据进行加权求和,以生成一个紧凑的表示,该表示集中了输入数据的关键信息。
1.2数学原理:
假设我们有一个输入序列 X=[x1,x2,...,xn] ,其中 xi 是序列中的元素。在自注意力机制中,我们首先将输入转换为查询(Q)、键(K)和值(V):
变体:
- 多头注意力(Multi-Head Attention):
- 在 Transformer 模型中,使用了多头注意力机制,它将 Q、K、V 分割为多个“头”,每个头在不同的表示子空间中学习注意力:
1.3代码实现:
class Attention(nn.Module):
def __init__(self, dim, heads=8, dim_head=64, dropout=0.):
super().__init__()
inner_dim = dim_head * heads
project_out = not (heads == 1 and dim_head == dim)
self.heads = heads
self.scale = dim_head ** -0.5 #缩放因子,用于调整注意力得分的规模,通常是 dim_head 的平方根的倒数
self.attend = nn.Softmax(dim = -1) #Softmax 函数,用于计算注意力权重
self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
self.to_out = nn.Sequential(
nn.Linear(inner_dim, dim),
nn.Dropout(dropout)
) if project_out else nn.Identity()
def forward(self, x):
qkv = self.to_qkv(x).chunk(3, dim=-1)
q, k, v = map(lambda t: rearrange(t, 'b p n (h d) -> b p h n d', h = self.heads), qkv)
dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale
attn = self.attend(dots)
out = torch.matmul(attn, v)
out = rearrange(out, 'b p h n d -> b p n (h d)')
return self.to_out(out)
forward(self, x):
-
生成查询(Q)、键(K)和值(V):
qkv = self.to_qkv(x).chunk(3, dim=-1)
: 这行代码使用一个线性变换(self.to_qkv
)将输入x
转换为查询(Q)、键(K)和值(V)这三组向量,然后将其分割成三个部分。
-
重排为多头格式:
q, k, v = map(...)
: 这里使用rearrange
函数将 Q、K 和 V 的形状转换为多头格式。原始的扁平形状被重排为一个具有多个头部的形状,以便独立进行自注意力运算。
-
计算注意力得分:
dots = torch.matmul(q, k.transpose(-1, -2)) * self.scale
: 这里计算查询(Q)和键(K)之间的点积,以得到注意力得分。得分通过self.scale
(一个基于头维度dim_head
的缩放因子)进行缩放,以防止梯度消失或爆炸。
-
应用 Softmax 获取注意力权重:
attn = self.attend(dots)
: 使用 Softmax 函数对注意力得分进行归一化,得到每个键对应的注意力权重。
-
加权和以得到输出:
out = torch.matmul(attn, v)
: 将注意力权重应用于值(V),得到加权和,这是自注意力的输出。
-
重排并通过输出层:
out = rearrange(out, 'b p h n d -> b p n (h d)')
: 将输出重排回原始格式,并通过可能存在的输出线性层和 dropout 层。