Week 7
Week 7 - Attention:让当前位置按需读取左侧上下文
Key question当“喜欢”既出现在 [我,喜欢] 又出现在 [猫,喜欢] 时,模型如何从输入向量计算 Q、K、V,给可见位置打分,并产生不同的上下文表示与下一词 Logits?
Learning objectives
- 用同一个可复现数值例子完整计算 X → Q/K/V → Raw Scores → Scale → Causal Mask → Attention Weights → Weighted Values。
- 解释 Attention 如何打分、分数如何通过训练学会,以及 Attention Softmax 与 Vocabulary Softmax 的区别。
- 准确读取 [B,T,C]、[B,T,d_head]、[B,T,T] 和 [B,n_head,T,T] 中每个轴的语义。
- 实现并审计可复现的单 Head、可复用的 Causal Attention Head 与 Multi-Head Attention。
- 说明 Attention Output 如何继续影响 Logits、Attention 的边界、T² 成本,以及它为什么需要 Week 8 的 Transformer Block。
110 min estimated reading time
上一周的 Bigram 只用当前 token 查一行分数。现在保留“我 喜欢”和“猫 喜欢”两条前缀,想让最后的“喜欢”读到不同的左侧信息。Token 编号不变;为算术清楚,本周显式使用更简单的四维输入和固定投影。
Scroll horizontally to view all columns.
| 学习单元 | 本次解决的问题 |
|---|---|
| 一:读取什么 | 平均和手工加权的限制;再说明 query 是本次匹配需求、key 用来打分、value 是实际取回内容。 |
| 二:逐步手算 | Q/K/V → 点积 → 缩放 → 每行权重 → 加权值;每个数都追溯到同一组输入。 |
| 三:为什么不能偷看 | 对应输入和下一词目标,说明 mask 的方向、负无穷和位置轴。 |
| 四:怎样参与学习 | 从末位置输出接词表评分和 CE;观察一个 Wq 参数的梯度,再理解多头。 |
运行 python week07_attention.py;需看到 A/B 末位置权重不同,并解释两种 Softmax 分别沿“位置”还是“词表”归一化。多头并行读信息,多个 block 串行改造表示,不要混为一谈。
建议阅读、手算、改代码交替进行,每个单元可拆成几次完成。章节编号保留用于旧链接和回查;按页面从上到下的新顺序学习,不需要按旧编号来回跳转。
Week 7 核心目标:让相同 Token 读取不同前缀
这一周保留词语“我、猫、喜欢”及 [B,T,C] 的含义,但为了让 Q/K/V 每项都能手算,改用本章指定的简单浮点 X 和固定投影。它不是把 Week 6 训练到某一步的 embedding 原样搬来。Week 8 会另给 token+position 的演示值;Weeks 10–12 则使用同一套可学习 MiniGPT。
本周只围绕两个 Prompt 展开:Prompt A=[我,喜欢],Prompt B=[猫,喜欢]。两者最后一个 Token 相同,但合理的模型应该能让最后的“喜欢”读取不同的左侧信息。Attention 增加的就是这条动态信息通路。
Scroll horizontally to view all columns.
| Batch / Position | Tensor Slot | Token | 语义 |
|---|---|---|---|
| b=0, t=0 | x[0,0,:] | 我 | Prompt A 的第一个 Token |
| b=0, t=1 | x[0,1,:] | 喜欢 | Prompt A 的第二个 Token |
| b=1, t=0 | x[1,0,:] | 猫 | Prompt B 的第一个 Token |
| b=1, t=1 | x[1,1,:] | 喜欢 | Prompt B 的第二个 Token |
- 输入表示 X [B,T,C] = [2,2,4]
- 每个 Head 投影出 Q / K / V [2,2,2]
- QKᵀ 产生 Raw Scores [B,T,T] = [2,2,2]
- 除以 √d_k,应用 Causal Mask
- 沿 Key Position Axis 做 Softmax 得 Weights [2,2,2]
- Weights @ Values 得 Head Output [2,2,2]
- 两个 Heads Concat + W_O 恢复 [2,2,4]
- 后续 Transformer 与 LM Head 产生 Logits [2,2,V_vocab]
Knowledge check
为什么两个最后都是“喜欢”的 Prompt 在 Bigram 中相同,在 Attention 中却可能不同?
1. 从输入 X 到最简单的 Context Aggregation
Attention 不直接接收 Token ID。Token ID 只是用于查表的整数;进入 Attention 的 X 是 Embedding 或上一层输出的向量。本课使用简化表示,使每一步矩阵乘法都能手算。真实模型中的向量通常是训练得到的稠密小数。
一个简单基线是对当前位置允许读取的前缀做均匀平均。最终位置 t=1 的固定读取比例是 [0.5,0.5];它能让 A 与 B 因输入不同而产生不同平均值,但不能根据当前 Query 动态改变读取比例。
Scroll horizontally to view all columns.
| 机制 | 最终位置对 j=0 / j=1 的读取 | 能否按 Query 动态选择 |
|---|---|---|
| Causal Uniform Mean | [0.5, 0.5] | 不能,比例固定 |
| Prompt A 的教学 Attention Head | [0.599, 0.401] | 可以 |
| Prompt B 的教学 Attention Head | [0.426, 0.574] | 可以 |
Knowledge check
Uniform Mean 与 Attention 的核心区别是什么?
2. 用搜索系统理解 Query、Key、Value
Scroll horizontally to view all columns.
| Attention 必须回答的问题 | 名称 | 在最终“喜欢”的例子中 |
|---|---|---|
| 当前位置正在寻找什么? | Query (Q) | “喜欢”形成当前读取请求 |
| 每个位置凭什么被找到? | Key (K) | “我”或“猫”提供可匹配线索 |
| 找到位置后带回什么? | Value (V) | 对应位置的内容参与新表示 |
可以把 Query 想成搜索请求、Key 想成索引线索、Value 想成记录正文。这个比喻只解释职责;模型中没有真正的字符串搜索,也没有人为指定“某一维等于主语”。
Knowledge check
Attention Weights 形成以后,Q、K、V 中哪一种会被加权相加?
3. 为什么需要三份表示
一个位置可以用 Key 宣传“怎样找到我”,用 Value 保存“找到我后应带走什么”,并在自己的读取轮次用 Query 表达“我现在需要什么”。三者来自同一个 x_t,但使用不同参数。
Knowledge check
为什么 Key 不需要保存 Value 中的全部信息?
4. 从 XW 得到 Q、K、V,再计算 Raw Scores
下面的参数专门为教学设计,目的是让所有数字可以手算。真实模型通常从随机参数开始,通过训练得到稠密小数。这里的 W 仍是全局共享矩阵,并不是为每个 Token 单独写一套规则。
例如 x_喜欢=[0,1,0,0],所以它乘任一 W 时会取出对应矩阵的第二行:q_喜欢=[1,1],k_喜欢=[0.2√2,0.2√2]≈[0.283,0.283],v_喜欢=[0,1]。
最终“喜欢”的 Query 是 [1,1]。它与“我”的 Key 做 Dot Product:1×1.131+1×0=1.131;与“喜欢”自己的 Key 计算:1×0.283+1×0.283=0.566。
在 Prompt B 中,它与“猫”的 Key 计算:1×0+1×0.141=0.141;与“喜欢”自己的 Key 仍得到 0.566。
Knowledge check
Prompt A 中最终“喜欢”对“我”的 Raw Score 1.131 是怎样产生的?
5. 从 Scores 到 Attention Weights
先将最终 Query Row 除以 √d_k。本例 d_k=2,所以 Prompt A 从 [1.131,0.566] 得到 [0.8,0.4],Prompt B 从 [0.141,0.566] 得到 [0.1,0.4]。最终位置可以读取两列,因此这一行没有未来位置需要屏蔽。
Prompt A, final query row
scaled scores = [0.8, 0.4]
exp values = [2.226, 1.492]
sum = 3.718
weights = [0.599, 0.401]
Prompt B, final query row
scaled scores = [0.1, 0.4]
exp values = [1.105, 1.492]
sum = 2.597
weights = [0.426, 0.574]Scroll horizontally to view all columns.
| Softmax | 竞争的 Axis | 回答的问题 |
|---|---|---|
| Attention Softmax | T 个 Key Positions | 当前 Query 应读取哪些位置? |
| Vocabulary Softmax | V 个 Vocabulary Tokens | 下一个 Token 应该是哪一个? |
Knowledge check
为什么 Attention Softmax 必须让每个 Query Row 分别加总为 1?
6. 用 Weights 加权汇总 Values
Prompt A, final 喜欢
weights = [0.599, 0.401]
Values = [[1,0], [0,1]]
o_A = 0.599 * [1,0] + 0.401 * [0,1]
= [0.599, 0.401]
Prompt B, final 喜欢
weights = [0.426, 0.574]
Values = [[-1,0], [0,1]]
o_B = 0.426 * [-1,0] + 0.574 * [0,1]
= [-0.426, 0.574]两条 Prompt 的最后 Token 都是“喜欢”,但 Head Output 已经不同。差异一部分来自 Key 不同造成的 Weight 不同,另一部分来自“我”和“猫”的 Value 本身不同。
Knowledge check
Prompt A 与 Prompt B 的最终 Head Output 为什么不同?
7. 一条完整的 Scaled Dot-Product Attention 计算链
- X @ W_Q/W_K/W_V → Q、K、V
- Q @ Kᵀ → Raw Scores S
- S / √d_k → Scaled Scores
- Future Columns → −∞ → Masked Scores
- Row Softmax → Attention Weights P
- P @ V → Head Output O
训练时,O 继续影响 Transformer 的后续表示、Language Model Head、Logits 与 Cross Entropy Loss。梯度再从 Loss 反向经过 O、P、Softmax 和 Scores,更新 W_Q、W_K 与 W_V。模型不是先拥有正确 Attention 表,而是在降低最终预测 Loss 的过程中逐步学会怎样打分和传递内容。
Scroll horizontally to view all columns.
| 从输出 O=PV 回传 | 经过哪些中间量 | 最后影响 |
|---|---|---|
| 内容这条路 | O → V | W_V 以及输入 X |
| 读取比例这条路 | O → P → Softmax → S → Q、K | W_Q、W_K 以及输入 X |
两条路在同一个输入 X 处要汇总梯度,和 Week 4 的共享变量一样。V 不参与 QKᵀ 的 score 计算,因此它的直接梯度不需要绕过 S。先能指出分支,再看完整矩阵求导。
Knowledge check
模型中“什么位置应得高分”是谁决定的?
8. 为什么除以 √d_k,而不是 d_k
Dot Product 是 d_k 个乘积之和。若每个分量大致零均值、单位方差且不过度相关,那么这些乘积之和的方差约随 d_k 增长,标准差则约随 √d_k 增长。除以 √d_k 可以把典型 Score Scale 拉回较稳定的范围。
Prompt A, final query
raw scores = [1.131, 0.566]
sqrt(d_k) = sqrt(2) ≈ 1.414
scaled scores = [0.800, 0.400]
Prompt B, final query
raw scores = [0.141, 0.566]
scaled scores = [0.100, 0.400]如果同一行分数差距过大,Softmax 容易过早接近 One-Hot,使部分注意力权重对分数的局部变化不敏感。所有分数同加一个大常数不改变 Softmax;也不能把这里的局部斜率简单等同于所有最终参数的梯度。缩放不会改变同一行的排序,只调整 Softmax 接收到的数值尺度。
Knowledge check
除以 √d_k 后,什么保持不变,什么变得更稳定?
9. Self-Attention 的 Shape 与每个 Axis
Scroll horizontally to view all columns.
| Tensor | Shape | 三个 Axis 的含义 |
|---|---|---|
| X | [B,T,C] = [2,2,4] | Batch, Token Position, Model Feature |
| Q / K / V | [B,T,d_head] = [2,2,2] | Batch, Token Position, Head Feature |
| Scores / Weights | [B,T,T] = [2,2,2] | Batch, Query Position, Key/Value Position |
| Head Output | [B,T,d_head] = [2,2,2] | Batch, Query Position, Head Feature |
每张 [T,T]=[2,2] 表中,行 t 是发起读取的 Query Position,列 j 是被比较的 Key Position,也是稍后对应的 Value Position。它们都不是 Feature Axis。
Scroll horizontally to view all columns.
| 索引 | 含义 |
|---|---|
| weights[0,1,0] | Prompt A 最终“喜欢”分给“我”的 Weight |
| weights[1,1,0] | Prompt B 最终“喜欢”分给“猫”的 Weight |
| output[1,1,:] | Prompt B 最终“喜欢”的 Head Output Vector |
Scroll horizontally to view all columns.
| 额外形状检查,另取 B=1,T=3,C=4,H=2 | 预期 shape |
|---|---|
| 输入 | [1,3,4] |
| 分 head 后 Q/K/V | [1,2,3,2] |
| scores:每个 query 对每个 key | [1,2,3,3] |
| 拼回通道 | [1,3,4] |
这只是检验轴的独立例子,不改变前面的两词手算。数字不全相同时,误把 head 轴当时间轴更容易暴露。
Knowledge check
weights[1,1,0] 表示什么?
10. 为什么 GPT 需要 Causal Mask
例如输入 [我,喜欢]、目标 [喜欢,猫]。位置 t=0 应只根据“我”预测“喜欢”;若未使用 Mask,它可以直接读取右侧已经出现的“喜欢”,相当于训练时看见答案。生成时未来 Token 尚不存在,因此这种能力无法使用。
位置 t=3 可以读取 0、1、2、3,不是只能读取紧邻的前一个 Token。Mask 只划定信息边界,不决定允许位置之间具体读取多少。
Knowledge check
为什么不使用 Mask 会造成训练与生成不一致?
11. 为什么 Mask 在 Softmax 前使用 −∞
Scroll horizontally to view all columns.
| t=0 的 Scaled Row | 结果 |
|---|---|
| 原始 [0.2,0.9] | 第二列是 Future |
| 错误:Future 改为 0 | Softmax([0.2,0]) = [0.550,0.450] |
| 正确:Future 改为 −∞ | Softmax([0.2,−∞]) = [1,0] |
Knowledge check
为什么 Forbidden Score 不能简单改成 0?
12. 可复现全部教学数字的 PyTorch 代码
import math
import torch
torch.set_printoptions(precision=4, sci_mode=False)
sqrt_2 = math.sqrt(2)
# [B,T,C] = [2,2,4]
x = torch.tensor([
[
[1.0, 0.0, 0.0, 0.0], # 我
[0.0, 1.0, 0.0, 0.0], # 喜欢
],
[
[0.0, 0.0, 1.0, 0.0], # 猫
[0.0, 1.0, 0.0, 0.0], # 喜欢
],
])
# Formula convention: [C,d_head] = [4,2]
w_q = torch.tensor([
[0.5, 0.5],
[1.0, 1.0],
[-0.5, 0.5],
[0.0, 0.0],
])
w_k = torch.tensor([
[0.8 * sqrt_2, 0.0],
[0.2 * sqrt_2, 0.2 * sqrt_2],
[0.0, 0.1 * sqrt_2],
[0.0, 0.0],
])
w_v = torch.tensor([
[1.0, 0.0],
[0.0, 1.0],
[-1.0, 0.0],
[0.0, 0.0],
])
q = x @ w_q
k = x @ w_k
v = x @ w_v
raw_scores = q @ k.transpose(-2, -1)
scaled_scores = raw_scores / math.sqrt(q.size(-1))
T = x.size(1)
causal_mask = torch.tril(torch.ones(T, T, dtype=torch.bool))
masked_scores = scaled_scores.masked_fill(~causal_mask, float("-inf"))
weights = torch.softmax(masked_scores, dim=-1)
output = weights @ v
print("Q:", q)
print("K:", k)
print("V:", v)
print("Raw scores:", raw_scores)
print("Scaled and masked scores:", masked_scores)
print("Attention weights:", weights)
print("Head output:", output)Expected final rows
Prompt A weights: [0.5987, 0.4013]
Prompt B weights: [0.4256, 0.5744]
Prompt A output: [ 0.5987, 0.4013]
Prompt B output: [-0.4256, 0.5744]这段代码使用 x @ w_q,所以 W 按公式写成 [C,d_head]。nn.Linear(C,d_head) 内部存储的 weight 是 [d_head,C],运行时框架使用其转置;两种写法的数学含义相同。
Knowledge check
为什么这段代码不使用随机初始化的 nn.Linear?
13. 可复用的 Causal Attention Head
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
class AttentionHead(nn.Module):
def __init__(self, embed_dim: int, head_size: int, context_length: int):
super().__init__()
self.query = nn.Linear(embed_dim, head_size, bias=False)
self.key = nn.Linear(embed_dim, head_size, bias=False)
self.value = nn.Linear(embed_dim, head_size, bias=False)
self.register_buffer(
"causal_mask",
torch.tril(
torch.ones(
context_length,
context_length,
dtype=torch.bool,
)
),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# x: [B,T,C]
_, T, _ = x.shape
if T > self.causal_mask.size(0):
raise ValueError("Sequence length exceeds context_length")
q = self.query(x) # [B,T,d_head]
k = self.key(x) # [B,T,d_head]
v = self.value(x) # [B,T,d_head]
scores = q @ k.transpose(-2, -1) # [B,T,T]
scores = scores / math.sqrt(k.size(-1))
mask = self.causal_mask[:T, :T]
scores = scores.masked_fill(~mask, float("-inf"))
weights = F.softmax(scores, dim=-1)
return weights @ v # [B,T,d_head]Scroll horizontally to view all columns.
| 代码阶段 | 公式 | Shape |
|---|---|---|
| query/key/value(x) | Q=XW_Q, K=XW_K, V=XW_V | [B,T,C] → [B,T,d_head] |
| q @ k.transpose(-2,-1) | S=QKᵀ | [B,T,d_head] @ [B,d_head,T] → [B,T,T] |
| scores / sqrt(k.size(-1)) | S/√d_k | [B,T,T] → [B,T,T] |
| masked_fill | Future → −∞ | [B,T,T] → [B,T,T] |
| softmax(dim=-1) | Row Softmax | [B,T,T] → [B,T,T] |
| weights @ v | O=PV | [B,T,T] @ [B,T,d_head] → [B,T,d_head] |
register_buffer 让 Mask 随模型移动到 CPU 或 GPU,但不会成为 Trainable Parameter。[:T,:T] 让同一个最大 Context Mask 适配当前 Runtime Sequence Length。
Knowledge check
这个 AttentionHead 为什么不能直接与输入 x 做 Residual Addition?
14. 为什么叫 Self-Attention
Self 的含义是 Q、K、V 都来自同一条输入 X。它不表示 Token 只能看自己;GPT 的 Causal Self-Attention 允许每个位置看自己和全部可见左侧。
Scroll horizontally to view all columns.
| 类型 | Query 来源 | Key / Value 来源 |
|---|---|---|
| Self-Attention | 序列 X | 同一序列 X |
| Cross-Attention | 目标序列或当前状态 | 另一条 Source Sequence |
Prompt A 的 Scores Slice 只包含“我、喜欢”;Prompt B 的 Slice 只包含“猫、喜欢”。把两条 Prompt 放入同一 Batch 只是并行计算,不是把它们接成一段文本。
Knowledge check
Prompt A 的“喜欢”可以读取 Prompt B 的“猫”吗?
15. Multi-Head Attention 与 Output Projection
每个 Head 都有自己的 W_Q、W_K、W_V,可以学习不同的匹配空间和 Payload。不同 Head 可能利用不同线索,但不保证它们自动变成可命名的语法专家。
- X [B,T,C]=[2,2,4]
- 并行:Head 1(X) 与 Head 2(X),各 [2,2,2]
- 沿特征轴拼接为 [2,2,4]
- 乘 W_O:[4,4],输出 [2,2,4]
class MultiHeadAttention(nn.Module):
def __init__(self, embed_dim: int, num_heads: int, context_length: int):
super().__init__()
if embed_dim % num_heads != 0:
raise ValueError("embed_dim must be divisible by num_heads")
head_size = embed_dim // num_heads
self.heads = nn.ModuleList([
AttentionHead(embed_dim, head_size, context_length)
for _ in range(num_heads)
])
self.output_projection = nn.Linear(
embed_dim,
embed_dim,
bias=False,
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
head_outputs = [head(x) for head in self.heads]
concatenated = torch.cat(head_outputs, dim=-1)
return self.output_projection(concatenated)Output Projection 不只是为了 Shape。Concat 后不同 Head 的 Features 仍只是并排放置;W_O 允许模型学习如何跨 Head 重新组合信息,并为后续 Residual Addition 提供 [B,T,C] 接口。
Head 2 接收的是同一个 X,不是 Head 1 的输出。可以把两个结果想成同一行的两份两维记录,先并排拼成四维,再由输出投影学习怎样组合。堆叠两个 Transformer blocks 才是前一块输出进入后一块的顺序计算。
Knowledge check
为什么 Multi-Head Concat 后还需要 W_O?
16. Attention Output 怎样影响最终 Logits
- X [B,T,C]
- Multi-Head Attention [B,T,C]
- Transformer 后续 Residual / FFN / Layers [B,T,C]
- Language Model Head W_vocab:[C,V_vocab]
- Logits [B,T,V_vocab]
- 需要解释概率时再对 Vocabulary Axis 做 Softmax
本课的 Prompt A 与 Prompt B 已在最终位置产生不同的 Head Output。经过 Multi-Head、W_O 与后续 Transformer 处理后,它们可以形成不同的 H,因此 Language Model Head 可以产生不同 Logits。Attention 并不直接输出哪个 Token。
Scroll horizontally to view all columns.
| 对象 | 典型 Shape | 意义 |
|---|---|---|
| Attention Weights | [B,n_head,T,T] | 每个 Query 读取哪些 Key/Value Positions |
| Contextual Features H | [B,T,C] | 每个位置经过上下文处理后的表示 |
| Vocabulary Logits | [B,T,V_vocab] | 每个候选 Token 的原始分数 |
| Vocabulary Probabilities | [B,T,V_vocab] | Logits 沿 Vocabulary Axis Softmax 后的分布 |
Knowledge check
Attention Weights 与 Vocabulary Probabilities 分别回答什么问题?
17. Attention 的计算成本
每个 Head 的 Score Matrix 有 T² 个 Elements。所有 Batch Examples 和 Heads 合计拥有 B×n_head×T² 个 Score Elements;Weights 还需要同样数量的 Elements,训练还会保存额外 Activations 与 Gradients。
Scroll horizontally to view all columns.
| 固定 B=2、n_head=2 | 全部 Heads 的 Score Elements | 相对 T=2 |
|---|---|---|
| T=2 | 2 × 2 × 2² = 16 | 1 倍 |
| T=1000 | 2 × 2 × 1000² = 4,000,000 | 250,000 倍 |
Causal Mask 禁止读取未来位置,但普通 Dense 实现仍可能先构造完整 T×T Matrix。不同优化实现可以减少实际 Memory 或运算,但不会改变本课需要理解的基础 Shape。
Knowledge check
当 B、Heads 和 Width 固定时,T 翻倍后 Score Elements 增长几倍?
18. Week 7 调试清单与必须掌握的 10 件事
Scroll horizontally to view all columns.
| 调试顺序 | 应该检查什么 |
|---|---|
| 1. X | 确认是 [B,T,C] 向量,不是 Token ID |
| 2. Q/K/V | 确认 [B,T,d_head],数值来自相应 Projection |
| 3. Scores | 确认使用 K.transpose(-2,-1),得到 [B,T,T] |
| 4. Scale | 确认除以 √d_k |
| 5. Mask | 确认 Future Columns 在 Softmax 前为 −∞ |
| 6. Softmax | 确认 dim=-1,每个 Query Row 加总为 1 |
| 7. Retrieval | 确认 Weights @ V,而不是 @ K |
| 8. Multi-Head | 确认在 Feature Axis Concat,并经 W_O 恢复 C |
| 9. Batch | 确认不同 Batch Examples 没有相互读取 |
| 10. Logits | 确认 LM Head 接收 Contextual Features,而不是 Attention Weights |
- Attention 解决相同当前 Token 无法读取不同前缀的问题。
- X 是 Token 的向量表示,不是 Token ID。
- Query 表达当前位置需要寻找什么。
- Key 提供用于匹配的 Learned Clue。
- Value 提供匹配后真正带回的 Payload。
- QKᵀ 的每个元素都是一个 Query-Key Dot Product Raw Score。
- Scale、Mask、Row Softmax 的顺序不能交换或省略。
- Causal Mask 禁止 Future,但允许全部历史和当前位置。
- Multi-Head Concat 与 W_O 将多个 Head 恢复到 Model Width C。
- Attention Output 是 Contextual Features;LM Head 才产生 Vocabulary Logits。
Knowledge check
如果 Scores 正确,但 Future Position 仍有正 Weight,最应该先检查哪两步?
19. Week 7 → Week 8:Attention 还不是完整 Transformer Block
Week 8 将从同一个 [B,T,C]=[2,2,4] 接口继续。Token Embedding 与 Position Embedding 相加后仍为 [2,2,4];Multi-Head Attention 经过 Concat 与 W_O 后也必须返回 [2,2,4],才能与 Residual Path 相加。
- Token Embedding + Position Embedding [2,2,4]
- Pre-Norm Multi-Head Attention [2,2,4]
- x + Attention(LN₁(x)) [2,2,4]
- Per-Position FFN [2,2,4]
- x₁ + FFN(LN₂(x₁)) [2,2,4]
- Language Model Head → Logits [2,2,V_vocab]
Scroll horizontally to view all columns.
| 组件 | 主要职责 |
|---|---|
| Position Embedding | 提供 Token 顺序与位置信息 |
| Causal Multi-Head Attention | 跨允许的 Token Positions 混合信息 |
| FFN | 在每个 Position 独立执行相同非线性变换 |
| Residual Connection | 保留原路径并改善深层训练 |
| Layer Normalization | 帮助稳定各层输入尺度 |
Knowledge check
Week 8 中哪个组件跨位置混合,哪个组件逐位置独立处理?