04 课 · 矩阵乘法
LESSON 04 · 卷四 矩阵登场

一次算完一整批点积

第 2 课你手里有一把尺子:量两个向量像不像,量出来是一个数。第 3 课表上挂着 20 个字, 每个字 8 个数。现在问一句最朴素的话——20 个字里,谁跟谁像?连自己算上,这张表是 400 个格子;把句子换成 1,024 个 token, 同一张表会涨到 1,048,576 个格子。这一课我们就干一件事: 把「一个点积」升级成「一次算一整批点积」。

STAGE 01
一条规则
行 · 列,把点积排成方阵
STAGE 02
形状
左边几列,右边就得几行
STAGE 03
一次算完
400 个点积、3,200 次乘法
STAGE 04
查表落盘
one-hot 取一行;1448 字节的真模型文件
第 1 站

一条规则,把点积排成方阵

第 2 课的尺子一次只量一对向量。要给 20 个字排一张「谁像谁」的表, 就是把 190 对统统量一遍——写两个循环,不难,也不慢。

所以问题不在「算不算得完」,而在怎么把这件事一次交出去。 显卡不会一个数一个数地帮你算;它最擅长的是「同样一个动作,成千上万份一起做」。 我们需要的是一种能把一整批点积打包成一个动作的写法。

写两层循环也能算完这 190 对,那为什么还要专门发明一套「矩阵乘法」的写法?它到底省了什么?

现在把「行点列」这条唯一的规则钉死。看一个能手算的例子: A 是 23, B 是 32, 结果 C 是 22。 点右边结果表里的任意一格,看它是怎么来的:

核心实验矩阵动物园 —— 点一格,看是哪一行和哪一列点出来的
123456
A · 2 行 3 列
×
789101112
B · 3 行 2 列
=
C · 2 行 2 列
A 的第 0B 的第 0它们点一下,就是 C 的第 (0, 0) 格
C 的第 (0, 0) 格 = A 第 0 行 · B 第 0 列:
1 × 7=7+2 × 9=18+3 × 11=33
加起来 = 7 + 18 + 33 = 58
就一条规则:左边那一行右边那一列一对一乘完再全部加起来。 C 里每一格都这么算 —— 比如 (1, 0) 那格是 4 × 5 × 6 各自乘 7 × 9 × 11 再相加 = 139
👆 点右边结果表里的任意一格,看它是哪一行和哪一列点出来的。 注意 A 是 2×3、B 是 3×2,结果却是 2×2 —— 不是 3 也不是 6。
就一条规则:结果第 (i, j) 格 = 左边第 i 行 和 右边第 j 列 的点积。 逐项相乘、全部相加——和第 2 课那把尺子分毫不差,只是位置从「两个向量」换成了「一行一列」。
图 4-1 · A[2,3] · B[3,2] = C[2,2];四个格子全是整数,可以心算核对

比如 C 的 (1, 0) 格:A 第 1 行是 4, 5, 6, B 第 0 列是 7, 9, 11, 一一相乘再相加,得到 139。 这就是「矩阵乘法」的全部:把一堆点积排成一张表,一次性报出来。

请注意你刚刚做了什么——
你把一个动作
写成了一张
术语 · 一张表就叫一个「矩阵」

23 列的方阵,写成 [2, 3], 读作「23」。第 3 课那张嵌入矩阵就是 [20, 8]——20 行(20 个 token),每行 8 个数。行是「哪一个」,列是「哪一维」,这个方向感后面每一课都会用到。

矩阵乘法写成 A · BA @ B(代码里写 A @ B)。 它不满足交换律:A · BB · A 通常不是一回事, 甚至连形状都不一样。这一点第 3 站你会亲眼看到。

第 2 站

形状:左边几列,右边就得几行

规则一句话讲完了,可它藏着一个前提:「行点列」要求两串数一样长。左边那一行有几个数,右边那一列就必须有几个数——否则点积根本配不成对。

这条要求翻译成形状,就是整件事最要紧的一句话: 左边有几列,右边就得有几行。下面这台机器,四个数字随便你改:

