一、先把"概率"这个词钉死
天气预报说"明天下雨概率 70%"。这个数字是怎么来的?不是气象员拍脑袋,大体上是这么算的:翻出历史上和明天气象条件相似的很多天,数一数其中有多少天真的下雨了——如果相似的 100 天里有 70 天下了雨,这个概率就报 70%。
第 1 讲说语言模型输出的是"一个概率分布",但一直没说清楚这句话具体指什么。答案和天气预报是同一个思路:“今天天气很"后面接"好"字的概率是 35%,意味着在模型见过的文本里,“今天天气很"这个开头出现过的所有地方,大约 35% 接的是"好"字。
这一讲要做三件事:把"概率分布"这个说法钉成精确的数学定义;讲清楚这个分布最朴素的算法(数数);再讲清楚怎么给"模型猜得准不准"打一个分数。
二、打个比方:一个越滚越大的计数本
想象你有一个巨大的笔记本,每次读到"今天天气很"这四个字,就翻到对应的那一页,在下一个字出现的位置画一道"正"字:
"今天天气很" 后面出现过的字:
好 正正正正正正正 (35 次)
热 正正正正 (18 次)
冷 正正 (12 次)
糟 正 (9 次)
...
读的文本越多,这个计数本就越准。要"猜"下一个字,就是把每个字出现的次数,除以"今天天气很"这四个字总共出现的次数,变成一个比例。这个比例的集合,就是一个概率分布——这正是最早的语言模型(n-gram 模型,第 1、2 讲提到过)的全部原理:不用任何神经网络,纯粹靠数数。
三、把直觉写成数学
概率分布:一个求和等于 1 的向量
给定词表 V(所有可能出现的词的集合),一个概率分布是给 V 里每一个词 w 分配一个数字 P(w),满足两条规矩:
① 每个数字都不小于 0: P(w) ≥ 0
② 所有数字加起来等于 1: Σ P(w) = 1 (对词表里所有 w 求和)
⭐ 回到第 3 讲:这不是一个新概念,概率分布本身就是一个向量——词表里有多少个词,这个向量就有多少维,只是这个向量还多了一条额外的约束(非负、求和为 1)。语言模型每一步真正在计算的,就是这样一个向量。
n-gram:用计数直接估计概率
要估计 P(下一个词 | 前面的词),最直接的办法就是第二节笔记本那样,用计数的比例来算:
P(好 | 今天天气很) = count(今天天气很好) / count(今天天气很)
分子是"今天天气很好"这五个字连续出现的次数,分母是"今天天气很"这四个字出现的次数——这就是这一整套方法叫 n-gram 的原因:只看前面固定的 n-1 个词来预测第 n 个词。只看前 1 个词叫 bigram,只看前 2 个词叫 trigram,以此类推。
用一个更小的例子把整个流程摊开算一遍。假设你的全部训练文本只有这三句话:
① 我 喜欢 吃 苹果
② 我 喜欢 吃 香蕉
③ 我 喜欢 看 电影
用 trigram(看前 2 个词猜第 3 个词),要估计 P(? | 我 喜欢):
"我 喜欢" 一共出现 3 次
其中后面接"吃"的有 2 次 → P(吃 | 我 喜欢) = 2/3 ≈ 0.67
其中后面接"看"的有 1 次 → P(看 | 我 喜欢) = 1/3 ≈ 0.33
这就是一个完整的概率分布:0.67 + 0.33 = 1,两个数字都不小于 0。
链式法则:从"猜一个词"到"给整句话打分”
这一步是这一讲最关键的数学,它回答了一个第 1 讲留下的问题:只会猜"下一个词”,为什么就能等价于理解整句话?
答案是概率论里一条基本恒等式,叫链式法则(chain rule):一整句话(x₁ 到 x_T)同时出现的概率,可以被严格地拆解成一串"猜下一个词"的概率,连续相乘:
P(x₁, x₂, ..., x_T) = P(x₁) × P(x₂|x₁) × P(x₃|x₁,x₂) × ... × P(x_T|x₁,...,x_{T-1})
用第三节的小例子验证一下,“我 喜欢 吃 苹果"这整句话的概率:
P(我 喜欢 吃 苹果)
= P(我) × P(喜欢|我) × P(吃|我,喜欢) × P(苹果|我,喜欢,吃)
⭐ 这条公式是全课"猜下一个词"这条主线成立的数学根基:只要你能把每一步"给定前文,猜下一个词"的概率算准,把这些概率一路乘下去,你就同时拥有了给任意一整句话的合理程度打分的能力——一句话如果每一步都是"大概率会出现的词”,整体概率就高,读起来就通顺;如果中间某一步是个几乎不可能出现的词,整体概率会被这一步拉得很低。“逐词预测"和"给整句话打分”,在数学上是同一件事,不是两件事凑巧都能做。
困惑度:给"猜得准不准"打一个分数
有了概率,就可以给语言模型的好坏打分了。最常用的指标叫困惑度(perplexity,缩写 PPL)。
先看它的直觉:如果一个模型在每一步都非常确信下一个词是什么(比如给正确答案分配了 99% 的概率),说明它"没那么困惑";如果每一步都在一堆词之间犹豫不决(正确答案只分到了 2% 的概率),说明它"很困惑"。困惑度就是把这种"犹豫程度"翻译成一个数字:
PPL = 模型平均而言,在每一步要在大约多少个"同样可能"的候选词之间做选择
计算方法是先对测试文本里每一步"模型给正确答案打出的概率"取对数、取负号、求平均(这一步的名字叫交叉熵,第 6 讲讲反向传播、第 13 讲讲预训练目标时会重新用到这个量,那时它会正式成为训练时被优化的目标),再对这个平均值取指数:
困惑度 = exp( 每一步 -log P(正确答案) 的平均值 )
⭐ 困惑度有一个很好用的直觉解释:困惑度是 10,大致意味着模型平均下来,好像在 10 个差不多可能的词之间做选择——数字越小,模型越"自信且猜得准";数字为 1 是理论上的完美(每一步都 100% 确定下一个词),随手乱猜(词表多大就有多少种等可能选项)会得到一个接近词表大小的困惑度。
四、n-gram 的致命缺陷:数据稀疏
第三节的小例子只有 3 句话,用起来毫无压力。但真实语言的组合空间大得离谱:如果词表有 5 万个词,trigram 要统计的"两个词接一个词"的组合数量级是 5 万的三次方——天文数字。
这带来一个躲不掉的问题:绝大多数合理的三个词组合,在任何规模的训练语料里,都从来没有连续出现过一次。
count(我 喜欢 攀岩) = 0 ← 这句话完全通顺,但语料里恰好没出现过
↓
P(攀岩 | 我 喜欢) = 0/count(我 喜欢) = 0
这个模型会武断地给一句完全合理的话打出零概率——不是"这句话不太可能",是"这句话不可能",这在直觉上明显是错的。历史上有一整套叫"平滑(smoothing)“的技术专门在打补丁:从没见过的组合那里"借"一点点概率过来,不至于让概率归零。这类技术在数学上做得相当精巧,但只是在给一个结构性缺陷打补丁,没有解决根本问题。
⚠️ 根本问题出在第 3 讲留的一个伏笔上:n-gram 把每个词当成一个孤立的符号来计数,“苹果"和"香蕉"在计数表里是完全不相关的两个条目,即便它们意思很接近。模型见过"我喜欢吃苹果”,完全不能因此对"我喜欢吃香蕉"更有信心一点——符号计数没有"举一反三"的能力。而第 3 讲讲的向量表示恰好是反过来的:如果"苹果"和"香蕉"的向量天然接近,一个基于向量而不是基于孤立符号计数的模型,理论上就能把从"苹果"那里学到的规律,自动泛化到"香蕉"身上。
五、和后面课程的关系
- 链式法则是第 13 讲"预训练目标"的数学骨架——那一讲会把"用链式法则把整段文本的概率拆成一串逐词预测"这件事正式命名为自回归(autoregressive)建模。
- 交叉熵在这一讲只是"打分工具”,到第 6 讲讲反向传播时,它会变成训练时要去最小化的目标——“打分"和"训练目标"在数学上是同一个量,只是用途不同。
- n-gram 的数据稀疏问题,是第 5 讲引入神经网络语言模型最直接的动机:用一个连续的向量空间(第 3 讲)替代离散的计数表,让模型具备"苹果"和"香蕉"之间的泛化能力,同时用一个函数(而不是一张查不到就是 0 的表)来估计概率,不管这句话有没有在训练数据里逐字出现过。
六、本讲小结
- 概率分布是给词表里每个词分配一个非负数字、所有数字加起来等于 1 的一组数——它本身就是一个向量(第 3 讲)。
- n-gram 模型用最朴素的方式估计这个分布:直接数训练语料里"前面固定几个词后面接某个词"的次数比例。
- ⭐ 链式法则把"逐词预测"和"给整句话的合理程度打分"在数学上严格地统一成同一件事:
P(x₁,...,x_T) = ∏ P(xₜ|x₁,...,xₜ₋₁)——这是"猜下一个词"这条主线成立的根本原因。 - 困惑度是衡量语言模型好坏的标准指标,直觉上是"模型平均在多少个差不多可能的词之间犹豫”,数字越小越好。
- ⚠️ n-gram 的致命缺陷是数据稀疏:真实语言的词语组合空间是天文数字,绝大多数合理组合在训练数据里从未出现过,导致计数表给出错误的零概率;更深层的问题是它把每个词当成孤立符号,没有能力从相似的词之间"举一反三"。
- 这个缺陷直接指向第 5 讲:用向量和神经网络替代计数表,是解决数据稀疏问题最根本的办法,不是缝缝补补。
思考题
- 用第三节的三句小语料(“我喜欢吃苹果"“我喜欢吃香蕉"“我喜欢看电影”),如果用 bigram(只看前 1 个词)估计
P(看 | 喜欢),你会发现结果和用 trigram 算出的一样——因为这个小语料里"喜欢"前面永远是"我”。现在假设语料里再加一句"你 也 喜欢 看 电影”,bigram 和 trigram 估计出的P(看 | 喜欢)还会相等吗?这说明"上下文更长"要在什么情况下才会真正帮上忙? - 用链式法则手动展开
P(我, 喜欢, 看, 电影),写出需要相乘的每一项。如果其中某一项概率是 0,整句话的概率会变成多少?这说明了什么? - 一个语言模型在测试集上算出的困惑度是 50,另一个是 20,哪一个模型更好?如果一个模型的困惑度恰好等于词表大小,说明它在做什么(提示:想想"随手乱猜")?
- 为什么说"平滑技术在打补丁而不是解决根本问题"?如果给所有从未出现过的组合都统一加上一个很小的概率,这解决了"零概率"问题,但解决了"苹果和香蕉应该被认为相似"这个问题吗?
- 假设词表有 5 万个词,想直接统计"看前 5 个词猜第 6 个词"(6-gram),需要的组合数量级大约是多少(
5万⁵)?对比宇宙中估计的原子数量级(约10⁸⁰),你能得到什么直观感受?