模块 01 · 约 15 分钟

什么是语言模型?

在写第一行代码之前,我们先把"语言模型在做什么"这件事讲清楚。

① 直觉:它是一个"超强自动补全"

想象你在手机上打字,输入法会根据你已经打出的几个字猜测下一个字。 语言模型做的事情本质相同,只是它见过的文本多得多(数千亿到数万亿 token), 而且它一次只关心一件事:给定上文,下一个 token 是什么

但要小心一个关键点:模型输出的不是"一个答案", 而是整个词表上的一组概率。比如词表有 5 万个 token, 模型就告诉你"第 17 个 token 的概率是 35%,第 982 个是 12%,第 33215 个是 8%..."。

真正的输出文本,是通过从这个分布中采样得到的。 而采样的"刺激程度",就由一个叫 temperature 的旋钮控制。

② 玩一玩:温度如何改变分布

下面这个演示展示了几个常见上文,以及模型给出的下一个 token 候选。 拖动 temperature 滑块,观察概率条的形状变化;点"采样"按钮,看它真的从这个分布里抽出哪个。

分布熵=2.44bits
0.1(确定)1.0(默认)2.0(混乱)
上文:今天天气⏵ 下一个 token 的概率分布(由 softmax 算出):1 / 5
40.1%
19.9%
14.7%
8.9%
7.3%
4.0%
3.0%
2.0%
今天天气

本演示为每一步预设了不同的概率分布(共 5 步),让你能看到真实模型里"上下文怎么改变下一个 token 的可能性"。

③ 数学:softmax 把 logits 变成概率

模型最后一层输出的不是概率,而是一组实数,叫 logits(可正可负、可大可小)。要变成"加起来等于 1"的概率分布,就用 softmax

数学定义 · softmax
P(xi)=exp(zi/T)jexp(zj/T)P(x_i) = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}
代码中每行注释标出了它对应公式的哪一部分 —— 这就是数学到代码的一一映射。
↓ 对应的 Python 实现(可以直接改、直接运行)
  • ziz_i 是第 i 个候选 token 的 logit,即模型给它打的原始分数
  • TTtemperature。 T 越小,分布越尖锐(接近 argmax);T 越大,分布越平(接近均匀)
  • 分母(jexp(zj/T)\sum_j \exp(z_j / T))是 归一化项,保证所有概率加起来等于 1

小练习:把 T0T \to 0 代入公式,看看为什么最大 logit 的概率会趋近 1。 (提示:除以一个很小的数会让差距被放大很多倍。)

④ 代码:跑一遍

下面这段 Python 用 numpy 实现了 softmax 和采样。点右上角的 ▶ 运行 按钮就能在浏览器里真的执行(Pyodide 把 CPython 编进了 WebAssembly), 你能看到不同温度下概率分布的实际样子。

python
直接编辑这段代码即可。输入 np. 看自动提示,⌘/Ctrl + Enter运行。

留意 z -= z.max() 这一步:直接对大数取 exp 会溢出, 减去最大值可以让结果数值稳定,且不改变概率分布。 这是工程实现中的小但重要的细节。

⑤ 检验理解

Q1.当 temperature 设为接近 0(如 0.01)时,模型的输出会怎样?
Q2.既然模型已经算出每个 token 的概率,为什么不直接选概率最高的那个?

⑥ 延伸阅读

Tokenization