核心实验形状计算器 —— 改四个数,看能不能乘、结果是多大
左边那张
×
20 行,每行 8 个数
·
右边那张
×
8 行,每行 20 个数
8 = 8里面这两个数必须一样 —— 因为「行点列」要求两串数一样长
✅ 能乘。结果是一张 20 × 20 的表,一共 400 个格子。 每个格子要做 8 次乘法、7 次加法,所以总共 3,200 次乘法、2,800 次加法。
400 个格子 —— 太多了,画不出来。真实的注意力分数表就是这个量级: 一句话 1024 个 token,表就是 1024 × 1024,一百多万个格子,一格都不能省。
20 个字的相似度表:左边的形状 (20, 8), 右边的形状 (8, 20) —— E 乘 E 的转置
👆 四个数字都能改。试试把左边第二个数改成别的 —— 它会立刻告诉你乘不了。
三个真实用例都在按钮里:查一个字的向量是 [1,20]·[20,8]、相似度表是 [20,8]·[8,20]、一层注意力的分数表是 [1,024,3,584]·[3,584,1,024]。 最后一个按钮是故意错的:中间那两个数不一样,当场被拦下。
图 4-2 · 结果的形状只看两头(左行 × 右列),中间那个数被「吃掉」——它只决定每格做多少次乘法
面试常问 · 「形状对不上」到底是什么
  • 能不能乘[m, k] @ [k, n]——中间那个 k 必须相等,这是唯一的条件。
  • 结果多大[m, n]。只抄左边几行、右边几列。
  • 算多少下:乘法 m × k × n 次,加法 m × n × (k−1) 次。 我们的表是 3,200 次乘法;换成真实模型就是 3,758,096,384 次。
  • 为什么显卡快:结果里每一格互相不认识——算 (0,0) 不用等 (0,1)。 所谓「并行」不是什么玄学,就是「这批格子之间没有先后关系」。

最后一句话值得停一下。整个 AI 硬件产业,几乎都是被「格子互相不认识」这件事养活的。如果每一格都必须等上一格算完(像第 3 课 BPE 那样,一步接一步), 再多的核心也帮不上忙;正因为这 400 个格子彼此独立, 才能几千个核心一起开工、一次算完。

第 3 站

一次算完 400 个点积

回到开头那个问题:20 个字,谁跟谁像。 每个字是 8 个数,所以嵌入矩阵 E[20, 8]。 要的不是 190 对里的某一对,而是整张 20×20 的表—— 第 (i, j) 格就是「第 i 个字」和「第 j 个字」的点积。

最直接的念头:把 E 和自己乘一下。E · E[20, 8][20, 8]—— 停一下,能乘吗?

[20, 8][20, 8]:左边 8 列、右边 20 行,两个数不相等,乘不了。可是我们想要的明明就是「E 里两行做点积」——最小的一步修补是什么?
图解推导转置 E → Eᵀ —— 点一下躺下来,拖 i、j 看点的是哪两条
E [20, 8] ──转置──▶ Eᵀ [8, 20]行 ↔ 列 互换:20 × 8 = 160 个数,一个不多、一个不少
现在左图是 E,形状 = [20, 8](图里画的是前 10 个字 → [10, 8])。 点上面的「↻ 转置」,每一格会沿对角线滑到对面,形状读数就变成 [8, 20]。
01234567?
E · 行 = 字、列 = 维度 0–7 图里是 [10, 8],真实是 [20, 8]
?01234567
Eᵀ · 行 = 维度、列 = 字 图里是 [8, 10],真实是 [8, 20]
E 的第 i 行 = Eᵀ 的第 i 列(同一串数,横的变竖的)E 的第 j 行 = Eᵀ 的第 j 列i、j 落在同一条上 —— 自己点自己(对角线那格)
行 i0 ?
列 j1
E·Eᵀ 的第 (0, 1) 格 = E 的第 0 行 · Eᵀ 的第 1 列 = 「?」的向量 · 「」的向量
也就是 E 的第 0 行点第 1 行 —— 因为 Eᵀ 的第 1 列,正是 E 的第 1
0.027200 × 1.238100=0.033676+−0.954100 × 0.497200=−0.474379+0.421200 × 0.209000=0.088031+−0.625100 × −0.804800=0.503080+−0.773900 × −0.268900=0.208102+0.294500 × 0.751800=0.221405+−0.608500 × −0.065100=0.039613+0.480200 × −0.570900=−0.274146
加起来 = 0.033676 − 0.474379 + 0.088031 + 0.503080 + 0.208102 + 0.221405 + 0.039613 − 0.274146 = 0.345382
格子里印得下两位:0.35 —— 和图 4-4 那张相似度表里的同一格分毫不差。 把 i 和 j 换个位置,这一格的数不变(点积不分先后),所以那张表是对称的。
👆 先点「↻ 转置」:右图每一格沿对角线滑到对面,形状读数从 [20, 8] 变成 [8, 20]。 再拖「行 i」「列 j」:蓝色那条在 E 里横着、在 Eᵀ 里竖着,两边是同一串数 —— 这就是「转置 = 行列互换」。最后看下面那串乘法:蓝色那一行 × 琥珀色那一列,加起来就是 E·Eᵀ 的第 (i, j) 格,也就是两个字之间的点积(相似度)—— 后面 Q·Kᵀ 干的就是这件事。 20 个字并排画不下,图里只画了前 10 个,真实是 20 个。
先点「↻ 转置」:右边那张表的每一格会沿着对角线滑到对面 —— 行变列、列变行, 形状读数从 [20, 8] 变成 [8, 20]。再拖「行 i」和「列 j」: 蓝色的那条在 E 里是横的、在 Eᵀ 里变成竖的,两边的数字一模一样; 蓝色那一行点琥珀色那一列,就是 E·Eᵀ 的第 (i, j) 格 —— 也就是「两个字之间的点积」,正好是下面那张相似度表里的一格。
图 4-3 · 转置就是「行 ↔ 列」:E[20,8] → Eᵀ[8,20],数的个数一个没变(20 × 8 = 160);Eᵀ 的第 j 列 = E 的第 j 行,所以 E·Eᵀ 的每一格都是两个字之间的点积

