跳到主要内容

从零搭一个能写字的模型 — 1 500 步里验证差距 2.69 → 1.72

这一章讲一件事: 只用「猜下一个字」这一个训练目标,怎么让一个百万级参数的小模型写出成段的话; 以及跑完之后,那一串下降中的数字该怎么读出「它在哪个档次」。

它在全书链条里的位置: 第 15–17 章备齐了零件并对照了今天的改法, 这一章把这些零件第一次组装成一个「只留写的那一半」的完整模型, 也是第 21 章一切后加工的底座。

需要的基础: 组块的四个动作(第 16 章);Pre-LN、融合注意力(第 17 章);三段式学习率(第 12 章)。

1. 先看现象:只会「接着写」的家伙,凭什么写出整场戏

给它一句「ROMEO:」,它能顺着写出罗密欧的对白——有称呼、有标点、句长都对位。 通篇没有任何一行代码写着语法——哪个字该跟在哪些字后面——或者剧情逻辑。 这些是从哪来的?这一章先把答案的一半亮出来: 来自一个朴素到近乎敷衍的训练目标。看清它,再看它在数据上一步步长大的样子。

2. 训练目标只有一句话

给前面一段文字,猜下一个字是什么。 就这么一个目标。

形式上叫自回归:每次只用左边已出现的部分算出当前的输出, 再把刚生成的那个字接到尾部、喂回自己继续猜下去1。 工程上的实现还有一个巧处:输入和目标是同一段话,只是错开一位—— 输入取前 T 个字、目标取第 2 到第 T+1 个字, 一次就能并行地练「每个位置的下一个是什么」2

书里点明了这一章的位置:在这个预训练(拿海量普通文本先练基本功的阶段,后面第 21 章的微调是在它之后) 出来的模型之上,再叠加微调、对齐与智能体能力3

全章主走查:同一句提示词,五个训练阶段
═══════════════════════════════════════════════════════════════════
输入 TinyShakespeare(莎士比亚作品集纯文本,约 100 万字符)[^4]
一份子任务:训一个 100 万个可调数的字符级小模型 1 500 步[^1]
───────────────────────────────────────────────────────────────────
§3 ① 切字:全部只拆成 65 种字符编号
§4 ② 防作弊:三角掩码挡住右边的答案
§5 ③ 开训:五个检查点的输出从乱码变成伪莎士比亚
§6 ④ 读数:1.72 在什么刻度上算好
§7 ⑤ 开写:四种取词策略各有什么毛病
═══════════════════════════════════════════════════════════════════

3. 切字的两种档位:字符级 vs 子词级

先把文字换成编号,这一步叫词元化:把文本切成最小单位、每样发一个编号。切出来的每个最小单位,行话就叫 token;后文说「词元」和说 token 是同一个东西。

书里为了演示简单用的是最省事的字符级——每个英文字符(连标点和换行)算一个单位, 全本莎剧也就 65 种4;数据按 9:1 切成训练和验证两份5

字符级的问题一眼可见:「Shakespeare」这个单词要花 11 个单位, 模型一步只能挪一个字母,长文写得又慢又难够到「词」级别的规律6; 而照单词切又会撞上另一堵墙——英文几十万、中文几百万种单词,编号表直接爆炸, 还会被没见过的生词卡死6

主流大模型取中间路线,这套按频次合并的编码法叫字节对编码(Byte Pair Encoding,BPE)。想法朴素得可以在饭桌上讲完7:

① 开局把每个字符当独立单位
② 统计语料里所有相邻搭配的出现次数
③ 把次数最高的那对合并成新单位
④ 回到 ②,直到编号表攒够目标大小

书里在前 1 万字符上真跑了这套流程,打印出的前几次合并依次是: (t,h)、(th,e)、(o,u)、(a,t)、(r,e)……8 注意顺序:「th」先成形、「the」随后才轮到——这就是合并只认当下最高频那对的贪心增长方式9。 同一个词在不同合并轮数下的切片长度10:

合并轮数Shakespeare 被切成单位数
0 次S·h·a·k·e·s·p·e·a·r·e11
10 次S·h·a·k·e·s·p·e·a·re10
30 次S·h·a·k·es·p·e·a·re9
100 次S·h·ak·es·pe·are6

高频短词(the、you、and)很早就并成一整个单位,低频长词切成「主干 + 词缀」式碎块—— 编号表可控,常用前后缀还能复用10。真实的 BPE 编号表有 5 万到 10 万条, 靠数百 GB 语料学出来11;工业界的分词——专门干「切字发编号」这件事的工具,如 SentencePiece、Tiktoken——都是这条路12, 还有一条从 GPT-2 开始流行的变体:先把文本转成原始字节流再合并,从此任何字符都发得出编号, 代价是中文一个汉字平均要占 2 到 4 个单位13

