01 / 从逐步读入到直接关联
当前位置可以参考哪些位置?
上一节的单向 RNN 依次读 Token,让后面位置通过状态间接获取前文。自注意力让每个位置直接给可见位置打分,再按分数汇合它们的信息。矩阵计算可以同时处理多个位置的相关性,概念上会形成一个 T×T 的位置关系表。
Query 与 Key 匹配,得到相关分数。
沿每一行做 softmax,变成非负且和为 1 的权重。
用权重对 Value 向量求加权和。
这里讲自注意力:Q、K、V 都由同一序列的向量分别投影得到;三套投影参数可以不同。解码时若要预测下一个词,还需因果掩码阻止看未来。
02 / 先把三种向量分开
Query 发出匹配请求,Key 用来比对,Value 用来汇合
把 Token “小猫 / 喜欢 / 小鱼”放在 3 个位置。下表的二维 Q、K、V 是人为指定的可手算数值,不是词的真实语义向量,也不是训练出的注意力。实际模型一般从输入 X 学三组线性投影。
点击下面矩阵中的一个格子,便同时选中了某个 Query 行与 Key 列,就能看到两个向量的点积。Key 决定匹配权重;Value 决定最后取回的内容。把 Key 与 Value 混作同一件事,就会看不懂后面的矩阵乘法。
03 / 一行一行看软选择
点积 → 除以 √d → 掩码 → softmax
本例 d=2,所以把点积除以 √2。这个缩放在维度较大时有助于避免点积分数随维度增大而过大,令 softmax 过于尖锐。再按是否启用因果掩码决定哪些列可见。
颜色越深表示权重越大;每一行的权重之和为 1。当前选中的分数来自某行 Query 与某列 Key;权重不是单个分数直接除以行和,而是先指数化,再归一化。
04 / 权重之后才使用 Value
第 i 个位置的输出是 Value 的加权和
选中某个 Query 行,下方会展示该行对三张 Value “取回”了多少。因果模式下未来位置权重为 0,它的 Value 不参与该行输出。
例如因果模式下第 0 行只能看自己,权重 [1,0,0],所以输出就是 V[0]=[1,0]。第 1 行可看位置 0、1,输出是两行 Value 的加权组合。
05 / 不让未来答案进入当前输出
因果掩码是上三角的“不可见”格
行 i 表示当前要产生第 i 个位置的输出;列 j 表示候选输入位置。若 j>i,列 j 在未来,训练下一个词时必须屏蔽。
配套代码还做了两个检验:把第 3 个位置的输入大幅改动,因果模式下位置 0、1、2 的输出完全不变;不加掩码时早期输出会变。反向传播位置 1 的输出时,对未来输入位置 2、3 的梯度恰好为 0。它们说明这段实现不会通过注意力读取未来。
block=True 表示“遮住”;PyTorch scaled_dot_product_attention 的布尔 attn_mask=True 表示“允许参与”。因此传给该 API 时需要取反,或直接使用 is_causal=True。不要把两种布尔约定当成相同。官方定义。06 / 一套注意力不够时
多头:并行使用不同的投影
真实代码用 B=2、T=4、D_model=4、H=2,每头宽度 d_head=2。Q、K、V 各经过一个可学习的线性层,按 head 拆开。每个 head 都有自己的权重表,分别聚合 Value,最后拼接并再做一次输出投影。
以上权重来自随机初始化、尚未训练的 CPU 模型,只用于验证形状与因果三角形;不要从色块推断它“理解了”句子。两头的不同权重来自不同投影,不等于把一个权重表复制两份。这个示例有 4 个 4×4 无偏置线性投影,共 64 个参数。
07 / 注意力自己知道顺序吗
给不同位置加入位置信息
如果不加因果掩码,也不加位置向量,普通自注意力只根据内容计算;把输入顺序重排,输出会以同样方式重排,这叫置换等变。它没有固定的“第 0 个位置”标记。给每个位置加不同位置向量后,输入内容与位置结合,重排内容却保持位置槽不变,输出一般会不同。
代码用未加掩码的随机模型核对:无位置向量时,重排前后的最大差异仅是浮点误差;加位置向量后,本次示例差异明显。因果掩码本身也给出“可看到多少前文”的结构线索,因此不能笼统地说“所有不加显式位置编码的因果模型完全没有位置信息”。
08 / 自己写一遍核心计算
本地 CPU PyTorch 练习
本项目只用已安装的 CPU PyTorch。代码手写注意力函数与两头模块,拿官方 API 核对手算例子,检查形状、因果隔离、梯度和位置效果;不需要下载数据或启动服务。
uv run python lessons/lesson-11-attention.py- 手算第 1 行的 Q·K、除以 √2、掩码和 softmax;解释为何未来列权重为 0。
- 在页面切换“全可见”,观察第 0 行是否会参考“小鱼”。这时不适合直接用于逐词预测。
- 用形状表逐步证明
(B,H,T,d_head) @ (B,H,d_head,T) → (B,H,T,T)。 - 改成
D_model=6、H=3,预测每头维度和各张量形状,再运行核对。 - 解释布尔 mask 的两种约定,并用“改变未来 Token”测试自己的实现。
09 / 自测