跳到主要内容

Attention 注意力机制

内容

围绕 注意力机制

  1. 什么是、为什么需要、怎么理解 "注意力机制"。
  2. Transformer 中的 Attention 具体与怎样的。
  3. 注意力机制在结构和工程上的变体与优化。

通俗地理解:

Attention = 当前 token 根据上下文动态决定"看谁",再按权重汇总信息。

例如:

小明把书放进书包,因为它很重。

理解"它"时,人类会自然回看"书"和"书包",再根据"很重"判断它更可能指"书"。

模型也需要类似能力:处理某个 token 时,不只看自己或附近词,而是从上下文里读取相关信息。

1. 为什么需要注意力机制

语言不是一个只靠相邻词就能理解的序列。很多关系会跨越很长距离,也会随着上下文变化。

1.1 解决长距离依赖

看这句话:

那位昨天在会议上介绍新项目、并回答了很多问题的工程师,今天请假了。

"请假了"的主语是"工程师",但中间隔了很多词。如果模型只能强依赖相邻位置,就很难稳定抓住这种远距离关系。

Attention 的价值是:当前位置可以直接和上下文中的任意可见 token 建立联系。它不需要信息一步一步从相邻 token 传过来。

1.2 解决动态上下文问题

同一个词在不同句子里需要关注的对象不同。

张三把钥匙交给李四,因为他要出门。
张三把钥匙交给李四,因为他忘带钥匙了。

两句话里的“他”可能指向不同人。模型不能写死规则,只能根据当前上下文动态计算:哪些 token 更相关,应该从哪里读信息。

1.3 让每个 token 变成"带上下文的表示"

Embedding 只把 token 变成初始向量。这个初始向量本身还不知道句子里其他 token 的信息。

Attention 做的事是让 token 之间交换信息:

初始 token 向量
-> 读取上下文
-> 融合相关信息
-> 变成带上下文的 hidden state

所以 Transformer 里的 token 表示不是静态的。经过多层 Attention 后,“苹果”在“吃苹果”和“苹果公司发布芯片”里的内部表示会变得不同。


2. 什么是注意力机制

Attention 的核心不是“注意力”这个比喻,而是一个 加权汇总 操作。

2.1 最小定义

当模型处理当前 token 时,它会对上下文里的 token 计算一组权重:

当前 token关注对象权重
小明0.10
电脑0.75
桌子0.10
它自己0.05

然后按权重汇总这些 token 提供的信息:

新的“它”的表示
= 0.10 × 小明的信息
+ 0.75 × 电脑的信息
+ 0.10 × 桌子的信息
+ 0.05 × 它自己的信息

权重越高,说明当前 token 从那个位置读取的信息越多。

2.2 Attention 在 Transformer 里的作用

在 Transformer Block 里,Attention 主要负责 token 之间的信息交互;FFN / MLP 主要负责对每个 token 的表示做进一步非线性加工。

简化理解:

Attention:token 之间传递信息
FFN / MLP:每个 token 内部加工信息
LayerNorm + Residual:让深层网络稳定训练

所以 Attention 不是整个 Transformer,但它是 Transformer 能处理上下文关系的核心部件。

2.3 Attention 并非固定规则

Attention 权重不是人工写好的规则,也不是固定词典。它由模型参数和当前输入共同计算出来。

同一个 token 在不同上下文里的注意力分布会变化:

他不饿 -> 可能关注“把蛋糕给别人”
他忘带钥匙 -> 可能关注“钥匙”和“收钥匙的人”

这也是它比简单关键词匹配更强的地方。


3. 怎么理解注意力机制

理解 Attention,重点是三件事:Q/K/V、三步计算、矩阵形式。

3.1 Q、K、V 的直觉

可以用“检索系统”来理解:

组件直觉作用
Query(Q)我现在想找什么当前 token 用它去匹配上下文
Key(K)我有什么索引特征每个 token 用它表示“我能被怎样找到”
Value(V)我真正提供什么内容被注意力权重加权汇总的信息

注意力不是直接用 Q 去拿 K,而是:

Q 和 K 算相关性
相关性变成权重
根据权重去汇总 V

