这一课完成什么
把一次注意力汇总分成几组并行计算,再合并结果。每一组叫一个“头”。头数不是诗句数,也不是模型里几个独立人格;它只是把表示宽度分成若干部分,分别计算匹配和汇总。
多头,是把特征分组后分别汇总
一个位置的向量被分成几组,每组各自计算注意力,最后拼回原宽度。不同组可以学出不同的处理方式,但我们没有事先给它们分派语法或押韵任务。
用文字逐步读这张图
- 原来的宽度:每位置 8 个数字;C = 8
- 分为 2 头:每头 4 个数字;8 ÷ 2 = 4
- 第一组计算:自己的 Q、K、V;得到一份汇总
- 第二组计算:另一组 Q、K、V;可有不同权重
- 拼回 8 格:先拼接,再做变换;不是求平均
- 尺寸要兼容:8 可以分 1、2、4、8 头;不能平均分成 3 头
增加头数一定增加参数吗?
在总宽度固定、当前实现不变时,主要是重新分组,QKV 的总投影尺寸不因此增加。
用尺寸追踪一次分头
假设 B=1、T=3、C=8,头数 H=2。每个头宽度为 8÷2=4。Q 原本是 [1,3,8],先改成 [1,3,2,4],再交换位置维和头维,得到 [1,2,3,4]。
| 环节 | 尺寸 | 含义 |
|---|---|---|
| Q、K、V | [1,2,3,4] | 两个头各处理三个位置 |
| 匹配分数 | [1,2,3,3] | 每个头有一张位置匹配表 |
| 汇总后的内容 | [1,2,3,4] | 每个头各输出四项信息 |
| 合并 | [1,3,8] | 每个位置重新拼回八项 |
每个头都执行第 11、12 课的比较、遮挡、归一化与汇总。合并后再经过输出投影,允许不同头的信息相互组合。
运行并查看
./poet lesson 13q = q.view(batch, length, heads, width // heads).transpose(1, 2)
merged = values.transpose(1, 2).contiguous().view(batch, length, width)先不改代码,用纸列出两次 transpose 前后的每个维度。随后把头数从 2 改为 4,再运行。总宽度不变,每头宽度由 4 变成 2,权重表头维由 2 变成 4。
头数增加会发生什么
在本项目固定总宽度的实现中,只改变头数,QKV 变换矩阵的尺寸不会增加,每头分到的宽度反而变小。因此不能把“头数更多”直接等同于“模型参数更多”或“效果一定更好”。不同头可能学到不同的关联,也可能重复;需要用固定的验证方式比较。
注意力头的含义不是事先写死的“一个看押韵、一个看思乡”。模型没有收到这样的分工指令。为了说明结构可以用多组汇总来理解,但不能把比喻当作已验证的解释。
验收与排错
- 两头实验权重尺寸为
[1,2,3,3],输出仍是[1,3,8]。 - 宽度 8 可被 2、4 整除,不能被 3 整除。
- 合并时交换回位置与头维,否则同样数量的数字会被排成错误顺序。
view报错时检查连续性;本代码明确调用contiguous()。
小练习与答案
正式配置宽度 256、头数 4、前文长度 64,单首诗每个头的分数表多大?所有头共多少格?
查看答案
每个头是 64×64,共四张表,因此有 4×64×64=16,384 个分数格;每头的 Q、K、V 宽度是 64。这里是中间计算数量,并非新增了这么多可学习参数。批数量增加还会复制这些中间计算。