05 课 · 位置编码
LESSON 05 · 卷五 顺序登场

给每个座位发一张指纹

第 4 课算完了注意力分数表的形状:一句话 1,024 个 token, 表就是 1,024 × 1,024。可那张表从头到尾只回答一个问题—— 「谁和谁像」。「谁先出现、谁后出现」,它一个字都没说。这件事听起来小,代价却很大:把「十五」和「五十」喂进去, 模型看到的是一模一样的 8 × 2 个数。这一课我们补上 Transformer 拼装前的最后一块零件——让矩阵第一次知道顺序。

STAGE 01
顺序丢了
同一个袋子,两种摆法
STAGE 02
座位号
直接加 → 被位置项压死
STAGE 03
指纹
32 个座位 32 张不重样
STAGE 04
用起来
加法、相对位置、上限
第 1 站

模型眼里没有顺序

先把这件事看成一个具体的问题。第 3 课训出来的那张嵌入矩阵 E [20, 8]。 一句话进去,模型拿到的是一个 [字數, 8] 的小矩阵—— 每一行是一个字在第 3 课学到的向量。就这些,没有别的了。

「十五」和「五十」用的是同一批字,只是摆的顺序不一样。 点下面的按钮来回切这两句话,盯住两个地方:袋子里的东西变没变,两两打分的那张表变没变。

核心实验换个摆法 —— 模型看到的是不是同一份东西?
模型拿到的输入:2 行 × 8 个数 —— 每一行是那个字在第 3 课学到的向量, 行与行之间只有「摆在第几个」,没有任何额外标记。
0.26-0.270.170.51-0.28-0.76-0.200.650.73-0.16-0.18-0.850.120.290.480.34
袋子里的东西数一数:2 个字,两种排法用的是同一批
两两配对打的分 ↓
1.54-0.36-0.361.75
这句话摊开是 4 个分数:1.75、1.54、-0.36、-0.36
换一句话(「五十」), 摊开还是这 4 个数 —— 一个不差,只是换了摆法。
模型接下来做的每一件事——连机算谁像谁、按分数加权收集——都只认这 4 个数。 所以「十五」和「五十」在它眼里是同一份输入; 可这两个数一个是 15、一个是 50。序丢了,意思就丢了。
👆 点上面的按钮换句子:先看「袋子里的东西」有没有变,再看「两两配对打的分」那 4 个数有没有变。 两次都是没变 —— 变的只有「谁摆在第几行」。
「十五」和「五十」,模型手里的 8 维向量一行不差;「三加五」和「五加三」也一样。 连两两配对的分数都逐个相等——因为点积压根不看顺序,a·bb·a 本来就是同一个算式。 模型接下来要做的每一件事,都只认这 8 个数和这些分数。
图 5-1 · 同一批字的两句话:[字數, 8] 的输入矩阵只是行换了个位置,两两配对的分数表一个不差

这不是「有点不准」的问题,是彻底看不见。你喂进去的是 15 还是 50, 模型给出的东西完全一样。所以第 4 课末尾那句「矩阵不知道谁先谁后」, 现在有了证据。

「十五」和「五十」在模型眼里是一模一样的一份输入最小的一步修补是什么?先别往下翻,真的想 30 秒。
第 2 站

最笨的塞法:座位号直接加

最笨的塞法就是字面意思:把座位号当成一个数,加到那个字向量的每一维上。 第 12 个座位的「」就变成 E() + 12, 8 个数一起加 12。两个位置的字要量相似度时,就是(E + p) · (E′ + q)

看起来挺合理。但把它展开,就会看见一件麻烦事。下面这台机器把这一整条算式摊成四项,每一长条都按同一个刻度尺画——拖两根滑块试试:

