计算原理、公式推导与实战问答
目录导读
- 自注意力是什么? —— 从直觉到数学定义
- 自注意力的核心计算步骤 —— 三步法拆解
- Q、K、V矩阵的生成与意义
- 注意力分数的计算:点积与缩放
- Softmax归一化与权重分配
- 加权求和与输出生成
- 自注意力在Transformer中的角色
- 常见问答:为什么需要多头?为什么用缩放?
- 总结与延伸阅读
自注意力是什么?
问题:
自注意力和普通注意力有什么区别?为什么说它是“自”的?
回答:
自注意力(Self-Attention)让序列中的每一个元素都能关注到序列中其他所有元素,从而捕捉长距离依赖关系,普通注意力通常是“源-目标”之间的交互(如机器翻译中的编码器-解码器注意力),而自注意力是同一个序列内部的注意力,因此叫“自”,它的核心是让每个位置的表示不再是孤立的,而是基于全局上下文重新加权组合。
自注意力的核心计算步骤
自注意力的计算可归纳为 三步(以单头为例):
- 生成Q、K、V矩阵
- 计算注意力分数(Attention Scores)
- 加权求和得到输出
下面逐步骤深入。
Q、K、V矩阵的生成与意义
假设输入序列有 ( n ) 个token,每个token的原始嵌入向量维度为 ( d{\text{model}} )(例如512),那么输入矩阵 ( X ) 的形状为 ( n \times d{\text{model}} )。
自注意力需要三个可训练的参数矩阵:
- ( WQ )(维度 ( d{\text{model}} \times d_k ))
- ( WK )(维度 ( d{\text{model}} \times d_k ))
- ( WV )(维度 ( d{\text{model}} \times d_v ))
计算: [ Q = X W_Q,\quad K = X W_K,\quad V = X W_V ]
- Q(Query,查询):当前元素“想找谁”的向量表示。
- K(Key,键):每个元素“我是谁”的标识向量。
- V(Value,值):每个元素“我有什么信息”的实际内容。
注意:在Transformer原论文中,( d_k = dv = d{\text{model}} / h ),( h ) 是注意力头数。
直观比喻:
Q像是一个人在问“谁与我最相关?”,K像是每个人的名片,V像是每个人实际携带的信息,先通过Q与K的匹配度决定关注程度,再根据V提取内容。
注意力分数的计算:点积与缩放
1 点积注意力分数
对于矩阵 ( Q ) 和 ( K^T ) 进行矩阵乘法: [ \text{score}_{i,j} = Q_i \cdot K_j^T ] 即第 ( i ) 个查询与第 ( j ) 个键的内积,内积越大,表示两个向量越相似,注意力权重越高。
2 为什么需要缩放?
当 ( d_k ) 较大时(( d_k=64,128 )),点积的方差会变大,导致某些得分极大而其他得分极小,Softmax后梯度几乎消失。
解决方案:对点积除以 ( \sqrt{d_k} ),即 [ \text{scaled_score}_{i,j} = \frac{Q_i \cdot K_j^T}{\sqrt{d_k}} ]
问题:
为什么不直接除以 ( d_k ) 而用根号?
回答:
( Q, K ) 每个元素独立且服从均值为0、方差为1的分布,( Q_i \cdot K_j ) 的均值为0、方差为 ( d_k ),除以 ( \sqrt{d_k} ) 使方差变为1,保持数值稳定。
Softmax归一化与权重分配
对每个查询 ( i )(行),对其所有键的分数做Softmax: [ \text{attention_weights}{i,j} = \frac{\exp(\text{scaled_score}{i,j})}{\sum{k=1}^{n} \exp(\text{scaled_score}{i,k})} ]
这使每一行(对应一个token)的权重和为1,代表该token分配给其他token的“关注度”比例。
结果矩阵形状: ( n \times n )(每个token对其他所有token的注意力权重)。
加权求和与输出生成
用注意力权重矩阵乘以 ( V ) 矩阵: [ \text{Output} = \text{AttentionWeights} \times V ]
输出矩阵形状为 ( n \times d_v ),对于第 ( i ) 个位置: [ \text{output}i = \sum{j=1}^{n} \text{weight}_{i,j} \cdot V_j ]
即重新用Value信息加权组合,得到融合了全局上下文的新表示。
自注意力在Transformer中的角色
在Transformer中,自注意力模块是 编码器 和 解码器 的核心组件:
- 编码器层:每个token都可以看到整个输入序列(包括自己)。
- 解码器层:使用 掩码自注意力(Masked Self-Attention),只允许看到当前位置及之前的token,防止未来信息泄露。
Transformer会叠加 多头注意力(Multi-Head Attention),即并行计算多组Q、K、V,然后将输出拼接,再通过一个线性层整合。
常见问答
Q1:为什么需要多头注意力而不是单头?
A:单头自注意力可能只关注到一种模式(如语义相似性),多头允许模型在不同子空间中学习不同的关系模式(如语法关系、语义关联、距离依赖等),提高表达能力。
Q2:自注意力的计算复杂度是 ( O(n^2 d) ),对长序列不友好怎么办?
A:对,这是自注意力的主要瓶颈,改进方案包括:稀疏注意力(仅关注局部窗口)、线性注意力(如LinFormer)、Longformer、Reformer等,以及用滑动窗口或哈希方法降低复杂度。
Q3:自注意力可以替代RNN和CNN吗?
A:在序列建模任务中,自注意力已基本替代RNN,因为它能并行计算、捕捉长距离依赖,但CNN在某些局部特征提取场景(如图像)仍有一席之地,不过Transformer在CV领域也已崛起(ViT)。
自注意力的计算本质是一个 可微的、基于内容的寻址机制:通过Q与K的匹配度生成权重,再根据V提取内容,它的成功在于让每个位置能够动态地、全局地整合上下文信息,且计算高度并行化,理解这个流程(生成QKV → 缩放点积 → Softmax → 加权求和)是掌握Transformer一切变体的基石。
延伸阅读建议:
- 阅读《Attention Is All You Need》原始论文。
- 动手实现一个简单的自注意力层(如用PyTorch)。
- 研究多头注意力与位置编码的互动关系。
如果你正在搭建一个需要长文本理解的模型(如文档摘要、代码生成),请务必评估自注意力在序列长度超过2048时的显存消耗,并考虑采用滑动窗口或分段注意力策略,对于大多数中等长度任务(如句子级或段落级),标准自注意力仍然是最佳选择。