Self-Attention
自注意力让序列中的每个词元都能根据查询、键和值来衡量其他每个词元的重要性,这些查询、键和值均来自同一输入。它是 Transformer 的核心机制。
自注意力是一种注意力形式,其中查询、键和值都来自同一个序列,因此每个token都会根据该序列中的其他所有 token 构建自己的新表示。单个自注意力层就能一步关联段落的首尾词,或图像中位于对角的角落;而循环神经网络 (RNN)每个位置都需要一步,卷积神经网络 (CNN)则需要堆叠许多层才能扩大感受范围。与前馈层堆叠后,自注意力构成了 2017 年论文 Attention Is All You Need中提出的 Transformer,它是大语言模型 (LLM)、视觉 Transformer (ViT)和基于 Transformer 的检测器的基础。
自注意力的工作原理#
每个输入 token 都以嵌入表示,并与三个可学习矩阵相乘,得到查询、键和值。token i 的输出是所有 token 的值向量的加权平均,权重由 token i 的查询与所有键之间的缩放点积经过 softmax 得出,这就是注意力机制页面所述的缩放点积注意力。由于查询、键和值都是同一批 token 的投影,长度为 n 的序列会生成一个 n × n 权重矩阵。在“The animal didn't cross the street because it was too tired”这句话中,“it”对应的行可以将大部分权重分配给“animal”,并将该词的含义融入“it”自身的表示中。
多头自注意力会在较小的投影上并行执行多次此类计算,再将结果拼接起来,因此不同的注意力头可以追踪不同关系,例如一个头关注句法,另一个头关注共指。原始 Transformer 在 512 维模型中使用了 8 个头,每个头为 64 维。
顺序盲区与因果掩码#
自注意力将输入视为一个集合。打乱 token 会以相同方式打乱输出,而不会改变其他内容,因此模型会加入位置信息,例如原始 Transformer 中的正弦嵌入,或当前大多数 LLM 中的旋转位置嵌入 (RoPE)。BERT 等编码器允许每个 token 双向关注。仅解码器 LLM 会应用因果掩码,使每个 token 只能关注自身及之前的 token;这样模型就能从左到右生成文本,并通过 KV 缓存复用之前 token 的键和值。PyTorch 的 MultiheadAttention在将同一个张量作为查询、键和值传入时,展示了这两种特性:
import torch
torch.manual_seed(0)
tokens = torch.randn(1, 5, 16) # 一个序列包含 5 个 token,每个 token 有 16 个特征
attn = torch.nn.MultiheadAttention(embed_dim=16, num_heads=2, batch_first=True)
# 自注意力:查询、键和值都是同一批 token 的投影
out, weights = attn(tokens, tokens, tokens)
print("Attention weights shape:", tuple(weights.shape))
# 打乱 token 只会打乱输出,因此没有位置信息时无法识别词序
perm = torch.tensor([3, 0, 4, 1, 2])
out_shuffled, _ = attn(tokens[:, perm], tokens[:, perm], tokens[:, perm])
print("Same outputs after shuffling:", torch.allclose(out_shuffled, out[:, perm], atol=1e-6))
# 因果掩码会阻止模型关注后续 token,就像仅解码器 LLM 中那样
mask = torch.triu(torch.ones(5, 5, dtype=torch.bool), diagonal=1)
_, causal_weights = attn(tokens, tokens, tokens, attn_mask=mask)
print(causal_weights[0].detach().round(decimals=2))输出结果会显示一个 (1, 5, 5) 权重形状、用于打乱测试的 True,以及一个下三角矩阵:第一个 token 将权重 1.00 分配给自身,第二个 token 在前两个 token 之间分别分配 0.31 和 0.69,而对角线上方的每个元素都是 0.00。
自注意力与相关术语的区别#
- 注意力机制:根据查询与键的相似度对值进行加权的一般操作。如果查询、键和值都来自同一个序列,这种情况就是自注意力。
- 交叉注意力:查询来自一个序列,键和值来自另一个序列。翻译解码器会关注编码后的源句子,DETR 解码器的对象查询会关注图像特征,而文本到图像的扩散模型会关注提示词。
- 卷积:在每个位置应用相同的小型滤波器,因此每个输出只查看固定的局部窗口,其权重不随内容变化。自注意力则根据内容计算权重,并覆盖整个输入。
原始的编码器-解码器 Transformer 将双向自注意力、因果自注意力和交叉注意力结合起来:
计算开销与高效变体#
计算每一对 token 的分数会使时间和内存开销随序列长度的平方增长:1,000 个 token 每个头会产生 100 万个分数,100,000 个 token 则会产生 100 亿个分数。FlashAttention通过分块计算精确的自注意力,无需存储完整矩阵;分组查询注意力 (GQA)在多个头之间共享键和值,以缩小 KV 缓存;而滑动窗口注意力、稀疏注意力和线性注意力会减少参与计算的 token 对数量。在视觉任务中,token 数量随图像分辨率变化,因此许多检测器只在特征图尺寸最小时应用自注意力。YOLO26仅在其主干网络末端的 C2PSA 模块和颈部中的一个启用注意力的 C3k2 模块中运行多头自注意力;两者都作用于 640 像素图像上的 20×20、步幅为 32 的特征图,也就是 400 个 token。其注意力模块通过在该特征图上应用一个 1×1 卷积来计算查询、键和值,并对值应用 3×3 深度卷积来加入位置信息。










