从0训练LLM · 现代大模型体系 阅读+实验 ≈ 30 分钟 页内实验 ×2
C0 序章:为什么是 Transformer + 预测下一个词 第 1 课

下一个词的概率怎么算?

从数数开始:bigram
语言模型只做一件事:给「下一个词」一个概率。最朴素的算法是数数——它会在一个没见过的词对上给出 0 概率,loss 变成无穷大。

本课一问:下一个词的概率怎么算? 前文是「小王 喜欢」,下一个词是「猫」的概率是多少?是「学习」的概率又是多少?

这一课先不碰:文字怎么切成词(那是 C1 的事,这里先按空格切好);任何神经网络(从下一课开始)。这一课只用数数。

从已有出发

贯穿整门课的例句是「小明 把 苹果 给了 小王」(词已按空格切好,真实切分见 C1)。对语言模型来说,这句话就是一串「下一个词」:读到「小明 把 苹果 给了」,要给「小王」一个概率。它就在下面实验用的语料里,本课先用数数去算它。

下面是整门课要一步步搭出来的流水线。序章一个环节都还没学,所以全部是灰的——先看全貌:最右端的「softmax 概率」,就是模型对每个位置的下一个 token 给出的概率分布。一个 27B 参数的模型,输出也只是这一样东西。

从已有出发 · 累计数据流 点已学环节看形状与参数
解码层

所以「语言模型」的定义只有一句话:给前文,输出下一个词的概率。这一章回答两个问题:为什么终点是这个概率(本课与 L5),以及中间为什么是注意力(L2 到 L4)。每一代方法都在一个具体数字上失败,逼出下一代:

先把「一句话的概率」写清楚。它能严格地拆成逐词的条件概率连乘——这是概率的链式法则,不是近似:

一句话的概率 · 链式法则 + bigram 近似
= ≈ =
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
loss 定义为平均的 −ln P(每个位置一项):给真实下一个词的概率越高,loss 越低。这个 loss 就是交叉熵,深度学习地基章讲过它的曲线形状。

先自己设计:最直接的办法是数数

先自己想:手里有一小段语料,怎么算 P(猫 ∣ 喜欢)?最直接的答案是数——「喜欢」后面出现过几次「猫」,除以「喜欢」后面一共出现过几次。下面这段语料每行一句,词之间用空格隔开(句首记作 <s>、句尾记作 </s>,也各算一次):

我 喜欢 机器 学习
我 喜欢 猫
小明 喜欢 猫
小明 把 苹果 给了 小王
小王 把 苹果 给了 小明

用它给测试句「小王 喜欢 猫」打分:

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案数数:bigram 最大似然

每一步都按计数相除。句子里的词全在语料里出现过:

⚠

常见误解:「语料够大就不会有零概率。」 不会。词表有 V 个词,bigram 表就有 V² 个格子,trigram 表有 V³ 个。锚点模型 Qwen3.8 的词表 V = 248,320,trigram 表有 1.53×10¹⁶ 个格子;一份语料有多少个 token,最多就只能见到多少种三元组——即使拿 Qwen3 的全部预训练数据(36T token)来数,也最多填满 0.235%(下面的实验台现算)。剩下的格子不可能见过,最大似然全部给 0。我们自己的项目语料上有多少相邻 token 对从没见过,见实验台底部的项目实测(数字从项目数据现读)。

改进:平滑,然后撞上「相似的词不共享」

第一轮:平滑。 零概率的直接修法是「从见过的组合那里匀一点概率给没见过的」。最简单的是上面的加 k 平滑(k = 1 时叫 Laplace 平滑)。

加 k 平滑
= ( + ) / ( + )
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
k 垫得越多,没见过的组合拿到的概率越多,见过的组合被压得越低。平滑只决定「匀多少」,不决定「匀给谁」。

平滑之后 loss 有限了,但看一眼上面「改进方案」一栏:「小王」后面所有没见过的 9 个词拿到完全相同的概率 1/14。「小王 喜欢」和「小王 学习」一样可能;而「小明 喜欢 猫」明明出现过,「小明」和「小王」都是人名这件事,计数模型一点都用不上——在它眼里每个词只是表格里的一行,行与行之间没有「像不像」。

更强的平滑确实存在:Kneser & Ney 1995 的回退平滑长期是 n-gram 语言模型里效果最好的做法之一 。但它们都在「怎么匀」上做文章,解决不了「相似的词不共享统计」。

🔜

预告(C1 兑现):把每个词换成一个可学习的实数向量,让「小明」和「小王」的向量靠近,于是「小明 喜欢」的统计能迁移给「小王 喜欢」——这就是 Bengio et al. 2003 的神经概率语言模型,今天每个 LLM 的 Embedding 表都是它的直系后代。C1 的 Embedding 课会从头讲。

