起因#
上一篇把 RNN 拆成了两层:state transition 和 output projection。State transition 维护 hidden state,output projection 从 hidden state 中映射出当前任务需要的预测结果。
继续看 MIT 6.S191 的 language model 部分时,下一个自然的问题是:对于语言模型,output layer 产出的东西到底长什么样?
直觉上觉得是"预测出一个词"。但其实不是。它是整个词表上的一个概率分布。
把这个分布写出来,就是条件概率:
$$P(x_{t+1} \mid x_1, \ldots, x_t)$$真的从头串一遍背后的概率论——conditional probability、joint probability、probability chain rule——会发现 next-token prediction 和 sequence modeling 之间有一个非常直接的数学连接。
这篇笔记把这条链路理一遍。
从 Hidden State 到概率分布#
上一篇已经建立了 RNN 的两层框架:
$$h_t = f(x_t, h_{t-1})$$$$\hat{y}_t = \text{task\_head}(h_t)$$对于语言模型,task head 通常是一个 linear layer 加 softmax:
$$z_t = W_y h_t + b$$$$p_t = \text{softmax}(z_t)$$\(z_t\) 叫做 logits,维度等于词表大小 \(|V|\)。softmax 把它变成一个合法的概率分布——所有分量非负,加起来等于 1。
flowchart LR
ht["h_t"] --> lmhead["LM Head(Linear)"]
lmhead --> logits["logits"]
logits --> sm["softmax"]
sm --> dist["P(next token)"]
\(p_t\) 不是"模型觉得下一个词是什么"。它是整个词表上的概率分布。每个词都对应一个概率值。
比如,在 “I love machine” 之后:
| token | 概率 |
|---|---|
| learning | 0.62 |
| translation | 0.08 |
| vision | 0.05 |
| … | … |
模型不是在说"下一个词一定是 learning"。它在说:在当前 context 下,learning 出现的概率是 0.62,translation 是 0.08,以此类推。
写成数学符号:
$$P(x_{t+1} \mid x_1, \ldots, x_t)$$竖线左边是"要预测的东西",右边是"已经看到的东西"。这就是 conditional probability(条件概率)。
条件概率#
先从最简单的情况说起。
\(P(A)\) 表示事件 A 发生的概率。比如 \(P(\text{下雨})\),可能是 0.2。
\(P(A \mid B)\) 表示在已知 B 发生的情况下,A 的概率。比如 \(P(\text{下雨} \mid \text{乌云})\),可能变成了 0.7。
关键在于:知道了额外的信息(乌云),概率发生了变化。条件概率描述的就是"获得额外信息之后,概率怎么变"。
回到语言模型。
$$P(\text{learning} \mid \text{I love machine})$$这不是在问 “learning” 这个词在英语里有多常见。它问的是:在已经看到 “I love machine” 的情况下,下一个 token 是 “learning” 的概率有多大。
context 不同,distribution 就不同。“I love machine” 之后,learning 的概率很高。“I love ice” 之后,cream 的概率很高,learning 几乎为零。
context 的作用,就是改变 next-token 的概率分布。
随机变量和观测值#
顺便澄清一个符号问题。
概率论里,大写 \(X_t\) 通常表示随机变量——“第 \(t\) 个位置上会出现什么 token"这件尚未确定的事。小写 \(x_t\) 表示具体的观测值——“第 \(t\) 个位置上的 token 实际是 machine”。
严格写法:
$$P(X_{t+1} = \text{learning} \mid X_1 = \text{I},\; X_2 = \text{love},\; X_3 = \text{machine})$$ML 文章里通常简写成:
$$P(x_{t+1} \mid x_1, \ldots, x_t)$$后面沿用这个简写。
整个 Sequence 的概率#
到目前为止讨论的都是单步的 conditional probability:给定前面的 token,下一个 token 的概率。
现在换一个更大的问题。一整句话:
$$\text{I love machine learning}$$出现的概率是什么?
写成:
$$P(x_1, x_2, x_3, x_4)$$这叫 joint probability(联合概率)——四个 token 同时以这个顺序出现的概率。
问题是:这个 joint probability 怎么算?
Probability Chain Rule#
概率论有一个恒等式,叫 chain rule(链式法则):
$$P(x_1, x_2, \ldots, x_T) = P(x_1) \cdot P(x_2 \mid x_1) \cdot P(x_3 \mid x_1, x_2) \cdots P(x_T \mid x_1, \ldots, x_{T-1})$$写成紧凑的连乘形式:
$$P(x_{1:T}) = \prod_{t=1}^{T} P(x_t \mid x_{\lt t})$$其中 \(x_{\lt t}\) 就是 \(x_1, \ldots, x_{t-1}\) 的简写。
用 “I love machine learning” 展开看:
$$P(\text{I, love, machine, learning})$$$$= P(\text{I})$$$$\times\; P(\text{love} \mid \text{I})$$$$\times\; P(\text{machine} \mid \text{I, love})$$$$\times\; P(\text{learning} \mid \text{I, love, machine})$$每一项都是一个 next-token conditional probability。
这个式子不是近似,是精确的恒等式。任何 sequence 的 joint probability 都可以这样拆。
如果模型能准确估计每一步的 \(P(x_t \mid x_{\lt t})\),它就能计算任意 sequence 的概率。 学 next-token prediction,和对整个 sequence distribution 建模,是同一件事。
这是 next-token prediction 最重要的数学基础。它不是一个和完整语言建模无关的小任务——probability chain rule 把两者直接连了起来。
语言中的 Token 不独立#
chain rule 对任何 joint distribution 都成立。但语言有一个性质让它特别有意义:token 之间不是独立的。
独立(independence)的意思是:
$$P(A \mid B) = P(A)$$知道 B 发生,不改变 A 的概率。
语言显然不满足这个条件。
\(P(\text{Francisco})\) 和 \(P(\text{Francisco} \mid \text{San})\) 差异非常大。“Francisco” 单独出现的概率不高,但在 “San” 之后,它几乎是唯一合理的选项。
同样,\(P(\text{learning})\) 和 \(P(\text{learning} \mid \text{machine})\) 也完全不同。
如果 token 之间真的独立,那 \(P(x_t \mid x_{\lt t}) = P(x_t)\),context 不起任何作用。直接查频率表就行了,不需要语言模型。
正因为 token 不独立,context 才有意义。语言模型真正需要学的,不是每个 token 本身出现的频率,而是 context 如何改变 token 的 conditional probability。
每个 Timestep 都是一个训练信号#
回到 RNN。把 sequence 沿时间展开:
flowchart LR
x1["x₁"] --> h1["h₁"]
x2["x₂"] --> h2["h₂"]
x3["x₃"] --> h3["h₃"]
h1 --> h2 --> h3
h1 --> p1["predict x₂"]
h2 --> p2["predict x₃"]
h3 --> p3["predict x₄"]
p1 -.-> L1["loss₁"]
p2 -.-> L2["loss₂"]
p3 -.-> L3["loss₃"]
每一步的 hidden state 都可以用来预测下一个 token,每一步的预测都可以和真实 token 比较,产生一个 loss。
一段长度为 \(T\) 的 sequence,可以产生 \(T - 1\) 个训练目标:
| input | target |
|---|---|
| I | love |
| I love | machine |
| I love machine | learning |
如果只在 sequence 最后预测一次(比如序列分类),一整个 sequence 只给一个 supervision signal。Next-token prediction 则在几乎每个位置都给一个。
同样一段文本,next-token prediction 能从中提取的训练信号密度要高得多。
Self-Supervised Learning#
传统的 supervised learning 需要人工标注:
| input | label |
|---|---|
| 一张猫的图片 | cat |
| 一封邮件 | spam |
有多少标注数据,就有多少训练样本。标注成本限制了数据规模。
Next-token prediction 不需要人标注任何东西。
拿一段文本:
$$\text{The cat sat on the mat}$$自动构造出训练数据:
| input | target |
|---|---|
| The | cat |
| The cat | sat |
| The cat sat | on |
| The cat sat on | the |
| The cat sat on the | mat |
target 直接来自 raw text 本身。输入是前面的 token,target 就是紧跟着的下一个 token。不需要有人逐条标注"这里正确答案是 sat”。
这种训练方式叫 self-supervised learning(自监督学习)——supervision signal 从数据自身的结构中来,而不是从外部标注中来。
对语言模型来说,这意味着三件具体的事情。
一,不依赖人工 label。互联网上的文本可以直接拿来用。
二,每个 token position 都产生一个训练目标。一段 1000 个 token 的文本能构造 999 个 (input, target) pair。
三,原始文本的规模本身就非常大。书籍、网页、代码、论文——都是可以直接转化成训练数据的原料。
不需要标注,每个位置都是 target,原始数据量巨大。这是 next-token prediction 能够 scale 到大规模训练的基础。
为什么这么简单的 Objective 能学到很多东西#
“根据前面的 token 预测下一个 token”,听起来像一个很窄的任务。但不同的 context 对预测能力的要求差异很大。
$$\text{The capital of France is \_\_\_}$$要预测好这个,模型需要捕获 factual knowledge。
$$\text{The keys to the cabinet \_\_\_ on the table}$$这里涉及 syntax——主语是 keys(复数),动词应该是 are 而不是 is。
$$\text{Alice gave the book to Bob. Later, Bob opened the \_\_\_}$$这里涉及 entity tracking 和长距离依赖——模型需要记住 Bob 拿到的是 book。
为了在各种 context 下都能降低 prediction loss,模型会受到压力去捕获大量不同类型的结构:词法、句法、事实、推理、语义关联。
这里有一个有意思的地方。我们并没有告诉 hidden state 应该长成什么样。没有 label 说"这个 hidden state 应该编码语法信息"或者"这个 hidden state 应该记住实体关系"。模型只是为了做好 prediction,逐渐在 hidden state 里形成了对 history 有用的 internal representation。
这件事属于 representation learning 的范畴,可以单独写一篇。
连接到 Likelihood 和 Cross Entropy#
最后补一步。
如果训练数据中真实的 next token 是 \(x_t\),训练时自然希望模型给出的条件概率越大越好:
$$P_\theta(x_t \mid x_{\lt t})$$根据 chain rule,整个 sequence 的概率是:
$$P_\theta(x_1, \ldots, x_T) = \prod_{t=1}^{T} P_\theta(x_t \mid x_{\lt t})$$取对数,连乘变成求和:
$$\log P_\theta(x_{1:T}) = \sum_{t=1}^{T} \log P_\theta(x_t \mid x_{\lt t})$$希望这个值越大越好——这就是 maximum likelihood。
训练时通常取负号,变成最小化问题:
$$\mathcal{L} = -\sum_{t=1}^{T} \log P_\theta(x_t \mid x_{\lt t})$$这就是 negative log likelihood,也等价于 cross entropy loss。
从 next-token prediction 出发,经过 chain rule,自然走到了这个训练目标。Cross entropy 的推导和信息论含义可以后面单独展开。
结论#
RNN 的 prediction head 产出的不是一个词,而是整个词表上的概率分布 \(P(x_{t+1} \mid x_{\lt t})\)。Conditional probability 描述的是:在当前 context 下,某个 token 有多可能出现。
Probability chain rule 把整个 sequence 的 joint probability 拆成一连串 next-token conditional probability。因此学 next-token prediction 和对 sequence distribution 建模是同一件事——这不是一个随意选择的小任务。
Next-token prediction 天然适合 self-supervised learning:不需要人工标注,几乎每个 token position 都产生训练目标,而原始文本的规模本身就非常大。一个 sequence 还能在多个 timestep 提供 supervision。这几件事叠在一起,是它能 scale 的基础。
参考资料#
- MIT 6.S191: Introduction to Deep Learning — https://introtodeeplearning.com/
- 重新理解 RNN:Hidden State、Output 和 Prediction 的区别
- 从 Forward 到 Optimizer:再看一遍 Training Loop