大模型数学速成(01):张量、维度与「列 = token」
你在文档里看到 [768, 1024],第一反应可能是:768 是行还是列?1024 是 token 数还是特征维?PyTorch 教程写 [batch, seq, hidden],推理引擎源码写 [n_embd, n_tokens]——同一套数据,括号顺序不同,读错维度后面所有公式都会对不上。
这一篇只解决一件事:在本系列采用的约定下,张量形状怎么读、矩阵图怎么画、常见运算后维度怎么变。 搞懂它,后面矩阵乘法、Q/K/V 投影才有共同语言。
这是「大模型数学速成」系列的第 1 篇。建议先读 第 00 篇:读 Transformer 前需要哪些数学?。下一篇我们讲 矩阵乘法——神经网络的「基本变换器」。
一、什么是张量?
在深度学习里,张量(tensor) 就是存放数字的多维数组。维度越高,结构越丰富,但读法有统一套路:
| 维度 | 生活类比 | 大模型中的例子 |
|---|---|---|
| 1D 向量 | 一行成绩:[语文, 数学, 英语, …] |
某一个 token 的 768 维 embedding |
| 2D 矩阵 | Excel 表格 | [n_embd, n_tokens] 整段序列的表示 |
| 3D 张量 | 一摞 Excel 表 | 多头注意力里「每个头一张表」 |
不必被「张量」这个词吓到——你可以暂时把它当成「带形状说明的多维数组」。形状写在中括号里,例如 [768, 1024],两个数字分别描述两个方向上有多少格。
二、本系列的维度写法
文档中频繁出现类似 [n_embd, n_tokens] 的标注:
1 | [n_embd, n_tokens] |
典型 LLM 配置下,$n_{\text{embd}} = 768$、$n_{\text{tokens}} = 1024$ 表示:1024 个 token,每个用 768 维向量表示。
行与列对照表
这是读者最容易混淆的地方——不要按「第几个括号」死记,先看清楚本系列约定:
第 1 个数 n_embd |
第 2 个数 n_tokens |
|
|---|---|---|
| 矩阵术语 | 行数(纵向 ↓) | 列数(横向 →) |
| 含义 | 每个 token 的特征有多少维 | 序列里有多少个 token |
| 图中方向 | 每一行是一种特征分量 | 每一列是一个 token |
ASCII 矩阵图
1 | 列 → (第 2 维 n_tokens,token 个数) |
关键约定:列 = token。 矩阵的每一列对应一个 token,列里的 $n_{\text{embd}}$ 个数字就是该 token 的特征向量(embedding)。
形象类比:参会者档案表
把每个 token 想象成一位参会者,他的「个人档案」有 768 个字段(身高、体重、爱好……)。整张表有 768 行(字段种类)、N 列(参会人数)——形状记作 [768, N]。
三、为什么是「行 = 特征维、列 = token」?
这不是随意约定,而是许多 C/C++ 推理引擎(如 ggml 系布局) 的常见存储方式:
- 形状
[n_embd, n_tokens]中,第 0 维是嵌入维、第 1 维是序列长度 - 矩阵乘法 $W \cdot X$ 时,权重 $W$ 的列数必须等于输入 $X$ 的行数(特征维),才能对每个 token 的列向量做变换——第 02 篇会详细讲「握手规则」
读源码或 GGUF 元数据时,看到 ne[0] 通常是特征维,ne[1] 通常是 token 数(具体字段名因框架而异,但逻辑顺序一致)。
四、与 PyTorch 顺序的差异
PyTorch 训练代码里,单个 batch 的张量常写成:
$$\text{shape} = [\text{batch},\ \text{seq_len},\ \text{hidden_dim}]$$
| 框架 / 场景 | 典型形状 | token 在哪一维 | 特征维在哪一维 |
|---|---|---|---|
| 本系列(2D,单 batch) | [768, 1024] |
第 2 维(列) | 第 1 维(行) |
| PyTorch(3D) | [1, 1024, 768] |
中间 seq_len |
最后 hidden_dim |
| NumPy 手算(行=样本) | [1024, 768] |
第 1 维(行) | 第 2 维(列) |
转换关系(单 batch、无转置):
- PyTorch
[1, S, H]去掉 batch 维 →[S, H](每行一个 token) - ggml 系
[H, S](每列一个 token) - 二者互为转置:$\text{ggml} = \text{PyTorch}^\top$(在去掉 batch 后)
读公式前先确认约定。 论文、框架文档、推理引擎源码可能用不同顺序。本系列一律采用
[特征维, token 数],与 第 00 篇 的符号表一致。
五、维度在运算中如何变化?
记住一条主线:大多数逐 token 运算是「按列处理」——改变每个 token 有多少维,但不改变有多少个 token(列数通常不变)。
| 运算类型 | 输入形状 | 输出形状 | 列数(token 数) |
|---|---|---|---|
| LayerNorm / RMS Norm | [768, 1024] |
[768, 1024] |
不变 |
| 残差加法 $X + Y$ | [768, 1024] + 同形 |
[768, 1024] |
不变 |
| 方阵线性层 $W \cdot X$ | [768,768]·[768,1024] |
[768, 1024] |
不变 |
| FFN 升维 | [3072,768]·[768,1024] |
[3072, 1024] |
不变 |
| FFN 降维 | [768,3072]·[3072,1024] |
[768, 1024] |
不变 |
| 注意力 $QK^\top$ | 见第 05 篇 | 中间 [S, S] |
token 间两两打分 |
用一句话概括:
矩阵乘法改变的是「每个 token 有多少维」(行数),一般不改变「有多少个 token」(列数)。
LayerNorm、残差、激活函数等同形运算,则是每个位置单独处理,输入输出形状完全一致。
六、3D 张量:多头在哪里?
多头注意力会把特征维拆成多个「头」,此时引入第 3 维:
$$[\underbrace{d_{\text{head}}}{\text{每头维度}},\ \underbrace{n{\text{head}}}{\text{头数}},\ \underbrace{n{\text{tokens}}}_{\text{token 数}}]$$
例如 $d_{\text{head}}=64$、$n_{\text{head}}=12$、$n_{\text{tokens}}=1024$:
- $64 \times 12 = 768$,与单头时的 $n_{\text{embd}}$ 一致
- 列 = token 的约定仍然成立——只是每个头各有一张
[64, 1024]的小表
第 09 篇会专门讲多头如何拆分与合并;现在只需知道:维度可以叠高,但「列 = token」不会变。
七、小结表格
| 问题 | 本系列答案 |
|---|---|
[768, 1024] 怎么读? |
768 维特征 × 1024 个 token |
| 哪一维是 token? | 第 2 维(列) |
| 哪一维是特征? | 第 1 维(行) |
与 PyTorch [B,S,H] 关系? |
去掉 batch 后互为转置 |
| 线性层后 token 数变吗? | 通常不变 |
| 线性层后特征维变吗? | 可能变(由权重矩阵行数决定) |
八、与训练 / 推理的关系
- 训练:PyTorch 用
[B, S, H]方便 batch 并行;反向传播时形状规则相同,只是多了 batch 维。 - 推理 Prefill:一次送入 prompt 的 $S$ 个 token,激活张量本质是
[H, S](或 3D 多头形式)。 - 推理 Decode:每步只来 1 个新 token,$S$ 每次 +1;列数在增长,特征维 $H$ 不变——第 11 篇 KV Cache 会用到这一点。
九、动手练习(可选)
用 NumPy 建立直觉(NumPy 默认行 = 样本/token,与本系列列 = token 相反,正好练转置):
1 | import numpy as np |
观察:X_ggml[:, j] 是第 $j$ 个 token 的特征向量;X_torch[0, j, :] 是同一个向量。
大模型数学速成系列第 1 篇完。下一篇我们讲 矩阵乘法——对每个 token 的特征向量做线性变换,以及 $W$ 与 $X$ 的「握手规则」。
系列导航
| 篇号 | 标题 | 状态 |
|---|---|---|
| 00 | 读 Transformer 前需要哪些数学? | ✅ |
| 01 | 张量、维度与「列 = token」(本篇) | ✅ |
| 02 | 矩阵乘法:神经网络的基本变换 | 下一篇 |
完整大纲见工作区 docs/MATH_SERIES_OUTLINE.md。










