这一课完成什么
这一课先把“注意力”当成一项明确的计算:根据分数,给前面各个位置分配权重,再按权重汇总它们携带的信息。权重是一组非负数,总和为 1。它们会随当前输入和训练得到的参数而变化。这里的名字并不意味着程序有人的意识。
注意力,是一次有权重的信息汇总
不是把某个字简单挑出来。模型先算各位置的参考权重,再把各位置带来的信息按这些权重加起来。
用文字逐步读这张图
- 当前正在读的字:提出本次查询;称为 Q
- 各位置的线索:用来与查询比较;称为 K
- 算相似分数:Q 与 K 做点积;再做缩放
- 变成参考权重:softmax 后和为 1;高权重多参考
- 各位置的信息:将要被汇总的数字;称为 V
- 加权相加:权重 × V,再求和;得到新的表示
注意力权重高,就证明这个字是语义原因吗?
不能直接这样解释。权重描述这层这组计算怎样混合信息,不是完整的因果解释。
假设当前已经读到“春江花”,三个位置携带的两项信息分别是 [1,0]、[0,2]、[2,2]。这些小向量是为了手算而设的示例,不给每一维强行命名为“季节”或“情绪”。真实模型中的表示由训练学出,通常无法给每一维贴上清晰的人工标签。
一次具体的汇总
假设三个位置的匹配分数为 [2,1,0]。先减去最大分数 2,得到 [0,-1,-2],再分别取指数,得到大约 [1,0.368,0.135]。除以总和 1.503,得到 [0.665,0.245,0.090]。这就是第 6 课介绍过的 softmax 运算。
汇总的第一项 = 0.665 × 1 + 0.245 × 0 + 0.090 × 2 = 0.845
汇总的第二项 = 0.665 × 0 + 0.245 × 2 + 0.090 × 2 = 0.670这个结果保留了三个位置的信息,贡献比例不同。与“只选择分数最高的位置”相比,加权汇总允许多处信息共同参与。注意力权重也不等于完整的因果解释:后面还有多层加工,不能只凭某个格子较亮就断言模型为什么写出了某个字。
演示中的滑块用于观察分数分布变尖或变平时,汇总如何变化。它是本页的教学控制;正式模型注意力使用代码中的缩放公式,生成时的 temperature 则控制最后选字的分布,二者作用位置不同。
动手计算
./poet lesson 10
.venv/bin/python lessons/10/experiment.py本课完整计算只有三个关键步骤:
scores = torch.tensor([2., 1., 0.])
weights = scores.softmax(-1)
values = torch.tensor([[1., 0.], [0., 2.], [2., 2.]])
summary = weights @ values@ 表示矩阵乘法。左侧有 3 项权重,右侧有 3 行、每行 2 项信息,所以结果只有 2 项。输出应接近 [0.845,0.670],小数末尾会受显示精度影响。把全部分数改为 0,三个位置的权重都会成为三分之一,结果接近 [1.000,1.333]。
从一个位置走向一整句
真实 GPT 会为每一个预测位置各算一组权重。若句子有 3 个字,就有一个 3 行、3 列的分数表:行表示“当前是谁在汇总”,列表示“从谁那里取信息”。第 11 课会把分数来源展开,第 12 课会限制哪些位置可以参与,第 13 课会同时做多组这样的汇总。
先记住本节的边界:我们暂时假定分数已经给定,还没有学习怎样生成分数。这样可以把“分配贡献比例”和“计算匹配程度”分开理解。
验收与排错
- 三个权重均非负,和接近 1;误差在浮点数最后几位是正常现象。
- 输出尺寸为
[2],不是[3]。输出尺寸取决于值向量宽度。 - 若提示尺寸不匹配,核对权重的项数与
values的行数是否都为 3。 - 若输出成了三个位置中某一行,检查是否误用了取最大值操作;这里需要加权相加。
小练习与答案
把分数改为 [0,0,0],先手算再运行。再把第一项变为 10,判断输出会靠近哪个向量。
查看答案
分数相同意味着三个权重都为 1/3,汇总是 [1,4/3]。第一项远高于其他项时,权重集中到第一个位置,输出会靠近 [1,0],但有限分数下其他位置权重仍可能大于 0。可以直接修改本课 experiment.py 的 scores,然后重新运行。
对应正式模型
在 poetry_gpt/model.py 的 CausalAttention.forward 中,weights @ v 就是本课的汇总运算。使用 inspect=True 可以拿到权重。正常训练走 PyTorch 的优化计算路径,意义一致;项目的测试会检查两条路径的结果。