插一句跟 65 有关的账,第 6 节要用: 这一小节的「65 种编号」不只是切法的副产品—— 它同时决定了「什么都不学的模型」起点该是多差,这是全章读数字的地基。 这笔账当场就算给你看,在第 6 节。

主走查之外的一眼:现成的合并器长什么样

补充(不在书里,依据我们的 frontier 书架):BPE 教学实现每一轮选对的依据写在循环体里。 依据: shelf=ai-frontier-reference/minbpe@src:minbpe/basic.py:35 @1acefe89412b20245db5a22d2a02001e547dc602 事实=pair = max(stats, key=stats.get)——对统计出的相邻搭配频次表取最大值所在的键,正是「每轮挑最高频那一对」这行字对应的源码本体。

4. 防作弊:只许看左边的三角掩码

第 17 章预告过那条约束,现在它是承重墙了:训练时若不加限制,自注意力会看到未来——每个位置直接抄右边那句的答案,损失会很漂亮,模型什么都没学14。 所以输入端套上一块三角形的屏蔽:第 i 行只放开前 i 个位置,右侧全部置成极小值,归一化后权重恰好为零。

其余三个工程决定都直接沿用第 17 章那张对照表:层规范化摆在直连边之前(更稳的那种摆法)15、 位置信息用一张可学习的查表(小语料上比固定曲线灵活)16、 每个组块内部仍是「规范化→注意力→加、规范化→前馈→加」17。 唯一的结构新意是把三份投影合成一个大矩阵一次乘出来(q、k、v 共用一个线性层)18, 前馈层的激活也换成了 GPT 同款的光滑曲线版(GELU,比折线更平滑的非线性)19

5. 主走查:1 500 步,五个阶段的生长记录

模型规格书里给了原话:约 200 行代码、约 1M 参数1,对应配置如下20:

上下文长 64 字符 · 批 32 条 · 4 层 × 4 头 × 128 维 · 暂退率 0.1
AdamW(权重衰减 0.1,动量两枚 0.9 / 0.95)[^22]
学习率三段式(第 12 章预告的那套):前 100 步从 0 线性升到 3e-3,
之后按余弦滑落到 1e-4 —— 这就是三段式步子在真实训练里的样子[^23]
数据批的取法:随机抽 32 个起点,各截 64 字符,
目标串整体向右错一位[^24]

CPU 上 3~5 分钟跑完,验证差距收到 1.7 附近21。 书里每隔一段把同一条提示词(发给模型的指令文本)「ROMEO:」的生成结果存档,凑成一张生长记录表22:

主走查第 ③ 步 — 五个检查点(提示词都是 ROMEO:,各生成 120 字符)[^26]
══════════════════════════════════════════════════════════════
步 验证差 输出开头
50 2.69 ROMEO: QGVmAkmerothithisthiteJ fore theU...
← 还在学哪些字符爱扎堆,近乎随机[^27]
200 2.21 ROMEO: Thou wisst vin Fis, o apoll pund c...
← 高频小词与古英语称谓冒头,拼不成句
500 1.94 ROMEO: Thuse the phe husnesd, your cholib...
← 短词组成形(your … hand 一类),句意仍乱
1000 1.78 ROMEO: That should all in a with you a si...
← 渐有莎味:句子平顺,生造词减少
1499 1.72 ROMEO: How you netter kind, sir, for 'Cla...
← 对话格式、称呼 sir、标点都对位了[^28]
══════════════════════════════════════════════════════════════

配套的两条曲线同样值得读:损失从约 4.4 快速下滑,终点训练约 1.5、验证约 1.7; 前段两条几乎重合,后期张开约 0.2 的缝——开始轻微过拟合的迹象,书里如实点了名23

6. 这个数好不好:两头钉出刻度

1.72 单独看没有意义,得给它找参照物。两头一钉,位置就出来了24:

上限参照(乱猜) log 65 ≈ 4.17
65 种等概率选项,-log(1/65)=ln 65≈4.17
——第 05 章给二分类算的 ln 2=0.6931、三分类的 ln 3=1.0986,
是同一笔账的家族成员
起步实测 ≈ 4.4(略高于均匀基线:初始参数并非真正均匀)
下限参照(理论上限) 文本自身的不确定性折合约 0.9
数据固有的不可预测性,谁也压不穿(信息论里的熵)
本模型落点 1.72 ≈ 把不确定性压到乱猜的 41%[^31]