核心实验座位号直接加 —— 四项摊开,看谁把谁盖住了
「加」的座位号 p12
「减」的座位号 q25
「加」+ 12
11.7111.9012.8411.0811.9811.6110.7112.91
「减」+ 25
25.0224.6926.0224.1424.7424.2224.2025.49
加完之后,这两个字各自的 8 个数就长这样 —— 位置被平铺到每一维上, 整行一起抬高了 1225
这两行量一次相似度,摊开是四项 ↓
① 内容项 E·E′第 2 课那把尺子,只认字
3.460500
② p × ΣE′12 × (减 那一行的总和)
-17.760000
③ q × ΣE25 × (加 那一行的总和)
-31.500000
④ d × p × q只认座位,不认字
2400.000000
= 总得分① + ② + ③ + ④
2354.200500
横条长度按 |值| 画,左端是 0、满格是 7,688(=④ 那一项能顶到的最大值 8 × 31 × 31,所有组合里没有比它更大的数)。 ① 那条细得看不见,因为它只有 3.460500
同一对字,只因为座位号不同,得分从 3.460500(都在 0 号座)一路变成 2354.200500。而这里面真正认识字的那一项只有 3.460500, 剩下的 2350.740000 全是座位号自己算出来的 —— 是它的 679 倍。
更难看的是这一组:座位 12 的「」和座位 13 的「」是同一个字(得分 1220.790800), 反而不如座位 12 的「」和座位 25 的「」 (得分 2354.200500)像。位置这把尺子一加进来,就把内容的尺子盖住了 —— 这正是「座位号直接加」走不通的原因。
👆 拖两根滑块换座位号。注意 ④ 那一条:它只跟 p、q 有关, 把「」换成任何一个字,它的长度都不会变。
四项里只有 ① 认识字。④ 是 d × p × q—— 它连「这两个字是什么」都不问,光凭座位号就能算出来,而且它最大: 座位号上到 31 时能到 7,688, 而整张嵌入矩阵里最大的内容项才 13.00(第 4 课量出来的对角线)。 差 591 倍。
图 5-2 · (E + p) · (E′ + q) = E·E′ + p·ΣE′ + q·ΣE + d·p·q; 三项都跟座位号有关,最后一项更狠——它跟座位号有关
7,688」和「591 倍」是怎么算出来的
(E + p) · (E′ + q) 摊开有四项,逐位相乘的 8 对里,每一对都多出一个 p × q
④ 纯位置项 = 8 × p × q;座位号取到 31 时最大 = 8 × 31 × 31 = 7,688
① 内容项的最大值 = 第 4 课那张相似度表的对角线 = 13.00
倍数 = 7,688 ÷ 13.00 = 591.4 591

注意这件事的荒谬之处:④ 这一项跟字没关系。 把「」换成任何一个字,它都一样大。 换句话说,模型量出来的「相似度」里,绝大部分是座位号自己在跟座位号聊天, 字的内容反而成了零头。

座位号直接加,坏在「它只是一个数」——一个数加到每一维上,摊开后必然生出一个8 × p × q 这种只认位置的巨项。那位置到底该做成什么样,才能既不盖住内容、又能分辨远近?
第 3 站

sin / cos:给每个座位一张指纹

现在的做法是这样的:每个座位不发一个号,发一张「指纹」。 这张指纹也是 16 个数,但每个数都由一个快慢不同的指针转出来。

想象 8 根指针,都从正右方出发,但转速天差地别:最快的那根每走一个座位就转一整圈; 最慢的那根走完 32 个座位连一圈的百分之一都没转完。 每个座位停下来的位置,8 根指针的横坐标和纵坐标, 就是这张指纹的 16 个数。下面这张图就是它:

