Attention:让每个位置选择上下文
直觉版:一边生成,一边”看重点”
Section titled “直觉版:一边生成,一边”看重点””注意力机制解决的问题是:当模型处理一个 token 时,应该重点参考哪些上下文?翻译”it”时可能要看前面的名词,回答问题时要看相关证据。注意力权重就是一组会随输入变化的分数,表示当前 token 对其他 token 的依赖强弱。
行表示正在更新的 token,列表示它关注的上下文 token;颜色越深,权重越高。
| query \ key | 大 | 语言 | 模型 | 关注 | 上下文 | 生成 | 答案 |
|---|---|---|---|---|---|---|---|
| 大 | 1.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 |
| 语言 | 0.25 | 0.75 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 |
| 模型 | 0.12 | 0.38 | 0.50 | 0.00 | 0.00 | 0.00 | 0.00 |
| 关注 | 0.08 | 0.24 | 0.28 | 0.40 | 0.00 | 0.00 | 0.00 |
| 上下文 | 0.05 | 0.18 | 0.22 | 0.25 | 0.30 | 0.00 | 0.00 |
| 生成 | 0.04 | 0.12 | 0.20 | 0.18 | 0.26 | 0.20 | 0.00 |
| 答案 | 0.03 | 0.10 | 0.22 | 0.12 | 0.23 | 0.18 | 0.12 |
注意力机制核心流程图:
graph TD A[输入序列 X] --> B[投影层: W_Q, W_K, W_V] B --> C[Query矩阵 Q] B --> D[Key矩阵 K] B --> E[Value矩阵 V] C --> F[计算相似度: QK^T/√d_k] D --> F F --> G[Softmax归一化] G --> H[注意力权重 A] H --> I[加权求和: AV] E --> I I --> J[输出: 上下文表示]Bahdanau 注意力先在序列到序列模型中证明了”动态查找上下文”的价值;Transformer 进一步把自注意力变成核心计算单元,让所有位置可以并行建立依赖关系。
工程版:Q、K、V 与复杂度
Section titled “工程版:Q、K、V 与复杂度”实现上,每个 token 会投影成 Query、Key、Value。Query 和 Key 点积得到相似度,经过 softmax 变成权重,再对 Value 加权求和。多头注意力把这个过程复制多份,让不同头学习语法、指代、位置或任务相关模式。
自注意力的主要代价是序列长度平方级:长度翻倍,注意力矩阵大约变为四倍。因此推理系统会使用 KV cache 复用历史 Key/Value;长上下文模型会结合稀疏注意力、分块、滑窗或更高效 kernel。理解这个瓶颈有助于解释为什么上下文窗口很贵。
示例代码:简化的自注意力实现
Section titled “示例代码:简化的自注意力实现”import numpy as np
def softmax(x):
"""数值稳定的 softmax"""
exp_x = np.exp(x - np.max(x, axis=-1, keepdims=True))
return exp_x / np.sum(exp_x, axis=-1, keepdims=True)
def scaled_dot_product_attention(Q, K, V):
"""
计算缩放点积注意力
Q, K, V: [seq_len, d_k]
返回: [seq_len, d_k]
"""
d_k = Q.shape[-1]
# 计算注意力分数
scores = np.matmul(Q, K.T) / np.sqrt(d_k)
# 应用 softmax 得到注意力权重
attention_weights = softmax(scores)
# 对 V 加权求和
output = np.matmul(attention_weights, V)
return output, attention_weights
# 示例
seq_len, d_k = 4, 8
Q = np.random.randn(seq_len, d_k)
K = np.random.randn(seq_len, d_k)
V = np.random.randn(seq_len, d_k)
output, weights = scaled_dot_product_attention(Q, K, V)
print("注意力权重形状:", weights.shape) # (4, 4)
print("输出形状:", output.shape) # (4, 8)
print("每行权重和:", weights.sum(axis=1)) # 每行和为 1.0研究版:注意力模式的可解释性
Section titled “研究版:注意力模式的可解释性”研究上,注意力权重本身能否解释模型的决策?早期工作认为注意力提供了”模型在看哪里”的透明信号,但后续研究表明,注意力分布与特征重要性并非简单对应——模型可以在高注意力权重区域保持输出不变,反之亦然。
更深的研究方向包括:多头注意力中不同头的专业化分工(语法头、位置头、 rare token 头);注意力模式的动态演化(深层 vs 浅层);以及注意力与梯度-based 归因方法之间的关系。理解这些有助于设计更稀疏、更高效、更可解释的注意力变体。
🔬 开放研究问题
该领域的关键问题与研究方向:
- 注意力权重本身能否可靠解释模型决策?注意力分布与特征重要性的关系如何准确刻画?
- 多头注意力中不同头的专业化分工如何量化?是否存在通用的"语法头"、"位置头"模式?
- 如何设计更稀疏、更高效、更可解释的注意力变体以降低计算成本?
本文引用论文
- Attention Is All You Need
Transformer 架构的奠基之作。作者完全用注意力机制替代了 RNN/CNN,提出多头自注意力与位置编码, 在机器翻译任务上大幅超越此前所有模型。今天所有主流 LLM 的底层架构都源于此论文。
- Neural Machine Translation by Jointly Learning to Align and Translate
注意力机制的开山之作(在 Transformer 之前)。作者发现 Seq2Seq 的固定长度瓶颈向量限制了翻译 质量,提出让解码器在生成每个词时都能"回顾"编码器的所有隐状态,动态分配注意力权重。 这个思想直接演化为 Transformer 的自注意力。
- Effective Approaches to Attention-based Neural Machine Translation
系统化地比较 global vs local attention、不同打分函数(dot / general / concat),是后人讲 "attention score 是怎么算的" 时最常引用的工程化版本。
- Sequence to Sequence Learning with Neural Networks
Seq2Seq 架构(编码器-解码器)的奠基之作。通过两个 LSTM 的"压缩-生成"结构,首次让神经网络 能够进行变长序列到变长序列的转换,在机器翻译上取得突破性进展,也直接启发了后来 Transformer 的编解码器设计。
- Neural Machine Translation in Linear Time
用扩张卷积做 seq2seq,把序列建模从"必须 RNN 顺序计算"中解放出来;和同期 ConvS2S 一起是 Transformer 之前"并行序列建模"的最强尝试。