书里把这三层关系写得很诚实:「降到多少算好」没有绝对标准,强依赖编号表大小和数据本身的随机性; 拿这份账去衡量别的模型时,也得先问清那两个前提24

书里给了数字、也反复圈出数字的边界:五阶段表格是真跑的输出, 四条逐段解读跟着表格走2526;两端刻度(log 65 与数据熵)是信息论的结论, 拿来当尺子而不是当成绩24判断性最强的一句书里自己写了: 这个小模型学不到真正的语义,它学到的是莎翁文本的统计规律——什么字常跟什么字; 输出看着像那么回事,情节和人物行为其实是杂揉拼接;要让「像」变成「懂」, 靠更大的模型、更多的数据27

判断(我们的,不是书里的):这一章真正的交付物不是那个 1.72,是「能盯着的仪表盘」。 乱猜 4.17、理论下限 0.9、落点 1.72——有了这三个刻度, 你改任何一处(层数、上下文长、换子词切分)都能立刻知道自己是朝哪边走的。 如果错,会错在: 如果某类改进在三个刻度上都不动弹(比如只影响生成风格的采样参数), 那「仪表盘」的说法就过宽了。判据是:换任何结构参数后验证差是否必然移动—— 是,则仪表盘成立。

7. 怎么往下写:四种取词策略与其毛病

模型吐出的其实不是某个字,而是 65 个候选各自的分数。怎么从分数里挑出一个, 这一步的讲究叫解码——同一份模型,挑法不同,写出来的东西判若两人28:

四种挑法,一张看全
══════════════════════════════════════════════════════════
贪心 永远挑分数第一的那个 确定,但极易复读机
温度 先把分数除以一个旋钮 τ 再归一化抽取
τ<1 分布变尖(接近只挑第一);τ>1 变平(更敢冒险)[^33]
前k 只在分数最高的 k 个候选里归一化后抽
把长尾的低分词元整段剪掉
核采样 按分数从高到低排队,凑满累计概率 p 为止,
只在这撮里抽(行话叫 top-p)[^34]
══════════════════════════════════════════════════════════

先把两个表头名词钉住:温度——抽词前给分数统一除以的那个旋钮,调低分布变尖(接近只挑第一)、调高变平(更敢冒险)。

另一种只从分数最高的那一段里取词的口径,叫核采样——按概率从高到低排队,凑够一个累计概率 p 就收手,只在这一小撮里抽。

这个口径在接口文档里以 top-p——nucleus sampling 的参数名——的面目出现,和核采样是同一件事的两个名字。

五种挑法对着同一句提示词放在一起比,病和药都现形了29:

策略生成片段(节选)书里的诊断
贪心And the see the stand the stand of the son...典型复读机问题30
温度 τ=1.0Fathall knownly so, To the indu Ier it the proce...自然但有噪声
温度 τ=1.5Ponfer devaln if God, thoughnieves:' but Wellowd...过头了,开始造词31
前 k(k=10)They hold before hang were is to the hugh...剪掉长尾,保住多样
核采样 p=0.9Been the had to will and fair, to hast stay she...同上

温度转多紧各有一套场景口径:代码、数学题这类要准的场景用尖的(τ 最高不过 0.3), 日常对话取自然区间(0.71.0),头脑风暴才放到 1.0 以上鼓励意外组合32; 生产的常用配比是温和温度配上核采样(τ 约 0.71.0、p≈0.9)33

还有一道推断时的账必须算:上面的 generate 函数每写一个新字都要把整个前缀重算一遍—— 平方级的浪费。改进的关键观察是:每一步只有最后那个位置的查询是新面孔, 前面所有的键、值都没变——先算好、存进一块缓存(放起来备用的仓库),后面直接取用即可。

这套存法的正式名字叫键值缓存(KV Cache):每字的注意力代价从平方掉到线性,大模型推断里普遍带来 10 倍以上的提速34。 书里正文点到为止说实现在配套笔记本,但要交代:第 17 章讲的「现成实现的融合注意力」就在这件事的后半场—— 框架内置的算子把掩码、缓存后的注意力一次性做完, nanoGPT 的教学实现里同样有这一开关35

现成的加速开关长什么样

补充(不在书里,依据我们的 frontier 书架):把这个内置算子的启用条件搬到源码里看。 依据: shelf=ai-frontier-reference/nanogpt@src:model.py:64 @3adf61e154c3fe3fca428ad6bc3818b27a3b8291 事实=if self.flash: 分支下调用 torch.nn.functional.scaled_dot_product_attention(..., is_causal=True)——一体化完成缩放、因果屏蔽与 softmax,并注明用的是 FlashAttention 的 CUDA 内核;else 分支才是手写的「乘 ÷√d、贴掩码、softmax」三步。