为什么 K 和 V 要分开?因为“怎么被检索到”和“真正提供什么内容”不是一回事。

例如一本书:

标题 / 标签 / 摘要:用来判断是否相关
正文内容:真正被读取的信息

对应到 Attention:

  • Key 更像索引,用来匹配。
  • Value 更像内容,用来汇总。

分开后,模型可以学习更灵活的关系:一个 token 用某种特征被找到,再用另一种信息影响当前 token。

3.2 Attention 的三步计算

标准 Attention 可以拆成三步。

第一步,计算相关性分数:

score = Q · K

例如当前 token 是“它”:

Key 对象分数
小明1.0
电脑4.0
桌子0.5
0.2

第二步,用 softmax 将相关性分数变成权重:

[1.0, 4.0, 0.5, 0.2]
-> softmax
-> [0.04, 0.86, 0.02, 0.08]

第三步,用权重加权汇总 Value:

output
= 0.04 × V_小明
+ 0.86 × V_电脑
+ 0.02 × V_桌子
+ 0.08 × V_它

最后得到的 output 就是当前 token 融合上下文后的新表示。

3.3 Attention 公式

标准 Scaled Dot-Product Attention (缩放点积注意力) 写作:

Attention(Q,K,V)=softmax(QKdk)V\operatorname{Attention}(Q, K, V) = \operatorname{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V

逐段看:

片段含义
QKQK^\top每个 Query 和每个 Key 算相似度
dk\sqrt{d_k}缩放因子,避免维度变大后分数过大
softmax把分数变成权重
乘以 VV按权重汇总内容

公式是把上面提到的三步计算过程写成了矩阵计算形式。

3.4 注意力矩阵

注意力矩阵来自上面公式里的这一段:

softmax(QKdk)\operatorname{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)

也就是三步计算中的第二步:先用 QKQK^\top 算出相关性分数矩阵,再对每一行做 softmax,得到注意力权重矩阵。

假设有 3 个 token:

我 / 喜欢 / 苹果

先算出来的分数矩阵可能是:

当前 token \ 被关注 token喜欢苹果
3.02.31.2
喜欢1.12.01.5
苹果0.82.12.4

对每一行做 softmax 后,得到 Attention 权重矩阵:

当前 token \ 被关注 token喜欢苹果
0.60.30.1
喜欢0.20.50.3
苹果0.10.40.5

按行看:

  • 每一行表示一个当前 token 的注意力分布。
  • 每一列表示它从某个 token 读取多少信息。
  • 每行权重通常经过 softmax,和为 1。

所以注意力矩阵不是最终答案,而是“用多少比例读取每个 Value”的权重表。它还要继续乘以 VV,才会得到这一层 attention 的输出。

3.5 完整示例

下面用一个极简的二维向量例子,把注意力计算的完整流程走一遍。真实模型里的向量维度可能是几千维,这里只用 2 维方便手算。

假设有两个 token:

我 / 苹果

它们进入某一层 attention 后,已经得到各自的 Q、K、V:

tokenQKV
[1, 0][1, 0][2, 0]
苹果[1, 1][0, 1][0, 3]

现在只看“苹果”这个当前 token 怎么更新自己的表示。

第一步,用"苹果"的 Query 去匹配所有 token 的 Key:

Q_苹果 = [1, 1]

score(苹果 -> 我) = [1, 1] · [1, 0] = 1
score(苹果 -> 苹果) = [1, 1] · [0, 1] = 1

这里两个分数一样,表示"苹果"对"我"和"苹果"自己的匹配程度相同。

第二步,对分数做 softmax,得到权重:

softmax([1, 1]) = [0.5, 0.5]

这就是"苹果"这一行的注意力权重:

当前 token关注"我"关注"苹果"
苹果0.50.5

第三步,用权重汇总 Value:

output_苹果
= 0.5 × V_我 + 0.5 × V_苹果
= 0.5 × [2, 0] + 0.5 × [0, 3]
= [1, 0] + [0, 1.5]
= [1, 1.5]

这个 [1, 1.5] 就是"苹果"经过这一层、这个 head 的 attention 后得到的新向量。它不再只包含"苹果"自己的信息,也混入了从"我"那里读取到的信息。

如果把两个 token 都一起算,矩阵形式就是:

QK^T -> 分数矩阵
softmax(分数矩阵) -> 注意力权重矩阵
注意力权重矩阵 × V -> 每个 token 的新向量

4. Transformer 中的注意力计算

前面的例子直接给出了 Q、K、V。

实际 Transformer 里,Q、K、V 不是凭空来的,而是由当前层的 hidden states 经过投影矩阵计算出来的。

假设输入到某一层 attention 的 hidden states 是:

X: [seq_len, hidden_size]

其中:

  • seq_len 是当前序列长度。
  • hidden_size 是每个 token 的向量维度。
  • X 的每一行就是一个 token 在当前层开始时的表示。

4.1 参数和中间值

在进行下面的内容之前,首先我们应该区分哪些是模型可学习的、用于训练的参数,哪些只是一次前向计算中临时算出来的中间值。

参数是模型文件里保存的权重,会在训练中被更新,推理时固定使用。

名称是否可学习说明
Token embedding table/matrix把 token id 映射成初始向量的查表矩阵
W_Q / q_proj.weight把 hidden state 投影成 Query
W_K / k_proj.weight把 hidden state 投影成 Key
W_V / v_proj.weight把 hidden state 投影成 Value
W_O / o_proj.weight把多个 head 的输出混合回 hidden size
FFN / MLP 权重Attention 后继续加工每个 token 的表示
LayerNorm 参数通常是缩放、平移 hidden state 的参数

中间值不是模型长期保存的知识,而是每次输入经过模型时临时计算出来的激活。

名称是否可学习说明
token idtokenizer 产生的离散编号
token embedding 向量用 token id 从 embedding table 查出来的结果
hidden state X某一层开始时,每个 token 当前的向量表示
Q / K / VX 经过 q_proj/k_proj/v_proj 后算出来的中间结果
attention scoreQK/dQK^\top / \sqrt{d} 得到的相关性分数
attention weightscore 经过 mask 和 softmax 后得到的权重
attention outputattention weight 乘以 V 后得到的输出

所以更准确地说:

可学习的是

  • Embedding 层中的 embedding 矩阵
  • Attention 层的一系列投影矩阵,如q_projk_projv_projo_proj
  • FFN / MLP 层的权重
  • Norm 层的参数

而 Q/K/V 矩阵、hidden state、注意力分数与权重是用这些参数算出来的中间值。

4.2 q_proj、k_proj、v_proj

Transformer 会先用 3 组可学习的线性投影矩阵 W_QW_KW_VX 分别变成 Q、K、V

Q=XWQQ = XW_Q K=XWKK = XW_K V=XWVV = XW_V

在代码或模型结构里,这三组矩阵通常对应:

模块名作用
q_proj生成 Query,表示当前 token 想找什么
k_proj生成 Key,表示每个 token 如何被匹配
v_proj生成 Value,表示每个 token 真正提供什么内容

如果暂时不考虑多头和 bias,形状可以简化理解为:

X:   [seq_len, hidden_size]
W_Q: [hidden_size, hidden_size] -> Q: [seq_len, hidden_size]
W_K: [hidden_size, hidden_size] -> K: [seq_len, hidden_size]
W_V: [hidden_size, hidden_size] -> V: [seq_len, hidden_size]

所以 Q/K/V 本质上是同一批 token 表示 X 的三种不同投影结果。

4.3 多头与 reshape

实际 LLM 通常使用 Multi-Head Attention。也就是说,Q/K/V 生成后,还会被拆成多个 head。

例如:

hidden_size = 4096
num_attention_heads = 32
head_dim = 128

此时 Q 会从:

Q: [seq_len, hidden_size]

reshape 成:

Q: [num_heads, seq_len, head_dim]

K 和 V 也会做类似处理。每个 head 会独立执行一次:

headi=softmax(QiKidhead)Vi\operatorname{head}_i = \operatorname{softmax}\left(\frac{Q_iK_i^\top}{\sqrt{d_\text{head}}}\right)V_i

这里的 QiQ_iKiK_iViV_i 表示第 ii 个 head 对应的那一份 Q/K/V。

4.4 attention mask

在 Causal Attention 中,mask 会加在 softmax 之前,也就是加在 attention score 上。

简化写法:

scores=QKdhead+mask\operatorname{scores} = \frac{QK^\top}{\sqrt{d_\text{head}}} + \operatorname{mask} weights=softmax(scores)\operatorname{weights} = \operatorname{softmax}(\operatorname{scores})

未来位置会被 mask 成一个极小值,softmax 后权重接近 0。这样模型就不能从未来 token 读取 Value。

4.5 o_proj

每个 head 都会输出一份结果:

head_1, head_2, ..., head_n

这些 head 的输出会先拼接:

concat(head_1, head_2, ..., head_n)

然后经过 W_O(或者叫 o_proj ):

O=Concat(head1,...,headn)WOO = \operatorname{Concat}(\operatorname{head}_1, ..., \operatorname{head}_n)W_O

W_O 的作用是把多个 head 的信息重新混合,并投影回模型的 hidden_size,这样后续的残差连接、LayerNorm 和 FFN 才能继续处理。

4.6 完整流程

总结一下 Transformer 中 Attention 机制的完整流程:

X
- (q_proj / k_proj / v_proj 投影) -> Q / K / V
- (reshape) -> 多个 head
- 每个 head
- (QK^T,加 mask) -> 注意力分数
- (softmax) -> 注意力权重
- (权重 × V) -> hidden state
- (concat 合并多个 head) -> hidden state
- (o_proj 投影) -> attention output

所以在真实 Transformer 里,Attention 不只是一个公式,而是一组可学习投影矩阵加上矩阵乘法、mask、softmax、head concat 和输出投影的完整计算模块。


5. Self、Causal、Multi-Head 等概念

从"信息从哪里来、能看哪里、分几个头看、K/V 怎么共享"来区分这几个概念。

5.1 Self-Attention 自注意力

Self-Attention 指 Query、Key、Value 都来自同一个序列。

例如:

猫坐在垫子上。

句子内部的 token 互相读取信息:

当前 token可能关注
坐、垫子
猫、垫子
垫子坐、上
垫子

大语言模型里的核心注意力通常就是 Self-Attention:每个 token 从同一段上下文中读取信息。

5.2 Cross-Attention 交叉注意力

Cross-Attention 指 Query 来自一个序列,Key / Value 来自另一个序列。

典型例子是 Encoder-Decoder 翻译模型:

英文:The cat sat on the mat.
中文:猫坐在垫子上。

生成中文“猫”时,目标序列里的 Query 会去源序列里关注 cat;生成“垫子”时,会更关注 mat

现代聊天 LLM 多是 Decoder-only,主要使用的是 Causal Self-Attention。但 Cross-Attention 这个概念仍然有助于我们理解 注意力就是对齐并读取相关信息

5.3 Causal Attention 因果注意力

自回归模型(如GPT、LLaMA、Qwen 这类生成模型)的任务是:根据过去预测下一个 token。

训练句子:

我 喜欢 苹果

预测"喜欢"时,模型不能看到"苹果";预测"苹果"时,才能看到"我"和"喜欢"。

所以需要 causal mask 来掩盖到不应当看到的部分:

当前 token \ 可见 token喜欢苹果
可见不可见不可见
喜欢可见可见不可见
苹果可见可见可见

Causal Attention 本质上仍然是 Self-Attention,只是加了"只能看过去和当前"的可见性限制。

5.4 Bidirectional Attention 双向注意力

与 Causal Attention 相对的概念是 Bidirectional Attention:

类型可见范围代表模型适合任务
Bidirectional Attention可以看左右上下文BERT理解、分类、Embedding
Causal Attention只能看当前位置之前GPT、LLaMA、Qwen生成、对话

例如:

我把苹果放在桌上,因为它很甜。

BERT 处理“它”时,可以同时看前后文。GPT 在生成到"它"时,只能看已经出现的前文。

5.5 Multi-Head Attention 多头注意力

Single-Head Attention 只能在一个表示空间里计算关系。Multi-Head Attention 会让模型并行使用多个 head,从不同角度读取上下文。

这里的 head 可以理解成“一组独立的注意力计算通道”。

更具体一点,在 Multi-Head Attention 中:

  • 模型的 hidden state 会先被投影成 Q、K、V。
  • Q、K、V 会按 num_attention_heads 切成多份,每一份就是一个 attention head。
  • 每个 head 都在自己的低维子空间里单独计算一套 attention 分数、权重和输出。
  • 多个 head 的输出 concat 起来,再经过 o_proj 混合回原来的 hidden size。

例如一个简化配置:

hidden_size = 4096
num_attention_heads = 32
head_dim = 4096 / 32 = 128

这里:一个 token 的 hidden state 被分到 32 个 head 中,每个 head 处理 128 维表示。每个 head 都没有使用完整数据,而是同一层 attention 里的一个子通道。

例如:

小王把蛋糕给了小李,因为他不饿。

不同 head 可能关注不同关系:

Head可能关注
Head 1“他”指代谁
Head 2“给了”的动作关系
Head 3“不饿”和“给蛋糕”的因果关系
Head 4名词之间的位置关系

简化流程:

输入 hidden states
- (q_proj / k_proj / v_proj) -> Q、K、V
-> reshape 成多个 head
-> 每个 head 独立计算 attention
-> concat 多个 head 的输出
-> o_proj 混合
-> 输出

多头的价值不是简单“多算几遍”,而是让模型可以同时学习多种关系。

5.6 MHA 变体

自回归模型在生成时,模型会一个 token 一个 token 往外生成。为了避免每一步都重新计算所有历史 token 的 Key 和 Value,推理框架会把历史 token 的 K/V 缓存起来,这个缓存就叫 KV Cache

KV Cache 越大,推理显存压力越高。它的大小和 K/V head 数量、K/V 保存形式强相关,所以很多现代 LLM 会调整 K/V head 的数量,或者进一步压缩 K/V 的缓存表示。

下面是几类常见的 MHA 变体:

缩写全名中文名K/V head 关系特点
MHAMulti-Head Attention多头注意力每个 Query head 都有自己的 K/V head表达能力强,但 KV Cache 最大
MQAMulti-Query Attention多查询注意力多个 Query head 共享一组 K/V headKV Cache 小,推理省显存
GQAGrouped-Query Attention分组查询注意力一组 Query head 共享一组 K/V head在效果和推理成本之间折中
MLAMulti-head Latent Attention多头潜在注意力不直接缓存完整 K/V,而是缓存压缩后的 latent 表示,再还原或投影出 K/V进一步降低 KV Cache 压力,常见于追求长上下文和高吞吐的模型设计

简化理解:

MHA:Q head 多,K/V head 也多
MQA:Q head 多,K/V head 很少
GQA:Q head 分组,每组共享 K/V
MLA:不只减少 K/V head,而是压缩 K/V 的缓存表示

这也是看模型配置时要关注 num_attention_headsnum_key_value_heads 以及是否使用 MLA 这类 latent KV 设计的原因。它们都会影响 KV Cache 显存。

5.7 小结

不同的 Attention 的信息来源以及 Mask 类型应用在不同架构上:

架构类型Self / CrossMask典型模型主要用途
Encoder-OnlySelfBidirectionalBERT 及变体理解类: 分类、NER、embedding 等
Decoder-OnlySelfCausalGPT/ Claude/ LLaMA/ Qwen生成类: 对话、写作、代码生成等
Encoder-DecoderSelf Encoder + Self & Cross DecoderNon-mask Encoder + Causal DecoderT5 / BARTSeq2Seq 类: 翻译、摘要、生成等
  • 工程上为了压缩 MHA 的 KV Cache,发展出了 MHA 的各种变体如 MQA、GQA、MLA 等。
  • 标准 Transformer 架构是 Encoder-Decoder 类型,使用的注意力是:
    • Encoder:Self Bidirectional Multi-Head Attention
    • Decoder:Self Causal Multi-Head Attention + Cross Multi-Head Attention (Non-causal)

6. 工程上的注意力优化

前面关注的是 Attention 的基本机制、常见结构及变体。

实际 LLM 部署时还会遇到更工程化的优化,比如 FlashAttention、PagedAttention、Sliding Window Attention、Sparse Attention 等技术。

这些方法不一定改变"Q 找 K、得到权重、加权汇总 V"这个核心逻辑,但会改变计算方式、内存组织方式或可见范围,从而提升速度、降低显存或支持更长上下文。

6.1 FlashAttention

FlashAttention 主要优化的是 attention 的计算和显存读写。

标准 attention 如果直接生成完整的注意力矩阵,会产生很大的中间结果。FlashAttention 的思路是分块计算 attention,减少中间矩阵在显存中的读写,让 GPU 更高效地完成同样的数学计算。

简化理解:

普通 attention:更容易产生大的中间注意力矩阵
FlashAttention:分块计算,减少显存读写,提高计算效率

它通常不改变模型语义,主要是让 attention 算得更快、更省显存。

6.2 PagedAttention

PagedAttention 主要优化的是 KV Cache 的管理方式。

自回归推理中,每个请求都要保存历史 token 的 K/V。如果直接为每个请求预留连续大块显存,很容易浪费或碎片化。PagedAttention 借鉴操作系统分页的思路,把 KV Cache 切成小块按需分配。

简化理解:

普通 KV Cache 管理:容易预留过多或产生碎片
PagedAttention:把 KV Cache 分页,按需分配和调度

vLLM 的高吞吐能力很大程度上就来自这类 KV Cache 分页管理和调度策略。

6.3 Sliding Window Attention

Sliding Window Attention 会限制每个 token 只关注附近窗口内的 token,而不是关注完整上下文。

例如窗口大小是 4096,那么当前位置可能只看最近 4096 个 token。这样可以降低长上下文下的 attention 计算和 KV Cache 压力。

代价也很明显:窗口外的信息不能被当前 token 直接读取,需要模型结构或系统策略额外处理远距离信息。

6.4 Sparse Attention

Sparse Attention 不让每个 token 都关注所有 token,而是只关注一部分位置。

常见思路包括:

  • 局部关注:只看附近 token。
  • 全局 token:少数特殊 token 可以被很多位置关注。
  • 间隔关注:按固定间隔看部分远处 token。

它的目标是减少完整 n×nn \times n attention 带来的成本。代价是实现更复杂,而且不同稀疏模式会影响模型能读取哪些信息。

6.5 与 MHA 及其变体的关系

这些概念容易混在一起,可以这样分:

类型主要解决什么
MHA / MQA / GQA / MLAK/V head 数量怎么设计,存储是完整存、共享还是压缩,影响表达能力和 KV Cache 大小
FlashAttentionattention 计算怎么更快、更省显存读写
PagedAttentionKV Cache 怎么分配和管理
Sliding Window / Sparse Attentiontoken 可见范围怎么限制,降低长上下文成本

所以 MHA、MQA、GQA 更像模型结构设计;FlashAttention、PagedAttention 等更像推理和系统实现优化。


7. 常见问题

7.1 Attention 和 KV Cache 是什么关系

KV Cache 是 Attention 在自回归推理中的缓存机制。

生成模型推理时是一个个 token 往外生成。如果每生成一个新 token,都重新计算所有历史 token 的 Key 和 Value,会出现重复计算导致浪费的情况。

KV Cache 的做法是:

历史 token 的 K/V 已经算过 -> 存起来
新 token 只计算当前 Q/K/V
当前-Q 和 历史-K 计算注意力权重
再用权重汇总 历史-V
把新 token 的 K/V 追加进 cache

所以 KV Cache 本质上是一个典型的 用空间换时间 策略:多占用一部分显存来保存历史 K/V,换取 decode 阶段少做大量重复计算。

而二者的关系可以概括为:

  • Attention 是 算法架构层 的结构机制:用 Q/K/V 计算权重并汇总信息。
  • KV Cache 是 模型推理层 的优化机制:缓存历史 K/V,用显存占用换取更少的重复计算。
  • KV Cache 不会改变 Attention 的数学含义,只是让 decode 阶段更高效。

7.2 为什么 KV Cache 会占用显存

KV Cache 保存的是每一层、每个历史 token 的 Key 和 Value。

简化看:

KV Cache 大小
≈ 层数 × token 数 × KV head 数 × head_dim × 2 × 每元素字节数

这里的 2 表示 Key 和 Value 各一份。

所以 KV Cache 会随着这些因素变大:

因素影响备注
输入/上下文 越长每个请求缓存的 token 越多
输出越长生成过程中 cache 继续增长
并发越高同时维护多份请求的 cache
KV head 越多每个 token 要存更多 K/VMQA,GQA 即是针对这里进行优化
精度越高每个元素占用字节更多

这就是为什么长上下文和高并发服务里,显存瓶颈经常不是模型权重,而是 KV Cache。

更完整的工程解释可以看:KV Cache

7.3 Attention 为什么让长上下文变贵

Self-Attention 需要计算 token 之间的关系。

如果序列长度是 nn,完整注意力矩阵大致是 n×nn \times n

序列长度注意力关系数量
1,0001,000,000
10,000100,000,000
100,00010,000,000,000

实际系统会用 FlashAttention、PagedAttention、KV Cache、滑动窗口、稀疏注意力等优化,但基本事实仍然存在:上下文越长,注意力相关的计算、访存和缓存压力越高。

7.4 Attention 和位置编码是什么关系

Self-Attention 本身只看 token 之间的相似度,不天然知道顺序。

如果没有位置信息,模型很难区分:

小明打了小王
小王打了小明

所以 Transformer 需要位置编码或类似机制。现代 Decoder-only LLM 中常见 RoPE,它会在 Attention 计算中对 Query 和 Key 注入位置信息。

更完整解释可以看:位置编码

7.5 Attention 权重能解释模型为什么这么回答吗

只能作为参考,不能等同于完整解释。

原因是:

  • 模型有很多层,每层都有不同 attention。
  • 每层有多个 head。
  • FFN / MLP 会继续加工信息。
  • 残差连接会混合不同路径的信息。

模型最终输出由整个网络共同决定。

所以更准确的说法是:

Attention 权重可以帮助观察某层某头读了哪里,但不能完整解释模型为什么输出某个答案。

8. 常见误区

注意力就是找关键词

不只是。Attention 可以关注关键词,也可以关注语法、指代、位置、格式、因果关系、代码变量、函数定义等更抽象的关系。

权重最高的 token 一定最重要

不一定。单层单头的注意力权重只是模型内部很多路径中的一部分。最终输出还会经过多层、多头、FFN、残差连接和 LM Head。

注意力越集中越好

不一定。有些任务需要集中关注一个证据,有些任务需要综合多个信息。过度集中可能导致模型忽略必要上下文。

长上下文就是无限记忆

不是。长上下文只是允许模型看到更多 token,不保证模型能稳定利用所有信息。上下文越长,也可能带来注意力干扰、成本上升和 KV Cache 压力。

KV Cache 会让模型“记住用户”

不会。KV Cache 是一次推理请求内部的临时缓存,保存的是当前上下文中 token 的 K/V。请求结束后通常会释放。它不是长期记忆,也不是训练参数更新。

Multi-Head 就是多个模型投票

不是。多个 head 是同一层内部的多个表示子空间,最后会 concat 并通过 o_proj 混合。它不是多个独立模型,也不是显式投票机制。


总结

Attention 的核心可以压缩成一句话:Q 结合 K,得到权重后加权汇总 V

再展开一点:

  • Attention 解决的是 token 如何从上下文中动态读取相关信息。
    • Self-Attention 是同一序列内部 token 互相读取信息。
    • Causal Attention 是加了 mask 来限制的自回归注意力。
    • Multi-Head Attention 让模型从多个表示角度并行读取上下文。
  • KV Cache 是 Attention 在推理阶段的缓存优化,核心是复用历史 Key 和 Value。
    • MQA / GQA 通过减少或共享 K/V head,MLA 通过压缩表示来降低 KV Cache 成本。
    • 推理部署中会使用 FlashAttention、PagedAttention、Sliding Window Attention 等技术进行 KV Cache 方面的工程优化。

todo: 其它 Attention 算法

大模型厂商在模型研发过程中,发展出各种各样注意力算法来提高模型表现或者效率:

  • FLA
  • Local Attention
  • Linformer Attention
  • Mamba