核心实验指纹表 —— 32 个座位 × 16 个数,点一格看它怎么转出来的
0123456789101112131415012345678910111213141516171819202122232425262728293031
越蓝 = 越接近 +1越黄 = 越接近 −1颜色深浅固定按 |值| ÷ 1.00 画,不按这张表里最大的那格归一
横轴是第几维(0 ~ 15):第 2i 维是 sin、第 2i+1 维是 cos,两个一组共用频率 ωᵢ。 纵轴是座位号(0 ~ 31)。点任意一格看它的数是怎么算出来的。
座位 7、第 0 维(第 0 对里的 sin):
ω0 = 1相位 = 7 × 1 = 7.000000sin(7.000000) = 0.656987
座位 7 的整张指纹(16 个数)是 [0.66, 0.75, 0.80, -0.60, 0.64, 0.76, 0.22, 0.98, 0.07, 1.00, 0.02, 1.00, 0.01, 1.00, 0.00, 1.00] —— 这 16 个数就是模型眼里「第 7 个位置」的全部样子。
32 个座位,32 张指纹,没有两张一样——最像的两个座位(3 4)也差着 1.0147,最不像的(0 28)差着 3.5090。最快那一对在第 31 个座位里转了 4.93,最慢那一对连 0.16% 圈都没走完。8 对频率分别是 1、0.3162、0.1、0.03162、0.01、0.003162、0.001、0.0003162 —— 从快到慢跨了 3162 倍。 快的负责「挨得近的差别」,慢的负责「离得远的差别」。 点上面两个按钮,只留最快或最慢那一对,感受一下这件事。
浅蓝是接近 +1、深黄是接近 −1、越白越接近 0。纵向一条一条的花纹, 就是一根一根指针转出来的轨迹:最快的(第 0、1 维)在短短 32 行里来回穿了 4.93 圈,最慢的(第 1415 维) 连 0.16% 圈都没走完。
图 5-3 · 32 × 16 = 512 个数,一张 [32, 16] 的「指纹表」; 颜色刻度固定在 ±1,不按表里最大值归一
请注意你刚刚做了什么——
你给每个座位,
发了一张指纹
这个数是哪来的 · 每一格都能按计算器核对
第 i 对指针的转速(角频率):ωᵢ = 1 ÷ 100002i/16
0: 1 1: 0.3162 2: 0.1 3: 0.03162 4: 0.01 5: 0.003162 6: 0.001 7: 0.0003162

第 p 个座位、第 k 维的值:
k 是偶数 → sin(p × ωk/2)   k 是奇数 → cos(p × ω(k−1)/2)
例:座位 7、第 0 维 → sin(7 × 1) = sin(7.000000) = 0.656987

转了多少圈 = 最大座位号 × ωᵢ ÷ 2π:
第 0 对:31 × 1 ÷ 6.283185 = 4.9338
7 对:31 × 0.0003162 ÷ 6.283185 = 0.16% 圈

最快的比最慢的快 1 ÷ 0.00031623162

这就是「位置编码」。第 2 站那个「座位号」是一个数、处处一样; 这里是一整串有快有慢的数,每一维的节奏都不同。 而且它是算出来的——不需要训练、不占任何参数, 座位号给多大就现算多大。

最要紧的是:32 个座位,32 张指纹,没有两张是一样的。 最接近的两个座位(34)也差着 1.0147;离得最远的(028) 差着 3.5090—— 是前者的 3 倍多。 所以模型只要看一眼指纹,就知道这是第几个座位。

第 4 站

指纹怎么塞进词向量

位置有了,接下来是纯粹的工程问题:这张指纹,怎么和那个字的 8 个数合起来?三条路摆在眼前——逐位相加、拼接座位号、拼接整张指纹。下面把它们并排摆出来。 (演示里指纹缩到 4 对、8 个数,好跟 8 维的词向量一格对一格地摆; 真实模型里两张表都是 3,584 个数,道理完全一样。)