第二轮:窗口。 就算换成向量,「只看前 1 个词」的问题还在。改成看前 2 个、前 4 个词?计数表是 Vn 个格子,n 每加 1 就乘一次 V;锚点词表下 n = 3 已是 1.53×10¹⁶ 格。固定窗口的方法都会撞上这堵墙——下一课换一种思路:不存表格,只存一个固定大小的「状态」,一路往下传。

目标活下来了,函数换掉了。 今天的 LLM 仍然在算同一个量 P(下一个 token ∣ 前文),只是不再数数,而是用一个几百亿参数的函数去算它。n-gram 本身也没有消失,它降级成了数据工具:GPT-3 用 13-gram 重叠检测评测集是否混进了训练数据(arXiv 2005.14165 附录 C,C14 细讲);OLMo 2 用重复 n-gram 删除病态文档(arXiv 2501.00656);CCNet 用 n-gram 语言模型的困惑度给网页打分过滤(arXiv 1911.00359,C7 细讲)。

🔍 n-gram 从哪来 Shannon 1948 年的《A Mathematical Theory of Communication》§3 讨论「用统计过程逼近英语」:先按字母频率随机抽,再按双字母(digram)、三字母的转移概率抽,再换成按词频、按词与词的转移概率抽,得到的「二阶词近似」样本已经有几分像英语。「对我新 ≠ 对领域新」:bigram 不是深度学习时代的发明,它比计算机语言学还老。平滑方法里 Kneser-Ney(1995)是经典 n-gram 时代的代表作。

极小真数字:改语料、改测试句、拨 k

算法模拟器 · 真 bigram 计数(浏览器里现算)
平滑系数 k
计数表 c(前一个词, 下一个词)——行是前一个词,列是下一个词;「·」= 0 次
🎯

试三件事: ① 把测试句改成「小明 喜欢 猫」——每个词对都见过,loss 有限;再改回「小王 喜欢 猫」,看同一个位置变成 ∞。 ② 在语料里加一行「小王 喜欢 猫」,看计数表里那一格从红框变绿框。对计数模型来说,唯一的补救是「见过」。 ③ 把 k 从 0 拨到 1,再拨到 0.01:看「小王」那一行所有没见过的词始终拿同一个概率——k 只改变「匀多少」,不改变「一视同仁」。

⚠

常见误解:「平滑之后问题就解决了。」 平滑只保证 loss 有限。实验台里把 k 拨到 1,「小王」后面没见过的词全部拿到同一个概率:平滑会平均分,不会类比。它和训练过的小 Transformer 在同一个验证集上差多少,L5 的基线阶梯会用我们自己的项目数据排出来。

证据三问

问本课的回答(以「平滑」为例)
① 它解决什么问题?没见过的组合 P = 0,整句 loss = ∞
② 数学上为什么可能有效?把一部分概率挪给没见过的格子,每一项都大于 0,−ln 就有限;但「挪给谁」一视同仁,不知道谁像谁
③ 实验上为什么被选中?不同平滑在真实语料上比出来,Kneser-Ney 胜出;没有定理说它最优

本课每条结论的证据等级:

结论证据等级依据
一句话的概率 = 逐词条件概率连乘可证明 概率论
只看前 1 个词是一个假设理论动机 建模选择
bigram 的最大似然 = 计数相除可证明 最大似然推导
没见过的组合让整句 loss = ∞可证明 定义
语料再大也填不满三元组表可证明 计数
平滑能改善 n-gram 的效果实验验证 Kneser & Ney 1995

一句话

📌

语言模型只做一件事:给下一个词一个概率。数数能算出它,但没见过的组合概率为 0,loss 就是无穷大。

🚦

先停在这里:记住「数数能算概率,但没见过就是 0」即可,进 L2。
再深一层:展开上面「n-gram 从哪来」的 Dig;或在实验台底部看我们自己的语料上,验证集有多少相邻对训练集里从没出现过。

下一个缺口

平滑把 0 抹平了,可计数模型只看前 1 个词。「小明 把 苹果 给了 ___」——要猜出「小王」,至少得记得 4 个词之前的「小明」;加大窗口又会撞上 Vⁿ 的墙。怎么记住任意长的历史? → L2 · 怎么记住任意长的历史

另一个悬而未决的疑问——「小明」和「小王」像不像——将在 C1 的 Embedding 课兑现(C1 · 文字怎么变成数字)。

你可能会问

这一课还没有真实提问记录(问答会归档到 05-问答记录/)。先列几个最常见的: