这个系列记录我读《从零构建大模型》的过程。不是读书笔记的摘抄,是我和每个概念搏斗的痕迹。规则只有一条:写下来的必须是我自己搞懂的,没懂的如实写"没懂"。
这一章在干什么
一句话:把离散的文本,变成神经网络能计算的连续数字。
整个第二章就在干一件事:文本 → token → token ID → 向量。我一开始小看它了,觉得不就是个分词吗。结果十几页的内容,我看了一个半小时,中途还去补了 python 和矩阵的课。
BPE:分词是一个数据压缩问题
BPE(Byte Pair Encoding)的思路比我预想的粗暴得多:
- 先把单词分到不能再分——26 个英文字母就是最初的原子;
- 统计语料里相邻对出现的频率,把最高频的对合并成新 token;
- 一路合并上去,词表就这么"长"出来了。
好处:任何不认识的单词都能被序列化(拆成熟悉的碎片就行),词表大小可控。
我想通的那个瞬间是:分词从"语言学工程"变成了"数据压缩问题"。它根本不懂什么叫"词",它只懂频率。
Embedding:我被"电流和电阻"坑了一次
这一节我栽了跟头,记个完整的纠错过程。
书里的代码把 token ID 丢进 torch.nn.Embedding,出来一个 (B, T, C) 的张量。我一开始的理解是:B 是 batch,T 是切块长度,C 是上下文长度,这个矩阵是神经网络权重的一部分,会随反向传播更新。
错了。错在把一个最基础的东西搞混了:
- Embedding 表(词表 × C 的那张表)才是权重,是"电阻",训练会更新它;
- (B, T, C) 这个张量是查表查出来的中间结果,是"电流",每次前向重新算,用完就扔。
Token ID 只是去表里查行。词表是固定的,训练更新的是表里那些数值——而且只更新这轮被查到的行。
正确的画面是:
token IDs (B,T) ──查 Embedding 表(vocab, C)──> (B,T,C) 激活
+ 位置向量广播相加
↓
进 Transformer
C 不是"上下文长度",是每个 token 的特征维度——一个数字能表达的信息太有限,升到 C 维才有地方放"这个词到底意味着什么"。
位置编码:我犯的一个可爱的错
我一开始想:要给 token 加位置信息,是不是给每个向量加一个下标,256 维变 257 维?
错的。真实做法是广播相加:每个位置的向量(T, C)直接加到 (B, T, C) 上——B 个样本共享同一份位置向量。向量里全是数字,没有谁规定哪个维度管"位置",训练过程自己会把位置信息"揉"进去。信息流 + 信息流,不是数组拼接。
顺带搞懂了:绝对位置(GPT-2 用的,在输入层加)和相对位置(RoPE,在 attention 里做)是二选一的方案。
Dataset 和 DataLoader
自己手敲实现了一遍。Dataset 负责"把整本书切成 (输入, 目标) 对",DataLoader 负责"按 batch 喂"。值得注意的是目标序列就是输入序列往左移一位——预测下一个 token,全部的秘密都在这个"移一位"里。
另外一个真实感受:矩阵运算对 for 循环是降维打击。手写循环遍历的思路,换成矩阵视角后全部消失。
今天卡住和没搞懂的
- 广播的底层我虽然接受了"就这样",但还没完全消化(留档,后面回头);
- 线性代数确实还给老师了,矩阵乘法的手感需要重新练;
- python 的语法细节磕磕绊绊,但不慌,用起来就熟了。
三问式收尾
- 今天学了什么?BPE、Embedding 表、(B,T,C)、位置编码、DataLoader。
- 哪里还没懂?广播的直觉、矩阵手算的生疏。
- 明天干什么?第三章,attention——全书真正的主角。
十几页,一个半小时,看到凌晨。慢是慢了点,但每一步都是踩实的。