8. 边界与局限

这一章没覆盖的:

没讲什么依据 / 为什么值得知道
并行算力(用多少计算硬件换时间)的使用全章在 CPU 上 3~5 分钟起步,显存/多卡话题超出体量21
键值缓存的完整代码正文给出复杂度账(平方→线性)后,实现指了配套笔记本34
把字符级升级成子词级留成了动手练习(换 tokenizers 库训小词表再看两项指标)36
更大的规模全书最大的模型就是这个 1M 参数的小不点,千亿级的路径只在正文一句话27

这条缝书里自己承认,也是通往下一章的门: 只会续写的东西并不听话——让它「用一句话概括《罗密欧与朱丽叶》」, 它多半接着写莎翁式独白而不是给概括37模型此刻还没有「听指令」这个能力,补齐这道工序是第 21 章第 1 节的事。

出门会撞见的名字:

  • 自回归(autoregressive) —— 第 1 节那条「猜一个、接回去」的生产线;
  • 字节对编码(BPE)、子词(subword) —— 第 2 节;工业分词器名:SentencePiece、Tiktoken12;
  • 因果掩码(causal mask) —— 第 3 节那块只许看左边的三角;
  • GELU —— 第 3 节 GPT 同款的激活函数;
  • 温度(temperature)、top-k、top-p / 核采样(nucleus sampling) —— 第 6 节3839;
  • 键值缓存(KV Cache) —— 第 6 节那道复用的账34

9. 可带走的

  1. 「猜下一个字」一个目标就够启动语言建模——自回归生产线:猜一个、接回去、再猜;
  2. 训练样本就是原文错一位:输入前 T 个、目标后 T 个,一个序列练出 T 道题;
  3. 切字三档位:字符级(教学)、BPE 子词级(工业主流)、字节级 BPE(永不遇生词,费单位);
  4. BPE 是贪心长大的:每轮只合并眼下最高频的相邻对,th 先于 the;
  5. 不给因果掩码就是开卷考试——三角形屏蔽把「看右边」的权重压成零;
  6. 数字要有刻度:乱猜 log 65≈4.17、数据熵约 0.9、本模型 1.72(压到基线的 41%);
  7. 不同步的两个数字隔着一条诊断线索:训练 1.5、验证 1.7,那 0.2 的缝就是过拟合的第一声咳嗽;
  8. 取词策略是一族旋钮:贪心复读、高温造词;生产默认是温火加核采样;
  9. 键值缓存把每字代价从平方砍到线性,推断必备(10 倍以上);
  10. 手写实现要熟,上线要用内置:融合注意力算子在框架里一行就启用 FlashAttention35

10. 原文地图