核心实验加法还是拼接 —— 三条路的宽度和结果,当场比
座位号
词向量 E
-0.29-0.100.84-0.92-0.02-0.39-1.290.91
+
位置指纹
0.660.750.640.760.071.000.011.00
结果
0.370.651.48-0.160.050.61-1.281.91
」在第 7 个座位,位置部分逐位相加: 结果宽度是 8(演示规模)/ 3,584(Qwen2.5-7B 的 3,584 维)。
加法:宽度一个数都不变(3,584),位置和内容挤在同一个位置里;拼接座位号:宽度变成 3,585,多出 1 个数;拼接整张指纹:宽度翻成 7,168,多出 3,584 个数。宽出来的每一维,后面每一层、 每一个矩阵都得跟着加宽 —— 这就是「拼接」看起来更干净、却没人用的原因。
👆 换三种写法看看「结果」那一行的宽度和数字。加法那一行是逐位相加, 拼接那两行是原样接在后面(所以前面 8 个数一个都没变)—— 这也是为什么加法卡里座位 0 的指纹(0.001.00…) 加进去之后,结果看起来「只是把词向量抬了一点」。
加法:8 个数 → 8 个数(宽度一个都不变)。拼接 1 个数:→ 9。 拼接整张指纹:→ 16。换成 Qwen2.5-7B 的 3,584 维, 就是 3,584 / 3,585 / 7,168
图 5-4 · 加法是「逐位相加、宽度不变」;拼接是「原样接在后面、宽度变大」

拼接看起来更干净——位置和内容分开放着,互不干扰,多好。 可真实模型(GPT、Qwen、Llama……)用的全是加法。为什么?

位置向量是上去的——那不就等于把原来的词向量搅浑了吗?模型还能分得清哪部分是字、哪部分是位置?
面试常问 · 位置编码为什么是「加」而不是「拼」
  • 加法不涨宽度[T, 3,584] 加完还是 [T, 3,584],后面每一层的形状都不用改。 拼接会变成 [T, 7,168],全网络跟着加宽。
  • 不需要「分开放」:模型的每一层都在做加法和点积, 它要的是「可区分的数」,不是「可还原的原文」。 位置信息只要能让同一批字在不同位置长出不同的向量就够了。
  • 实验结论一致:加法和拼接在效果上各有胜负、没有稳定优势, 而加法更省 —— 工程上这就足够定案了。
  • 代价要知道:加完之后向量的长度被抬高了(指纹的值最大到 1), 所以很多实现会把它按一个系数缩小一点再往里加。
第 5 站

为什么偏偏是 sin / cos

到目前为止,指纹满足的要求只是「32 个座位不重样」。这件事随机数也能做到—— 随便生成 16 个数当作指纹,32 个座位几乎不可能撞上。那为什么全世界的模型都用 sin 和 cos?

因为 sin/cos 多给了一样随机数给不了的东西。回头看那些「快慢不同的指针」: 座位往后挪几步,每根指针就整体转几度。 而这个转过的角度,跟起点在第几个座位毫无关系—— 只跟「隔了几步」有关。

招牌动画指针转盘 —— 拖动起点座位,看夹角数字变不变
起点座位 p11
相隔现在看的是:从座位 11 到座位 12
0 对指针
ω = 1(每挪 1 个座位转这么多弧度)
57.2958°
转角 = 1 × ω = 57.2958°
1 对指针
ω = 0.3162(每挪 1 个座位转这么多弧度)
18.1185°
转角 = 1 × ω = 18.1185°
2 对指针
ω = 0.1(每挪 1 个座位转这么多弧度)
5.7296°
转角 = 1 × ω = 5.7296°
浅色 = 起点座位 11 的指针深色 = 终点座位 12 的指针圆弧 = 这两根指针之间的夹角
第几对起点 01起点 1112起点 2526三个起点一致?057.2958°57.2958°57.2958°✓ 完全一致118.1185°18.1185°18.1185°✓ 完全一致25.7296°5.7296°5.7296°✓ 完全一致
拖「起点座位」:三根指针一起转,但每一格印出来的转角一动不动 —— 它只认「隔了几步」(k = 1)和「是第几对」,跟起点在第几个座位毫无关系。 三个起点(0 / 11 / 25)量出来的差距是 0.0000°
这就是 sin/cos 敢当位置编码的真正理由:它把「隔了几步」编码成了一根指针转过的角度。模型只要学会「看夹角」, 就等于学会了「看这两个字离多远」—— 语言里要紧的从来不是「这是第 7 个字」, 而是「这两个字隔了几个」。
👆 最快的第 0 对隔 1 个座位就转 57.2958°, 第 1 对只转 18.1185°、第 2 对 5.7296° —— 快的那几对分辨「挨着的差别」,慢的那几对兜底「离得远的差别」。 点「▶ 自动扫座位」看指针一路转下去,注意看:夹角数字一直不变
三台转盘是第 0 / 1 / 2 对指针(转得最快的那三根)。浅色是起点座位的指针, 深色是终点座位的指针,圆弧就是它们之间的夹角。 拖「起点座位」:指针一起转,夹角数字一动不动; 点「换成随机指纹」再拖一次 —— 同样的动作,数字立刻乱跳。
图 5-5 · 换起点,指针整体转、夹角不变;换成随机指纹,夹角就跟着起点跑了

