EECS498 · Transformer II · 10

Attention as Dynamic Information Routing

不要从公式背 Q/K/V。先要求 slept 真正取得 animal 的信息,再一步步推到 softmax(QKᵀ)V。

100–120 分钟WI22 A5Q · K · V · token routing

30-second recall

30 秒回忆

你写过 two-loop、batched two-loop、no-loop attention,再封装 SelfAttention 与 MultiHeadAttention。

  1. A[i,j] 到底是谁从谁读?
  2. Q/K 与 V 为什么不是同一职责?
  3. 哪些数在训练后固定,哪些权重随输入动态产生?

Before We Start

1. A[2,1] 很大,正确解释是?

2. 真正把位置 j 的内容带进输出 i 的运算是?

3. 模型训练完成后,面对两句不同输入,什么会变?

Arithmetic thread:同样的 routing 随后会让 subtract、两组符号与 digits 相互读取;本课先用 The animal slept 隔离机制,下一课再回到完整 arithmetic flow。

Step 1 · 先定义问题,不写公式

句子 The animal slept 查表并加入位置后,得到三个 vectors:

The      → x₀
animal   → x₁
slept    → x₂

若三个位置各自只通过 per-position MLP,x₂ 仍只来自 embedding(slept)+position(2);同一套 MLP 不会读取 x₁。它可以把“slept”这个特征变复杂,却没有一条 edge 把本句主语搬过来。

如果 token 之间完全不能交流?

slept 在 “The animal slept” 和 “The machine slept” 中经过同一 per-position function 会得到同样结果(忽略位置外其他输入),无法成为真正的 contextual representation。

Step 2 · 先接受“加权读取”

我们希望新的 slept 状态可以是其他位置所提供信息的组合:

new_slept
= 0.05 · information(The)
  + 0.80 · information(animal)
  + 0.15 · information(slept)

这一步尚未回答权重从哪里来。它先明确目标:位置 2 的输出数值应该真的含有位置 1 的信息。

Step 3 · 从需求推出 Q、K、V

  1. 当前位置想找什么?谓词位置可能需要“一个能充当主语的实体特征”——把这份寻址需求写成 Query。
  2. 候选凭什么被找到?每个位置暴露一份可匹配特征——写成 Key。
  3. 匹配后真正提供什么?被选中位置发送的 payload——写成 Value。
  4. 如何匹配所有候选?qᵢ·kⱼ 给 query i 与 key j 一个可微分的 compatibility score。
  5. 如何成为可读权重?对 row i 做 softmax,得到非负、和为 1 的读取比例。
  6. 如何搬运信息?用这些比例加权 values:yᵢ=ΣⱼAᵢⱼvⱼ。
Q = XWQ       [N,K,D]
K = XWK       [N,K,D]
V = XWV       [N,K,Dv]

S = QKᵀ/√D    [N,K,K]     matching scores
A = softmax(S) [N,K,K]     dynamic read addresses
Y = AV         [N,K,Dv]    retrieved information
Mental model

Q/K 决定本次输入中“去哪里读”;V 决定“读到后搬什么”。Attention 是输入相关、每次 forward 重新构造的 token-to-token 路由。

为什么同一个 X 要投影成三份?

Case A · Q=K=V=X 可以吗?

可以。这会形成一种合法 attention:原始 feature 同时承担匹配与传递。但它强迫“容易被找到的 feature”和“值得发送的 feature”完全相同。

Case B · Q=XWQ, K=XWK, V=XWV

独立 projections 让模型分别学习:如何提出查询、如何被匹配、实际发送什么。例如一个 token 可用“像名词”这一 feature 被匹配,却把数值、语义或位置信息的另一组合发出去。

Case C · 为什么 dot product,不是 Q+K?

加法本身只得到一条合成 vector,还需要另一个 function 才变成 scalar score。dot product 直接提供高维 feature matching,能以矩阵乘法并行计算所有 pairs,且可微分。它是高效 parameterization,不是数学宇宙中唯一可能的 attention;additive attention 也存在。

如果没有 V,直接把 A 当输出?

你只保留“从哪里读”的地址矩阵,却没有把源位置的 feature 内容搬到当前位置。A 可以用于分析路由,但不能替代新的 token representation。

Attention matrix · 每个元素都说清楚

对 K=3 的句子,一张可能的 attention matrix 是:

reader ↓ / source →   The   animal  slept
The                    .70    .20     .10
animal                 .10    .80     .10
slept                  .05    .80     .15

row i = 谁在读;column j = 从谁读。所以 A[2,1]=0.80 表示输出位置 slept 从 value 位置 animal 读取 80%。它不表示 animal 从 slept 读,也不证明两者 embedding 相同。

Inline check. 若 cross-attention A shape 是 [N,4,9],A[n,3,7] 是?

为什么“信息交换”不是比喻?

设 values 是二维 vectors:

V₀ = [1,0]   V₁ = [0,2]   V₂ = [1,1]
A₂ = [.05, .80, .15]

Y₂ = .05V₀ + .80V₁ + .15V₂
   = [.05,0] + [0,1.60] + [.15,.15]
   = [.20,1.75]

V₁ 的第二个分量以 0.80×2 真实进入 Y₂。这不是“模型仿佛知道 animal”;它是可在 tensor 中逐项核对的 value mixing。

重要 caveat · routing weight 不等于最终 reasoning explanation

Aᵢⱼ 确实控制这一 head、这一层的 value mixing;但大权重不等于该 token 是最终决策的唯一原因。residual 保留旧状态,多个 heads/layers 继续组合,MLP 改变 features,下游 logits 还依赖完整计算图。

Your Code · 从两层循环到 batched matrix multiply

Your code · 2023

win22/A5/transformers.py · scaled_dot_product_no_loop_batch()

View source →
scores = torch.bmm(query, key.transpose(1, 2))
scores /= math.sqrt(M)
scores = torch.masked_fill(scores, mask, -1e9)
weights_softmax = F.softmax(scores, dim=-1)
y = torch.bmm(weights_softmax, value)
query[N,Kq,D]
key.transpose(1,2)[N,D,Kv]
scores[N,Kq,Kv]
softmax(dim=-1)每个 reader 对所有 sources 归一化
value[N,Kv,Dv]
y[N,Kq,Dv]

这段代码不仅是“vectorization trick”。它把 two-loop 中每一个 (i,j) dot product 汇总成 batch matrix multiply。Notebook 中 loop 与 no-loop 的小 relative error,是在验证两种执行方式表达同一机制。

Deep Dive · 为什么除以 √D?

若 q/k 各分量近似零均值、单位方差,D 项乘积相加使 dot product variance 约随 D 增长。D 大时 logits 绝对值变大,softmax 迅速接近 one-hot,非最大位置 gradient 变小。除 √D 把 score 的典型尺度拉回较稳定范围。它不是为了让 row sum=1——那是 softmax 的工作。

Attention 与 MLP 各做哪种变化?

Attention · token mixing

让 position j 的 value 进入 position i。连接权重 A 随输入变化。

[N,K,M] → across K → [N,K,M]

MLP · feature transformation

对每个 position 独立应用同一 nonlinear function;主要在 M/hidden feature 轴上变换。

M → M_hidden → M, repeated over K

“token mixing vs channel transformation”是好用视角,不是说模块绝对只做一种语义工作。关键结构事实是:标准 position-wise MLP 没有跨 K 轴读取;attention 有。

对象训练后推理时是否随输入改变
WQ/WK/WV/WO固定 parameters否
Q/K/V activations本次 forward 产生是
scores / A本次 forward 产生是
MLP weights固定 parameters否

Multi-Head · 不只是“多个关系空间”

句子 The animal didn't cross the street because it was tired. 中,不同 heads 可能形成不同匹配:代词↔实体、动词↔主语、局部邻接、结构标记。这里是 conceptual intuition,不代表人为指定每个 head 的功能,也不保证训练后出现整洁的可解释分工。

M = H × Dh

per head Q,K,V      [N,K,Dh]
per head output     [N,K,Dh]
concat H heads      [N,K,H·Dh] = [N,K,M]
output projection   [N,K,M]

Your code · 2023

win22/A5/transformers.py · MultiHeadAttention

View source →
heads = [head(query, key, value, mask)
         for head in self.heads]
heads = torch.cat(heads, dim=-1)
output = self.linear_mult(heads)

每个 head 有独立 projections,concat 汇总 payload,最后 projection 让不同 heads 的 feature 重新混合。

End-of-Lesson Deep Checks

Q=[32,9,16]、K=[32,9,16]、V=[32,9,24],scores 与 output shape?

[32,9,9] 与 [32,9,24]。output feature width 来自 V,不来自 Q/K。

某个 query row 的 scores 全相同,输出是什么?

softmax 是均匀 1/K,输出是 values 的平均;本 row 没有内容选择性。

若固定同一 WQ/WK/WV,换一条输入,A 为什么会变?

X 变导致 Q/K 变,dot products 随之改变。dynamic 指 routing activations 动态,不是 parameters 每次改写。

Q/K 已经找到 animal,为什么不能输出 K?

K 是寻址 feature,不必包含希望传输的 payload;V 允许匹配空间与内容空间解耦。

Transfer Questions

  1. Q length=4,K/V length=9,attention matrix 与 output shape 各是什么?这更像 self 还是 cross attention?
  2. 若所有 heads 都产生完全相同的 A 和 V,增加 heads 还能带来独立 routing 吗?
  3. 若 A 接近 identity matrix,这一层跨 token 混合了多少信息?residual 又会造成什么差别?
核对第一题

A 是 [N,4,9],若 V width Dv,output 为 [N,4,Dv];不同长度通常更像 cross-attention。

闭卷解释

  1. 不看公式,解释为什么 Value 必须存在。
  2. 用一句不含“相关性”这个模糊词的话解释 A[i,j]。
  3. 为什么 Y=AV 证明了信息交换?
  4. 什么是 dynamic:参数还是 routing weights?
  5. Attention 与 position-wise MLP 在连接模式上有什么区别?

Then I implemented: QKᵀ → scale → mask → softmax → ×V.

Now I understand: 当前 position 用 Q 寻址所有 K,得到本次输入特有的读取分布 A,再用 A 搬运 V;Q/K 决定怎么找,V 决定真正拿走什么。

Connection · 同一机制为什么会出现三次?

Self-attention 规定 Q/K/V 来自同一组;cross-attention 允许 decoder queries 去读 encoder memory;causal mask 再限制哪些 sources 合法。下一课沿 arithmetic example 走完三条信息流。

Based on your implementation