5-A2S2-attention.ipynb 逐步说明这份 notebook 在 2/1-class-prog.md 里已经讲过整体结构。这里补的是更具体的“每一步到底在实现什么”。
它和后面第 3 课的最小 LoRA 实验有非常清楚的对应关系:
pairwise_similarities、mask、split_headscourse_lora_qwen_src 里你虽然不再手写 attention,但你改的 q_proj / k_proj / v_proj / o_proj 正是这些操作背后的模块init_qkv_proj(...) 和 self_attention(...)init_qkv_proj(n_embd:int)return (nn.Linear(n_embd, n_embd), nn.Linear(n_embd, n_embd), nn.Linear(n_embd, n_embd))这说明:
这和你们第 3 课里看到的:
target_modules=['q_proj', 'k_proj', 'v_proj', ...]可以直接对上。
self_attention(...)这一格是整份作业的总装函数。你会反复回来补它。
它的结构本质上是:
这就是 Transformer block 里 self-attention 的主链。
pairwise_similarities(Q, K)这一格让你实现:
A = QKT
它真正想让你注意的是:
K 不是直接乘,而是最后两维转置query positions x key positionsattn_scaled(A, n_embd, n_heads)这里要求你实现标准 scaling:
$$\frac{A}{\sqrt{d_k}}$$
其中:
d_k = n_embd / n_heads为什么要除以它?
这和前面 A2S1 故意把 scaling 去掉,刚好形成对照。
attn_softmax(A)这一步很简单,但有一个最容易犯错的点:
dim=-1因为你是在“对每个 query,看所有 key 的分布”。
compute_outputs(A, V)这里要求实现:
O = AV
也就是用注意力权重去加权求和 value。
make_causal_mask(n_tok)目标是构造一个下三角 mask,让每个位置只能看自己和过去。
为什么一定要这样?
apply_causal_mask(mask, A)通常的做法是:
-inf这样 softmax 后,未来位置的概率就变成 0。
这一步和后面第 3 课的所有 causal LM 微调完全同源。
split_heads_qkv(Q, K, V, n_heads)这里的真正难点不是数学,而是 shape。
你要学会把:
(B, T, C)变成类似:
(B, H, T, C/H)也就是说:
因为还涉及:
这些张量组织方式的变化,决定了每个 head 真正处理的是 embedding 的哪一部分。
从这里开始,notebook 从“手写 attention 小练习”进入“放进最小 Transformer 里跑训练”。
这部分和课程目录里的:
N-gram.zipmingpt-cse447.zip直接对应。你们在课程页里已经准备好了本地副本,就是为了让这一步不依赖在线下载。
mingpt.model.GPTX 和 Y这部分很值得和第 3 课 course_lora_qwen_src/data/*.json 对照:
形式不同,但本质都是“把原始文本组织成 next-token prediction 数据”。
model_config = GPT.get_default_config()train_config = Trainer.get_default_config()model.to(DEVICE)plt.plot(log)你可以把它理解成第 2 课版本的“最小训练闭环”。
这和后面你们第 3 课里训练完后立刻做推理,是同样的节奏:
训练不是终点,验证行为才是。
QK^T、scaling、softmax、加权和是 attention 的四步主链