下面这张表把上面那件事一格一格量出来:三个不同的起点、三根快慢不同的指针, 每一格都是从两个座位的 (sin, cos) 反推出来的夹角。

核心实验相对位置 —— 换起点,转角不变
相隔
第几对角频率 ωᵢ座位 23座位 1112座位 2829理论值 1×ωᵢ0157.2958°57.2958°57.2958°57.2958°10.316218.1169°18.1169°18.1169°18.1169°20.15.7296°5.7296°5.7296°5.7296°30.031621.8117°1.8117°1.8117°1.8117°40.010.5730°0.5730°0.5730°0.5730°50.0031620.1812°0.1812°0.1812°0.1812°60.0010.0573°0.0573°0.0573°0.0573°70.00031620.0181°0.0181°0.0181°0.0181°
每一格是这么来的:把这两个座位在第 i 对上的两个数(sin, cos) 各取出来,反推「从前者转到后者一共转了多少度」 (就是这两个二维指针的夹角)。同一行三个格子的数完全一样 —— 换起点、换距离,角度只跟着「隔了几步」和「是第几对」走。
比如第 0 对(ω = 1,转得最快):座位 2 的 (sin, cos) 和座位 3(sin, cos) 之间, 夹角就是 57.2958°; 换成座位 28 和座位 29,夹角还是 57.2958°
这就是 sin/cos 敢当位置编码的真正理由:它天生带相对位置。 模型只要学会「看夹角」,就等于学会了「看这两个字隔了几个座位」—— 跟它们从第几个座位开始压根没关系。这件事随机数做不到: 随机数只能保证 32 个座位不重样,但它不保证「第 5 个和第 8 个之间」和 「第 20 个和第 23 个之间」有什么关系。
👆 角频率越小的对,转角越小:最快那一对隔 1 个座位就转 57.2958°,最慢那一对隔 31 个座位也只转 0.5616°。 所以「挨得近」的差别主要由快的那几对负责,「离得远」的差别靠慢的那几对兜底 —— 一列快慢不同的指针,合起来就能分辨跨度很大的距离。
表里每一格是把两个座位的 (sin, cos) 取出来、反推出来的夹角。同一行三个格子的数完全一样——座位 2 到 5、座位 11 到 14、座位 28 到 31, 隔的都是 3 步,转过的角度就都是同一个数。
图 5-6 · 第 i 对的转角 = ωᵢ × 相隔的步数;换起点、换距离,这个式子始终成立

这件事的意义比它看起来大。语言里最要紧的位置信息从来不是「这是第 7 个字」, 而是「这两个字离得多远」。而这套指纹把「隔了几步」 直接编码成了一个可以算出来的角度:模型只要学会「看夹角」, 就等于学会了「看距离」,跟它们从哪儿开始没有关系。