主题原书章原文位置
nanoGPT 规模与定位第10章 大语言模型与智能体text/11-ch10.txt:141(搜「约 200 行代码」)
自回归目标与错位实现第10章 大语言模型与智能体text/11-ch10.txt:180(搜「自回归」)
五步流程与后续衔接第10章 大语言模型与智能体text/11-ch10.txt:192(搜「字符级 nanoGPT」)
TinyShakespeare 语料第10章 大语言模型与智能体text/11-ch10.txt:198(搜「TinyShakespeare数据集」)
字符级 65 种第10章 大语言模型与智能体text/11-ch10.txt:199(搜「经典测试床」)
两端切分的比例第10章 大语言模型与智能体text/11-ch10.txt:223(搜「n = int(0.9」)
BPE 折中路线第10章 大语言模型与智能体text/11-ch10.txt:239(搜「折中路线」)
合并序列输出第10章 大语言模型与智能体text/11-ch10.txt:298(搜「('t', 'h')」)
贪心增长特性第10章 大语言模型与智能体text/11-ch10.txt:303(搜「贪心增长特性」)
Shakespeare 各阶段切片第10章 大语言模型与智能体text/11-ch10.txt:323(搜「merges: Shakespeare」)
真实词表规模第10章 大语言模型与智能体text/11-ch10.txt:336(搜「数百 GB 语料」)
工业统一采用子词第10章 大语言模型与智能体text/11-ch10.txt:377(搜「工业大模型则统一采用」)
字节级 BPE第10章 大语言模型与智能体text/11-ch10.txt:383(搜「永远不会 OOV」)
看未来即抄答案第10章 大语言模型与智能体text/11-ch10.txt:403(搜「直接抄答案」)
三项工程决定第10章 大语言模型与智能体text/11-ch10.txt:401(搜「几个关键的工程决定」)
qkv 合一大矩阵第10章 大语言模型与智能体text/11-ch10.txt:416(搜「合在一个矩阵里」)
组块内两次规范化相加第10章 大语言模型与智能体text/11-ch10.txt:469(搜「self.attn(self.ln1」)
GELU 注记第10章 大语言模型与智能体text/11-ch10.txt:453(搜「GPT-2 风格」)
超参一览第10章 大语言模型与智能体text/11-ch10.txt:510(搜「max_iters = 1500」)
AdamW 配置第10章 大语言模型与智能体text/11-ch10.txt:524(搜「betas=(0.9,」)
三段式学习率函数第10章 大语言模型与智能体text/11-ch10.txt:517(搜「def get_lr」)
目标错一位的实现第10章 大语言模型与智能体text/11-ch10.txt:515(搜「i+1:i+block_size+1」)
CPU 时长与终点第10章 大语言模型与智能体text/11-ch10.txt:533(搜「验证损失压到 1.7 附近」)
存档检查点第10章 大语言模型与智能体text/11-ch10.txt:556(搜「{50, 200, 500, 1000, 1499}」)
曲线两条与缝隙第10章 大语言模型与智能体text/11-ch10.txt:577(搜「轻微过拟合」)
五阶段表首行第10章 大语言模型与智能体text/11-ch10.txt:602(搜「QGVmAkmerothithisthiteJ」)
五阶段表末行第10章 大语言模型与智能体text/11-ch10.txt:610(搜「How you netter kind」)
逐段解读第10章 大语言模型与智能体text/11-ch10.txt:614(搜「几乎是随机字符」)
统计规律而非语义第10章 大语言模型与智能体text/11-ch10.txt:623(搜「学不到真正的语义」)
乱猜基线与数据熵第10章 大语言模型与智能体text/11-ch10.txt:632(搜「log 65」)
压到基线的比例第10章 大语言模型与智能体text/11-ch10.txt:636(搜「≈ 41%」)
解码策略清单第10章 大语言模型与智能体text/11-ch10.txt:643(搜「常用的几种策略各有取舍」)
任务温度区间第10章 大语言模型与智能体text/11-ch10.txt:700(搜「代码生成」)
贪心的复读机样本第10章 大语言模型与智能体text/11-ch10.txt:727(搜「the stand the stand」)
高温造词的诊断第10章 大语言模型与智能体text/11-ch10.txt:748(搜「拼造词」)
生产默认组合第10章 大语言模型与智能体text/11-ch10.txt:751(搜「默认选择」)
KV 缓存的动机第10章 大语言模型与智能体text/11-ch10.txt:754(搜「KV」)
十倍以上的账第10章 大语言模型与智能体text/11-ch10.txt:758(搜「10 倍以上加速」)
升级练习第10章 大语言模型与智能体text/11-ch10.txt:388(搜「BPE 级」)

Footnotes

  1. 出处:「第10章 大语言模型与智能体」第 140–144 段(text/11-ch10.txt:141,搜「从零搭建一个字符级 nanoGPT」)。原文:本章从最基础的语言建模任务出发,从零搭建一个字符级 nanoGPT:约 200 行代码、约 1M 参数,在 TinyShakespeare 上预训练几分钟就能生成模仿莎士比亚风格的伪文本。 2

  2. 出处:「第10章 大语言模型与智能体」第 171–188 段(text/11-ch10.txt:180,搜「自回归」)。原文:语言模型将联合分布的估计转换为给定前缀、估计下一个词元的条件分布 p(x1..xT)=∏p(x_t|x_<t);这种建模方式就是自回归(autoregressive):只能用左侧已观测的词元来预测当前词元;工程实现上是把序列作输入、错开一位的同段作目标,并行预测每个位置的下一个词元。

  3. 出处:「第10章 大语言模型与智能体」第 192–194 段(text/11-ch10.txt:192,搜「字符级 nanoGPT」)。原文:本节从零搭一个字符级 nanoGPT,按数据处理、模型构建、模型训练、模型评价、模型预测五步完整走一遍;再往后几节,会在这个预训练模型之上叠加微调、对齐与智能体能力。「预训练」的解释是我们按通行用法补的一句话。

  4. 出处:「第10章 大语言模型与智能体」第 200–201 段(text/11-ch10.txt:199,搜「经典测试床」)。原文:为实现尽量简单,采用字符级词元化:每个英文字符(含标点和换行)算一个词元,词表大小约 65。

  5. 出处:「第10章 大语言模型与智能体」第 222–224 段(text/11-ch10.txt:223,搜「n = int(0.9」)。代码:data = encode(text); n = int(0.9 * len(data)); train_data, val_data = data[:n], data[n:]——90% 训练、10% 验证。

  6. 出处:「第10章 大语言模型与智能体」第 235–238 段(text/11-ch10.txt:238,搜「中文几百万」)。原文:字符级词元化的代价显而易见:「the」要花 3 个词元、「Shakespeare」要花 11 个词元,模型每一步预测一个字符,对长文本既慢又难学到词级别语义;另一个极端的词级词元化会让词表爆炸(英文几十万、中文几百万),并且严重受未登录词(OOV)问题困扰。 2

  7. 出处:「第10章 大语言模型与智能体」第 239–245 段(text/11-ch10.txt:239,搜「折中路线」)。原文:主流大模型走的是折中路线——字节对编码(Byte Pair Encoding,BPE);核心想法:一开始把每个字符当作一个词元;在整个语料里统计相邻词元对的出现频次;把出现最频繁的那对合并成一个新词元;重复直到词表达到目标大小。

  8. 出处:「第10章 大语言模型与智能体」第 298–300 段(text/11-ch10.txt:298,搜「('t', 'h')」)。原文输出:前 10 次 merge: [('t', 'h'), ('th', 'e'), ('o', 'u'), ('a', 't'), ('r', 'e'), ('s', 't'), ('i', 'n'), ('e', 'n'), ('a', 'n'), ('i', 't')]。

  9. 出处:「第10章 大语言模型与智能体」第 302–305 段(text/11-ch10.txt:303,搜「贪心增长特性」)。原文:注意「th」先合并、「the」随后才合并——这就是 BPE 的贪心增长特性:先合并当前最高频的对,新词元再继续参与后续合并。

  10. 出处:「第10章 大语言模型与智能体」第 313–329 段(text/11-ch10.txt:323,搜「merges: Shakespeare」)与图 10.2(text/11-ch10.txt:365,搜「BPE 训练过程」)。原文打印:0 merges→11 个词元(S h a k e s p e a r e);10 merges→10(re);30 merges→9(es);100 merges→6(ak es pe are);图注补充:高频子串(the、you、and 等)很早就并成完整词,低频长词切成「主干+词缀」式子词。 2

  11. 出处:「第10章 大语言模型与智能体」第 333–337 段(text/11-ch10.txt:336,搜「数百 GB 语料」)。原文:随着合并次数增加,常见子串逐步登场,词元数量从 11 降到 6;真实大模型的 BPE 词表通常有 5 万到 10 万条,由数百 GB 语料学到。

  12. 出处:「第10章 大语言模型与智能体」第 226–231 段(text/11-ch10.txt:228,搜「SentencePiece」)。笔记框原文:真实大模型通常采用字节对编码(BPE)或 SentencePiece 做子词级词元化,词表规模一般在 5 万到 20 万之间;本章为演示简洁选用字符级;末尾部署建议复述:Tiktoken 亦属工业分词器之列(第 377 段,text/11-ch10.txt:377,搜「子词分词器」)。 2

  13. 出处:「第10章 大语言模型与智能体」第 379–384 段(text/11-ch10.txt:383,搜「永远不会 OOV」)。提醒框原文:从 GPT-2 开始,字节级 BPE 成为大模型词元化的重要路线:先把文本编码为 UTF-8 字节流,再在字节序列上做 BPE——无论英文、中文还是 emoji 都能稳定词元化、永远不会 OOV;代价是中文一个汉字平均需要 2∼4 个词元。

  14. 出处:「第10章 大语言模型与智能体」第 403–404 段(text/11-ch10.txt:403,搜「直接抄答案」)。原文:因果掩码——训练时若不加约束,自注意力会「看到未来」,等于直接抄答案;所以强制套上三角 mask,屏蔽掉每个位置右侧的所有词元。

  15. 出处:「第10章 大语言模型与智能体」第 405 段(text/11-ch10.txt:405,搜「层规范化前置到」)。原文:预规范化(pre-LN)——层规范化前置到 attention 与 FFN 之前,相比原始 Transformer 的 post-LN 更易稳定训练,是现代大模型的标准做法。(「modern 一侧详见第 17 章第 2 节」是我们的回指。)

  16. 出处:「第10章 大语言模型与智能体」第 407 段(text/11-ch10.txt:407,搜「可学习位置编码」)。原文:位置编码采用可学习位置编码,在小语料上比固定的正余弦更灵活。

  17. 出处:「第10章 大语言模型与智能体」第 395–400 段(text/11-ch10.txt:397,搜「个 Transformer Block」)。原文:整体结构为词元嵌入+位置编码;N 个组块(每组块:层规范化、因果多头自注意力、残差,以及层规范化、前馈网络(4 倍隐藏维度)、残差);末端层规范化;线性层映射到词表大小的未归一化分数。

  18. 出处:「第10章 大语言模型与智能体」第 416 段(text/11-ch10.txt:416,搜「合在一个矩阵里」)。代码注释:# q, k, v 投影合在一个矩阵里——self.qkv = nn.Linear(n_embd, 3 * n_embd, bias=False),forward 里 split(C, dim=2) 三等分。

  19. 出处:「第10章 大语言模型与智能体」第 452–455 段(text/11-ch10.txt:453,搜「GPT-2 风格」)。代码注释:nn.GELU() 处标注 # GPT-2 风格;前馈层为 Linear(n_embd,4n_embd) → GELU → Linear(4n_embd,n_embd) → Dropout。

  20. 出处:「第10章 大语言模型与智能体」第 508–510 段(text/11-ch10.txt:510,搜「max_iters = 1500」)与第 523 段(text/11-ch10.txt:523,搜「model = NanoGPT(vocab_size, block_size」)。代码:block_size=64;batch_size=32;n_layer=4;n_head=4;n_embd=128;max_iters=1500;warmup=100;lr_max=3e-3;lr_min=1e-4;实例化时 dropout=0.1。

  21. 出处:「第10章 大语言模型与智能体」第 532–534 段(text/11-ch10.txt:533,搜「验证损失压到 1.7 附近」)。原文:在 CPU 上,这个小模型大约 3∼5 分钟即可把验证损失压到 1.7 附近——足够生成出可识别的莎士比亚风格片段。 2

  22. 出处:「第10章 大语言模型与智能体」表 10.1(text/11-ch10.txt:598,搜「生成质量」)。表头约定:同一个提示词「ROMEO:」、最多生成 120 个新词元;五行的步数与 val_loss:50/2.69、200/2.21、500/1.94、1000/1.78、1499/1.72(sample_steps 定义于 text/11-ch10.txt:556,搜「{50, 200, 500, 1000, 1499}」)。

  23. 出处:「第10章 大语言模型与智能体」第 574–577 段(text/11-ch10.txt:577,搜「轻微过拟合」)。原文:左图为训练损失和验证损失随步数的变化;损失从约 4.4 快速下降,训练损失最终到约 1.5、验证损失约 1.7;前期两条曲线几乎重合,后期出现约 0.2 的小间隙——这是小模型开始轻微过拟合的迹象,但整体仍在收敛。

  24. 出处:「第10章 大语言模型与智能体」第 629–636 段(text/11-ch10.txt:632,搜「log 65」)。提醒框原文:「损失降到多少算好」没有绝对标准——强烈依赖词表大小和数据集本身的随机性;字符级莎士比亚的下限(数据熵)约 1.3 比特/字符,换算自然对数约 0.9 纳特/字符;这里的验证损失以自然对数计(与 log 65 ≈ 4.17 同制),从随机初始(约 4.4,略高于理论均匀基线)快速下降到 1.7 纳特。ln 65=4.1744 这个四位数是第 05 章第 8 节算过的同源账。 2 3

  25. 出处:「第10章 大语言模型与智能体」第 612–618 段(text/11-ch10.txt:614,搜「几乎是随机字符」)。原文四条观察的前三条:step 50 还在学「哪些字符常一起出现」,输出几乎是随机字符;step 200 常见英文小词、空格和古英语词(如 Thou)开始出现,但还拼不成合法句子;step 500 短词组初具雏形(如 your … hand),单词更像样但句意仍混乱。

  26. 出处:「第10章 大语言模型与智能体」第 619–621 段(text/11-ch10.txt:619,搜「莎士比亚味」)。原文第四条:step 1000 以后渐有「莎士比亚味」——对话格式(角色名加冒号、称呼 sir)、标点和句子长度都对了,只是仍夹杂大量生造词;表 10.1 末行(text/11-ch10.txt:610,搜「How you netter kind」)与本条对应。

  27. 出处:「第10章 大语言模型与智能体」第 623–626 段(text/11-ch10.txt:623,搜「学不到真正的语义」)。原文:要注意:这个 1M 参数的小模型学不到真正的语义;它学到的是「莎翁文本的统计规律」——什么字常跟什么字、什么句法常跟什么句法;生成的文本读起来像那么回事,但角色行为、情节都是杂揉拼接;更大的模型、更多的数据才会让「像」变成「懂」。 2

  28. 出处:「第10章 大语言模型与智能体」第 640–650 段(text/11-ch10.txt:643,搜「常用的几种策略各有取舍」)。原文:做法很自然——给一段前缀,模型输出下一个词元的概率分布,从中采样追加,再重复;「怎么采样」对最终文本风格影响巨大;列出贪心采样(每次选概率最大,确定但易重复)、温度采样(除以 τ 后再做归一化指数变换,τ<1 更尖锐、τ>1 更平坦)、前 k 采样(只在概率最高的 k 个上重新归一化)、核采样(在累积概率达到 p 的最小集合上采样)。

  29. 出处:「第10章 大语言模型与智能体」表 10.2(text/11-ch10.txt:723,搜「80 个词元」)。表:同一提示词、80 个新词元、固定种子 42 下五种策略的生成对比;各单元格片段原文照录。

  30. 出处:「第10章 大语言模型与智能体」第 727 段(text/11-ch10.txt:727,搜「the stand the stand」)。原文:贪心采样陷入重复(the stand the stand…、the son of the son)——这是贪心采样的典型问题。

  31. 出处:「第10章 大语言模型与智能体」第 747–749 段(text/11-ch10.txt:748,搜「拼造词」)。原文:τ=1.5 过头,开始拼造词(devaln、husuchoan)。

  32. 出处:「第10章 大语言模型与智能体」第 700–702 段(text/11-ch10.txt:700,搜「不容易出错」)。原文的场景清单:代码生成/数学题/事实问答 τ∈[0.0,0.3] (确定性高、不容易出错);对话/写作 τ∈[0.7,1.0];创意写作/头脑风暴 τ∈[1.0,1.5] (鼓励意外组合)。

  33. 出处:「第10章 大语言模型与智能体」第 750–752 段(text/11-ch10.txt:751,搜「默认选择」)。原文:前 k 采样/核采样剪掉低概率长尾,既保留多样性又避免明显失误,是生产环境的默认选择;常见的默认设置是 τ≈0.7∼1.0 配合核采样 p≈0.9。

  34. 出处:「第10章 大语言模型与智能体」第 754–758 段(text/11-ch10.txt:754,搜「KV」)。原文:朴素的 generate 每生成一个新词元都把整个前缀重新计算一遍——这是 O(T²) 的注意力计算;实际上每一步只有最后一个位置的 query 是新的,前面所有位置的 key 和 value 都可以缓存下来,这就是 KV 缓存(KV Cache);下一步只算新位置的 q 再与缓存的 K/V 做注意力,复杂度降到 O(T);在 GPT/Llama 等大模型推断中是必备优化(带来 10 倍以上加速);具体实现见配套 notebook。 2 3

  35. 出处:「第8章 注意力机制」第 145–147 段(text/10-ch09.txt:145,搜「scaled_dot_product_attention」)。原文(第 8 章末尾):PyTorch 2.0+ 已将 FlashAttention 集成到 scaled_dot_product_attention 里,对受支持的硬件会自动启用。书里 nanoGPT 正文的注意力是手写三分步,本章补充框把它接到现成实现。 2

  36. 出处:「第10章 大语言模型与智能体」第 387–389 段(text/11-ch10.txt:388,搜「tokenizers库」)。动手练习 10.1:把字符级 nanoGPT 改造成 BPE 级(用 tokenizers 库训一个小词表),观察验证损失和生成质量的变化。

  37. 出处:「第10章 大语言模型与智能体」第 773–777 段(text/11-ch10.txt:774,搜「并不会“听话”」)。原文(10.3 节开头):预训练完成的语言模型并不会「听话」:让它「请用一句话概括《罗密欧与朱丽叶》」,它多半会继续按训练语料的风格写莎翁式独白,而不是给出概括;要让模型学会按指令行事,需要监督微调。——此处只引现象本身,解法留给第 21 章。

  38. 出处:「第10章 大语言模型与智能体」第 679–702 段(text/11-ch10.txt:680,搜「3 种温度下的分」)与图 10.4 说明(text/11-ch10.txt:682,搜「趋于均匀」)。原文:给定固定分数向量,低温 τ=0.3 让分布更尖锐、几乎只采样最大概率;中温 τ=1.0 即原始分布;高温 τ=2.0 趋于均匀、输出更随机;直觉上低温让模型「更自信」(接近贪心),高温「更敢冒险」。τ 名称(temperature,温度)借自物理学里分子热运动的比喻。

  39. 出处:「第10章 大语言模型与智能体」第 648–650 段(text/11-ch10.txt:650,搜「累积概率达到」)。原文定义:前 k 采样——只在概率最高的 k 个词元上重新归一化采样;核采样——在累积概率达到 p 的最小词元集合上采样;后者以社区惯用名 top-p 通称。