所以相似度表的写法就是 E · Eᵀ。一次乘法,3,200 次乘法、2,800 次加法,400 个点积全部到位。 下面这张 20×20 的表就是这么算出来的——先按「一个一个算」跑一遍,再按「一次算完」跑一遍,感受差别:

核心实验相似度表 —— 拖动、点格子,看每一格的点积怎么加出来的
已算 400 / 400一次算完用了 1 步;一个一个算要 400 步,而格子之间谁也不等谁
??
越蓝 = 点积越大 = 越像越黄 = 点积为负 = 越不像格子里的数就是这两个字向量的点积(保留 2 位小数)
」和「」的点积 = 3.459776(格子里只印得下两位 → 3.46
0.021600 × -0.285100=-0.006158+-0.305600 × -0.102300=0.031263+1.017900 × 0.837600=0.852593+-0.858300 × -0.918200=0.788091+-0.257000 × -0.015500=0.003984+-0.783400 × -0.392200=0.307249+-0.800200 × -1.291000=1.033058+0.493900 × 0.910500=0.449696
加起来 = -0.006158 + 0.031263 + 0.852593 + 0.788091 + 0.003984 + 0.307249 + 1.033058 + 0.449696 = 3.459776
照着上面这 8 个数加一遍,得数就是 3.459776 —— 一个不差。这一格就是第 2 课那个「两个向量的点积」, 只不过这里是 400 个点积一次算完:[ 20 , 8 ] · [ 8 , 20 ] → [ 20 , 20 ],一共 3200 次乘法。整张表就是模型眼里「谁和谁像」的全貌。
模型自己数出来的「最像」

整张表 400 个数里,最大的(自己和自己除外)是」和「」= 3.46—— 而且这两句话反过来也成立。互相是对方最像的一个,一共 4 对:

2.202.751.793.46

没人教过它「加」和「减」是一家人 —— 它只是在 4000 道题里反复见到这两个字出现在同一类位置, 慢慢把它们的向量挪到了一起。这张表是第 3 课那 30 万步训练的成绩单

👆 点任意一格,看它的点积是怎么由 8 个乘积加出来的。 颜色的深浅按全表绝对值最大的那个数(13.00)来定。 格子小,只印得下两位小数;摊开的算式一路保留 6 位 —— 照着一加,得数分毫不差。
这张表是第 3 课那 20 个字的成绩单:颜色越蓝说明两个字的向量越同向、越「像」; 越黄说明越反向。表格是对称的——第 i 行第 j 列和第 j 行第 i 列严格相等, 因为「a 点 b」和「b 点 a」本来就是同一个算式。
图 4-4 · 全表绝对值最大的一格(对角线,自己和自己)是 13.00; 非对角里最大的一对是「」和「」= 3.46

横着看第 12 行、第 13 行,你会看到一个不显眼但很要紧的事实: 模型自己把「加」和「减」放得很近。 这两行的向量分别是:

= [0.02, -0.31, 1.02, -0.86, -0.26, -0.78, -0.80, 0.49]
= [-0.29, -0.10, 0.84, -0.92, -0.02, -0.39, -1.29, 0.91]

没人告诉过它这两个字是一家人。它只是在第 3 课那 300,000 步「猜下一个字」里, 反复见到「加」和「减」出现在同一类位置,慢慢把它们的向量挪到了同一个方向。点积 3.46 是全表非对角里最大的一个, 而且这两句话反过来也成立:全表一共 4 对这样的「互相最像」。

另一头也很有意思:最不像的一对是「」和「」, 点积 -5.24——负数。 意思是这两个字的向量大致朝着相反的方向。

面试常问 · 这张表就是注意力的分数表

Transformer 里那句「第 i 个 token 要看一眼第 j 个 token,得多少分」, 算的就是这张表。名字换了而已:Q 乘 K 的转置,[T, 128] · [128, T] → [T, T], 一共 28 个头,每个头的宽度 12828 × 128 = 3,584。 合起来就是 [1,024, 3,584] · [3,584, 1,024]3,758,096,384 次乘法——正是第 2 站那台形状计算器算出来的数。

为什么这一步这么贵 · 一个数就够了
我们的表:3,200 次乘法
真实一层注意力:3,758,096,384 次乘法(37.58 亿)
放大倍数:1,174,405.12117 万倍

117 万倍是怎么来的?拆开看就两件事: token 多了 51.2 倍,可表是 T × T 的,要平方 → 2621.44 倍; 每个向量的宽度再多 448 倍。两下乘起来正好是 1,174,405.12

「长文本为什么贵」的答案就藏在这个平方里。一句话从 1,024 个 token 变成 2,048 个,这张表要算的乘法会变成 4 倍,而不是 2 倍。 后面讲注意力、讲 KV Cache、讲各种省显存的花招,算的都是这笔账。

第 4 站

one-hot 乘矩阵,其实就是查表

第 3 课留了一个尾巴:把 token 的编号变成向量,说的是「查嵌入矩阵的那一行」。 可为什么是「查」?如果老老实实按矩阵乘法的规则算一遍,会得到什么?

one-hot 是只有一格是 1、其余全 0 的行向量。 用它去乘 [20, 8] 的嵌入矩阵, 按规则得做 160 次乘法——其中大部分是「某一行 × 0」:

核心实验查表证明 —— 点一个字,看它怎么从 20 行里「幸存」下来
① 一个 one-hot 行向量
00010000000000000000
1 × 20 的行向量:只有第 3 格是 1,其余 19 格是 0
×
② 每格都算一遍:one-hot 的第 j 格 × 嵌入矩阵第 j 行
0123456700000000010000000020000000030.6700-0.2907-0.3149-1.04770.24170.52950.1186-0.09374000000005000000006000000007000000008000000009000000001000000000110000000012000000001300000000140000000015000000001600000000170000000018000000001900000000
19 行的系数是 0,整行都乘成了 0;只有第 3 行原样留着。
每一列加起来 ↓
③ 结果
0.6700-0.2907-0.3149-1.04770.24170.52950.1186-0.0937
④ 直接取第 3
0.6700-0.2907-0.3149-1.04770.24170.52950.1186-0.0937
③ 和 ④ 是两串一模一样的数 —— 因为另外 19 行全被 0 乘没了。 这一趟硬算一共做了 160 次乘法,其中 152 次 是在乘 0,真正的活只有 8 次。
所以「用一个字的编号去乘嵌入矩阵」这件事,数学上是矩阵乘法, 实际干的就是把那一行取出来 —— 这就是 nn.Embedding 这一层在干的事。 真实词表有 151,936 行,一次要乘 151,936 次;而取行是 0 次乘法。 两条路结果完全一样,所以没人真去乘 —— 但你必须知道它们是同一件事。
👆 点上面任意一个字,看它的那一行是怎么从 20 行里「幸存」下来的。
③ 和 ④ 是两串一模一样的数:硬算一遍直接把那一行取出来, 得到的是同一个东西。这不是巧合——因为除了一行之外,别的行都被 0 乘没了。
图 4-5 · 160 次乘法里 152 次在乘 0,真正的活只有 8
(这张表你在第 3 课见过 —— 那时它叫稠密向量表。 现在名字对齐一下:整张叫矩阵(20 行 × 8 列),单独取出来的那一行叫「某个词的向量」。同一个东西,三个叫法。)
160 次乘法里,152 次是在乘 0。152 次能不能干脆不做?
面试常问 · Embedding 到底是查表还是矩阵乘
  • 数学上:embedding = one-hot @ 权重矩阵,[1, 20] · [20, 8] → [1, 8]。
  • 实现上:按下标取第 i 行,一步到位。这是「同一个函数的两种算法」, 一个漂亮、一个快,结果逐个数相等
  • 为什么快重要:词表大小只影响「行有多少」,取一次永远只要 O(8), 再大的词表也不会让查表变慢。真实词表十几万行 × 3,584 维, 指的就是这张表的规模。

不过真实训练里,一次要查的绝不止一个 token —— 一句话 10 个 token 就是 10 行, 一个批次 32 句就是 320 行。既然 one-hot 里能写好几个 1, 那一次查好几个字行不行?行 —— 但你要先看清楚它给你的到底是什么:

扩展实验一次查好几个字 —— 写成「一行」,还是摞成「几行」?
点字把它加进这一批、再点一下移出去(最少留 1 个,最多 4 个)。 下面两条路查的是同一批字,只是「打包方式」不一样。
路线 A · 把 one-hot 合成「一条」多热向量
第 1 步写 20 个格子:这一批字的位置写 1,其余写 0
00010000100001000000
形状 [1, 20]3 个 1、17 个 0
每一列加起来 ↓
0.67-0.29-0.31-1.050.240.530.12-0.09-0.29-0.100.84-0.92-0.02-0.39-1.290.910.73-0.16-0.18-0.850.120.290.480.341.11-0.550.35-2.820.340.43-0.691.16
结果 [1, 8]3 个字的信息糊成了一条向量
路线 B · 把 one-hot 摞成「一个矩阵」
第 1 步写 3 行 × 20 列:每行只有一个 1,行和行互不干扰
000100000000000000000000000000000100000000000000100000000000
形状 [3, 20],再乘 [20, 8] 的嵌入矩阵
乘完 ↓
0.67-0.29-0.31-1.050.240.530.12-0.09-0.29-0.100.84-0.92-0.02-0.39-1.290.910.73-0.16-0.18-0.850.120.290.480.34
结果 [3, 8]每一行还是那个字自己的向量,一个都没糊
同一批 3 个字,两种写法给出两种形状
路线 A 把 3 行加成了 [1, 8] —— 它是这 3 个字的混合体, 已经不是词表里任何一个字了(想在上面「点字」那排里找一个和它对上的,找不到)。
路线 B 得到 [3, 8] —— 一行一个字,原样保留。
所以多热那条路只在「就一个词」的时候等于查表;词一多,它就把几个词揉进一行了。 真实代码里要批量查词,从来不是写多热向量,而是把编号排成一个 [3] 这样的整数列表, 让 embedding 层按下标一行行取 —— 形状该是几行,就老老实实是几行。
两条路都只碰 1 对应的那几行,17 行乘 0 的活一次都不用干 —— 这正是第 4 站那个「查表证明」铺到 3 行上的样子。
👆 上面两栏里的数都是同一批字:左栏读「加起来的一条」,右栏读「并排的 3 行」。 左栏最底下那个「=」行,就是读者把上面 3 行格子里的数加起来能得到的那一行。
同一批字、两种打包方式,形状一样、结果不一样:合成一行是把那几行加起来,摞成矩阵是每行各自保留。 点字换几批试试,看左栏那一条怎么变、右栏那几行怎么不变。
图 4-6 · 同一批字的两条打包路线:「合成一行」得到 [1, 8],「摞成矩阵」得到 [批大小, 8]
第 5 站

矩阵落在硬盘上,长什么样

到这儿,矩阵已经会算了。可还有一个问题没交代:第 3 课训出来的那两张矩阵,平时睡在哪儿?你下载一个模型,下到的到底是什么?

答案朴素得有点无聊:就是一个文件,里面一个数挨一个数地排在一条线上。第 2 课说过「模型文件就是带形状标签的大数字数组」—— 现在这句话有证据了。下面这个 1448 字节的文件, 装的就是你自己训出来的那两张矩阵(一共 320 个数), 用真实的 safetensors 格式写的:

核心实验打开一个真的模型文件 —— 三段结构、目录、字节地址
📦
models/arith.safetensors
里面装的是第 3 课你自己训出来的那两张矩阵 —— 一共 320 个数, 整个文件 1448 字节。点下面的按钮,用「读模型文件」的方式把它读回来。
这个文件只有 1448 字节:开头 8 个字节说「目录多长」, 接着 160 字节的目录(一段普通 JSON),最后 1280 字节纯粹是数字。 点矩阵里任意一格,它会告诉你那个数住在文件的第几个字节
图 4-7 · 1448 = 8 + 160 + 1280;真实 Qwen2.5-7B 是同一个格式,只是数字有几十亿个

值得记一笔的是那 3 个补位空格:目录 JSON 本来是 157 字节,补到 160 恰好是 8 的倍数。这不是洁癖—— 真实硬件读文件喜欢从整齐的地址开始,不对齐就慢。 这种「看着没用、其实救命」的细节,在系统里到处都是。

面试常问 · 为什么是 safetensors
  • 它是什么:HuggingFace 推的权重格式。结构就三段——8 字节头长 + JSON 目录 + 一长条数字, 没有任何压缩、没有任何魔法。
  • 为什么不用 pickle(.bin):老格式用 Python 的 pickle,加载时会执行代码, 来路不明的权重文件等于让你在自己机器上跑别人的程序。safetensors 只有 JSON 加裸数字,读它不会执行任何东西
  • 为什么可以只读一半:目录里写了每个张量的字节区间(就是上面表格里那一列 [起点, 终点)),所以想用哪块就只读哪块, 不用把整份权重都搬进内存。加载大模型时这一条能省下几个 GB。

到这里,「矩阵」这件事就齐了:怎么算(第 1、2 站)、算什么(第 3 站)、 怎么用(第 4 站)、存在哪(第 5 站)。下一课开始,我们就要用这些零件去拼第一个真正的机制—— 但在那之前,还需要给矩阵补上一样它现在完全没有的东西。

第 6 站 · 收官

把这一课钉在墙上

本课核心 · TAKEAWAY

矩阵乘法没有新规则,它就是第 2 课那把点积尺子排成了一张表: 结果的第 (i, j) 格 = 左边第 i 行 · 右边第 j 列。 能不能乘只看一件事——左边几列 = 右边几行;结果的形状只看两头, 代价是 m × k × n 次乘法。 它的真正价值不在省乘法,而在「一整批一起交出去」: 结果里每一格互相不认识,所以显卡能几千个核心同时开工。 一个字从编号变成向量(one-hot 乘嵌入矩阵),数学上是矩阵乘、 实际干的是取一行;而模型训练完,这些矩阵就一个挨一个地 躺在 safetensors 文件里,前面挂一段 JSON 目录说明谁长什么样。

这一课你亲手做完了

  • 一条规则:A[2,3] · B[3,2] = C[2,2],四个格子全是整数, 每个格子都摊开成一串乘法给你看过了。
  • 形状:左边几列 = 右边几行,中间那个数被吃掉;结果 m×n、乘法 m·k·n、 加法 m·n·(k−1)。改四个数字,这三笔账当场跟着变。
  • 转置:要算「E 里两行做点积」,就得把一份躺下来成 Eᵀ,[20,8] · [8,20] → [20,20]
  • 一次算完3,200 次乘法换来整张 20×20 的相似度表—— 「」和「」最像(3.46), 互相最像的一共 4 对。放进真实模型,同一个动作是 3,758,096,384 次乘法、117 万倍。
  • 查表:one-hot 乘嵌入矩阵 = 取那一行。160 次乘法里 152 次在乘 0,框架一步都不做。
  • 一个真文件1448 字节 = 8(头长)+ 160(JSON 目录 + 补位)+ 1280(数字)。每一格都能查到它住在第几个字节。

学习小测验

已完成 0 / 50.0%答对 0
还没提交过 —— 每题先选一个选项,再点「提交」,答完就能看到诊断。
Q1[20, 8] 乘 [8, 20],结果是什么形状?
Q2E·Eᵀ 这张表里,第 (i, j) 格的那个数是什么?
Q3一次矩阵乘法要做多少次乘法?
Q4拿一个字的 one-hot 去乘嵌入矩阵,实际发生了什么?
Q5显卡为什么特别适合干矩阵乘法?
NEXT · 第 5 课

位置编码:矩阵不知道谁先谁后

现在你可以把一整批点积一次算完了。可回头看看这张表—— 它只知道「哪个字和哪个字像」,一个字都没说谁先出现、谁后出现。 换句话说:把「十五」和「五十」喂给模型,它看到的是同一堆向量 (都是「十」和「五」),算出来的表一模一样。可这两个数差了 3 倍多。 下一课我们给每个位置补一个「座位号」,让矩阵第一次知道顺序—— 这是 Transformer 拼装前的最后一块零件。

从零手册 —— 下一课:位置编码:矩阵不知道谁先谁后