面试常问 · 正弦位置编码到底好在哪
  • 不占参数:一个座位一个公式,位置给多大就现算多大, 参数表里一个数都不用存(对比下一站那张 3,670,016 个数的表)。
  • 天生带相对位置:第 i 对 (sin, cos) 是个单位圆上的指针, 相隔 k 步就是「转 k × ωᵢ 弧度」。这句话对任何起点都成立 —— 这是它从一堆候选方案里胜出的真正原因。
  • 快慢搭配:最快那对隔 1 步就转 57.30°, 最慢那对隔 1 步只转 0.0181°。8 对一起看,从「挨着的两个字」到「隔几十个字」都有分辨力。
  • 起伏有界:每一维都在 ±1 之间,加进词向量里不会把某一维撑爆 —— 第 2 站那个只认位置的 8 × p × q 再也不会出现,位置项再也压不死内容项。
第 6 站

位置这块,账有多大

位置编码听上去是件小事——16 个数而已。可它牵着两笔大账:一句话有多长,模型就要付多大的代价。 第一笔是第 4 课算过的注意力分数表,第二笔是位置本身怎么存。

核心实验上下文长度的账 —— 表是 T × T,不是 T
512
262,144× 0.25
1,024
1,048,576(基准)
4,096
16,777,216× 16
32,768
1,073,741,824× 1,024
横条按对数刻度画(每长一格 = 乘 10),因为最小的 26 万和最大的 10.7 亿差了 4096 倍 —— 线性刻度下前三条会细成一根线。格子数本身是 T × T,是算出来的,不是估计的。
选中的是 1,024 个 token:注意力分数表是 1,024 × 1,024 = 1,048,576(本课统一的「一句话」尺度,约 104.9 万格)
一句话从 1,024 拉到 32,768,长度只涨 32 倍,可这张表要涨 1,024 倍(32 的平方)—— 1,073,741,824 格,十亿出头。「长上下文为什么贵」的账,全在这个平方里。
正弦公式(本课这套)
0 个参数
每个位置现算。位置 100 万也能算出来,不用存任何东西 —— 但模型在训练长度之外会「没见过」,表现照样会掉。
可学习的位置表(GPT-2 那套)
367.0 万个数
一个位置一行:1,024 行 × 3,584 维,一共 3,670,016 个数。位置 1,025 没有对应的一行, 超出直接没得查。
现在的模型走的是第三条路:RoPE —— 不「加」位置,而是把位置当成一个旋转, 直接转 Q、K 两串数;ALiBi 则在注意力分数上减一个「隔得越远扣得越多」的偏置。 它们都继承了本课那套正弦花纹的脾气:算出来的、没有参数、天生带相对位置
分数表是 T × T:一句话 1,024 个 token 是 1,048,576 格, 拉到 32,768 个就变成 1,073,741,824 格 —— 长度只涨 32 倍,表涨 1,024 倍。 右边那张卡是可学习位置表的账:1,024 行 × 3,584 维 = 3,670,016 个数;正弦公式是 0 个。
图 5-7 · 横条按对数刻度画;格子数 T × T 是算出来的,不是估的
两笔账分别是怎么算的
① 注意力分数表(第 4 课那张「谁像谁」的表):T × T
1,024 × 1,024 = 1,048,576
32,768 × 32,768 = 1,073,741,824 格(≈ 10.7 亿)
倍数 = (32,768 ÷ 1,024)² = 32² = 1,024

② 可学习位置表(GPT-2 那套):1,024 行 × 3,584 维 = 3,670,016 个数
换算过来是 367.0 万个数; 正弦公式这条路上,这个位置上是 0

两个数一起看,就能明白为什么现在的模型都在「怎么把位置做得更省、更长」上下功夫:表是平方长大的,位置表是按长度线性长大的,而用户永远想要更长的上下文。

