5-A2S1-attention.ipynb 逐步说明

这份 notebook 你们在 2/1-class-prog.md 里已经知道它的总体目标了:建立 attention 的行为直觉。这里不再重复“它在做什么”,而是专门补上 notebook 里每个关键 cell 的具体作用。

它和后面第 3 课的 LoRA / Qwen 实验也有直接关系:

Cell 3:导入 torch

import torch

这一格很简单,但这里已经在告诉你:后面的 attention 不是符号推导,而是要拿真实张量直接算。

Cell 4:固定随机种子

torch.manual_seed(447)

作用是让 key / value 等初始化结果固定下来,保证每个同学跑出来的数值环境一致。

这和你们前面在 course_lora-tinygpt2 里做最小实验时固定环境,是同一种“保证可复现”的习惯。

Cell 5:定义 attention(...)check_query(...)

def attention(query, key, value):
    return F.scaled_dot_product_attention(query, key, value, scale=1)

这一行最关键的点

为什么这么做?

也就是说,这份作业在简化问题,让你先看懂机制。

check_query(...)

def check_query(query, target, key=key, value=value):
    a_out = attention(query, key, value)
    print("maximum absolute element-wise difference:", (target - a_out).abs().max())

这个函数的作用不是给你答案,而是告诉你:

这和后面第 3 课里不断打印 loss、检查生成结果,是同一种“先验证行为,再谈理论”的工程思路。

Cell 7:选中第一个 value

题目要求你构造一个 query,让 attention 输出尽量接近第一个 value 向量。

这里真正想让你体会的是:

所以这道题不是在考“有没有唯一正确答案”,而是在考:

你是否知道 query 要朝哪个 key 的方向靠近。

Cell 8:恒等映射

这道题要求你构造 query matrix,让输出近似等于整个 value 矩阵本身。

它在考的其实是:

这正是后面 multi-head attention、batch 计算能成立的最基本直觉。

Cell 10:平均所有 value

这一格最值得注意的不是答案,而是思路:

最朴素的做法就是让 query 对所有 key 的相似度差不多。

这和后面 Transformer 里“某个 token 同时关注多个上下文位置”是同一个机制。

Cell 11:只平均前两个 value

这一格开始从“均匀平均”进阶到“部分平均”。

真正的难点是:

这已经很接近真实 attention 的感觉了:一个 token 往往会对几个相关位置同时分配权重,而不是只盯着一个位置。

Cell 13:改第三个 key,让前三个 value 被平均

这里第一次不改 query,而改 key。

这题很重要,因为它说明:

这和你们后面在第 3 课里改 q_proj / k_proj 的意义是一致的:

Cell 14:改第三个 key,让 attention 返回第三个 value

这是本 notebook 最“行为操控”味道的一题。

它要你体会:

如果学生能真正理解这题,后面看到第 3 课里:

target_modules=['q_proj','k_proj','v_proj', ...]

就不会觉得这是魔法参数,而会知道:这些层控制的正是相似度与信息路由。

这份 notebook 最值得带走的 3 个具体感觉

  1. Query 决定“想看什么”
  2. Key 决定“谁会被看见”
  3. Value 决定“被看见后拿出什么信息”

如果这三个感觉已经建立起来,A2S2 里的手写 attention 就会顺很多。