面试常问 · 现在的模型还在用这套 sin/cos 吗
  • 正弦公式(本课这套):算出来的、无参数、按公式可以外推到任意位置。 但模型在训练长度之外仍然是「没见过」,表现会掉。
  • 可学习的位置表(GPT-2):一个位置一行,共 3,670,016 个数。 简单直接,可位置一旦超出表长就没有那一行了 —— 硬上限。
  • RoPE(现在的默认答案):不「加」位置,而是把位置当成一个旋转, 直接 Q、K 两串数。它继承的正是本课第 5 站那条性质: 两个向量点积只跟「相隔多少步」有关。Qwen2.5、Llama 用的都是它。
  • ALiBi:更省事,干脆不给向量加东西,直接在注意力分数上减一个 「隔得越远扣得越多」的偏置。它的思路也是「看重距离、不看重绝对位置」。
第 7 站 · 收官

把这一课钉在墙上

本课核心 · TAKEAWAY

自注意力只认「谁像谁」,天生看不见顺序——同一批字换个摆法, 它拿到的东西一个数都不差。补的办法是给每个座位发一张指纹8 根快慢不同的指针,每一根提供 sin / cos 两个数, 合起来 16 个数。快的那几对分辨「挨着的差别」,慢的那几对分辨「离得远的差别」, 从最快到最慢跨了 3162 倍。 这张指纹是算出来的,不占参数;它最大的好处是天生带相对位置——座位往后挪几步,指针就整体转几度, 转角只跟「隔了几步」有关。用的时候逐位加到词向量上(不是拼接:拼接会把宽度从 3,584 撑到 7,168, 后面每一层都得跟着加宽)。代价也要认清:一句话的长度 T 一涨, 注意力分数表就按 涨 —— 1,02432,768 就是 1,024 倍。

这一课你亲手做完了

  • 看见顺序丢了:「十五」和「五十」、「三加五」和「五加三」—— 输入矩阵只是换了行序,两两打分的表逐个相等
  • 试过最笨的塞法:座位号直接加,展开后 8 × p × q 这一项只认座位、不认字, 最大 7,688,是内容项的 591 倍。
  • 发过指纹32 个座位 × 16 个数 = 512 格、8 对快慢不同的指针,最快的转 4.93 圈、 最慢的 0.16% 圈,32 张指纹没有一张重复。
  • 比过三条路:加法 8 个数不变、拼接座位号 9 个、 拼接指纹 16 个;换成 3,584 维就是 3,584 / 3,585 / 7,168
  • 量过相对位置:座位 2→5、11→14、28→31 隔的都是 3 步, 转过的角度一模一样 —— 表里的角度里根本没有「在第几个座位」。
  • 算过两笔账:分数表 T²(1,02432,768 1,024 倍),可学习位置表 3,670,016 个数、正弦公式 0 个。

学习小测验

已完成 0 / 60.0%答对 0
还没提交过 —— 每题先选一个选项,再点「提交」,答完就能看到诊断。
Q1为什么非要有「位置编码」这样东西?
Q2把座位号当成一个数,直接加到词向量的每一维上,出了什么问题?
Q3正弦位置编码里,第 2i 维和第 2i+1 维是一对 (sin, cos)。这一对最要紧的性质是什么?
Q4真实代码里,位置向量和词向量通常怎么合起来?
Q5如果像 GPT-2 那样,把位置编码做成一张「可学习」的表,1024 行 × 3584 维要占多少个数?
Q6一句话从 1,024 个 token 变成 32,768 个,注意力分数表大约涨多少倍?
NEXT · 第 6 课

自注意力:Q K V

到这儿,Transformer 拼装前的零件齐了:向量(第 2 课)、查表(第 3 课)、 批量点积(第 4 课)、位置(这一课)。 下一课把它们装成第一个真正的机制——自注意力:一句话里的每个字,凭什么知道该多看谁一眼? 我们会把 Q、K、V 三个角色摆上台,用第 4 课那张分数表算出「该看谁」, 再用它把信息收集起来。这一课发的指纹,第一个要去的地方就是那里。

从零手册 —— 下一课:自注意力:Q K V