打开任何一个语言模型的训练代码,loss 都是交叉熵;读论文,动机写的是最大似然;做分析,工具是 KL 散度。三个名字指向同一个优化目标,这不是巧合也不是约定俗成,而是一组恒等式的三个侧面。把它们的关系推导清楚,"训练语言模型到底在干什么"这个问题才有精确的答案。
从最大似然出发
设真实数据分布 $p^*$ 不可知,手头只有 $N$ 个 i.i.d. 样本 $\{x_i\}$,它们定义经验分布 $\hat p(x)=\frac1N\sum_i\delta(x-x_i)$。经验分布是这篇文章的关键配角:它是"数据"在分布语言里的化身,后面所有等价关系都在 $\hat p$ 与 $p_\theta$ 之间发生。
模型 $p_\theta$ 的最大似然估计是
$$ \theta^*=\arg\max_\theta\prod_{i=1}^N p_\theta(x_i) =\arg\max_\theta\frac1N\sum_{i=1}^N\log p_\theta(x_i) $$
取对数(单调变换不改变 $\arg\max$),除以 $N$(正数缩放也不改变)。关键一步是认出右边就是经验分布下的期望:
$$ \frac1N\sum_{i=1}^N\log p_\theta(x_i)=\mathbb{E}_{x\sim\hat p}[\log p_\theta(x)]. $$
这个变形值得停下来看一眼:左边是"对这份数据求和",右边是"对一个分布求期望"。求和变期望的动作把"这份特定数据"抽象成了"一个可以谈论熵、散度的对象"——后面整条等价链都靠这个抽象才有讨论空间。
取负号把最大化翻成最小化,右边正是交叉熵的定义:
$$ H(\hat p,p_\theta):=-\mathbb{E}_{\hat p}[\log p_\theta]=-\frac1N\sum_i\log p_\theta(x_i). $$
所以"最小化交叉熵"与"最大似然"是同一个目标的两种写法,连数值都只差一个负号。注意交叉熵里的第一个参数是数据、第二个是模型——交叉熵从来不是一个对称的东西。
这里取对数还有一层计算动机:连乘 $N$ 个概率会数值下溢到 0,对数把乘变加,下溢问题消失、梯度求导也变成求和形式。理论等价与工程可行在这里是同一个动作。
减去常数得到 KL
把交叉熵再拆一层。定义经验分布自身的熵 $H(\hat p)=-\mathbb{E}_{\hat p}[\log\hat p]$,则
$$ H(\hat p,p_\theta)=H(\hat p)+\mathbb{E}_{\hat p}\!\left[\log\frac{\hat p}{p_\theta}\right]=H(\hat p)+D_{\mathrm{KL}}(\hat p\,\|\,p_\theta). $$
这个分解里藏着 Gibbs 不等式的证明线索:KL 非负当且仅当交叉熵不小于数据熵,而等号条件 $p_\theta=\hat p$ 给出"最优模型就是数据本身"的极限图景——完美的语言模型是不可区分于数据生成分布的模型,这话既是定义也是警告(它就是过拟合的极限形态)。
对 $\theta$ 而言 $H(\hat p)$ 是常数(数据熵不依赖模型),于是三个目标在优化意义上完全等价:
$$ \boxed{\ \arg\min_\theta H(\hat p,p_\theta)=\arg\min_\theta D_{\mathrm{KL}}(\hat p\,\|\,p_\theta)=\arg\max_\theta\ \text{似然}\ } $$
等价归等价,三种写法暴露的信息不同:似然说出目标的统计出身(频率派估计),交叉熵给出可计算的 loss 数值,KL 则给出下界与最优值——$D_{\mathrm{KL}}\ge0$(Gibbs 不等式),等号当且仅当 $p_\theta=\hat p$,所以交叉熵的最小可能值是数据熵 $H(\hat p)$,模型再好也降不下去。loss 曲线的绝对数值要减了这个底才有意义:两个数据集上 loss 都是 2.0,不代表模型一样好,可能一个离信息论下限 0.5、另一个只差 0.1。
语言模型的具体形态
自回归语言模型里,样本是序列,条件化展开 $p_\theta(x)=\prod_t p_\theta(x_t\mid x_{
$$ H=\frac1N\sum_i\sum_t-\log p_\theta(x^{(i)}_t\mid x^{(i)}_{
即每个位置的经验分布是"真实下一个 token 的 one-hot",与模型分布做交叉熵。one-hot 的熵为零,所以逐位置的 KL 就等于逐位置交叉熵——语言模型训练里两者数值上干脆合一,这也是很多讨论混用两个词的原因。
这个形态下还有一个值得点破的细节:链式分解意味着我们最小化的其实是逐位置条件分布的前向 KL 之和,而不是序列联合分布的 KL。两者在模型类足够表达时目标一致(联合 KL 也按链式分解),但逐位置的视图解释了为什么训练信号天然是"每个位置一份监督"——这也是语言模型样本效率高于多数序列模型的结构性原因。
但要注意等价链上有一个隐藏环节:我们最小化的是经验分布与模型的 KL,不是真实分布与模型的 KL。两者之差是泛化误差。$N\to\infty$ 时 $\hat p\to p^*$(Glivenko-Cantelli 意义下),经验解趋近真解;有限 $N$ 时,对 $\hat p$ 过拟合——记住训练集每个位置的 one-hot——同样能让经验 KL 归零,却对 $p^*$ 毫无益处。交叉熵的统计出身提醒我们:它衡量的贴合对象是数据,不是世界。
这也给"为什么预训练要拼命堆数据量"一个信息论层面的回答:增数据不是为了让 loss 更低,而是为了收窄 $\hat p$ 与 $p^*$ 的缝隙,让"贴合数据"与"贴合世界"这两件事重新合一。数据规模在这个视角下不是越多越好,而是唯一能把经验目标抬回真实目标的杠杆。
KL 的方向:为什么是这个方向
KL 不对称:$D_{\mathrm{KL}}(\hat p\|p_\theta)\ne D_{\mathrm{KL}}(p_\theta\|\hat p)$。最大似然锁定的是前向 KL(真实分布在前),它的行为特征是 mode-covering:$p_\theta$ 必须在 $\hat p$ 有质量的地方都有质量,否则某个 $x_i$ 的 $p_\theta(x_i)\to0$ 会让 $-\log p_\theta(x_i)\to\infty$,惩罚无限大。反向 KL(模型在前)则是 mode-seeking:允许模型只覆盖一部分模式,代价是放弃其余。
这个方向之分在下游反复出现:RLHF 的 KL 惩罚 $D_{\mathrm{KL}}(\pi_\theta\|\pi_{\mathrm{ref}})$ 是反向的,蒸馏里用正向还是反向 KL 决定学生模型是"全覆盖教师"还是"专攻教师的高置信模式"。选择从来不是随意的,是两种目标几何的必然结果。
再补一个常被忽略的事实:前向 KL 对 $p_\theta$ 是凸的(它是 $-\mathbb{E}_{\hat p}[\log p_\theta]$ 加常数,对数把指数族参数化变成凸函数),而反向 KL 一般不凸。这解释了为什么 MLE 的优化理论干净、而反向 KL 目标(如变分推断里的 ELBO)总要搭配额外的结构假设才好优化——凸性不在我们手里,在方向的选择里。
训练实践里等价的三个推论
等价关系落到代码里,有三个日常推论值得记住:
- loss 与 KL 混写无害:因为对 $\theta$ 求导时 $H(\hat p)$ 的梯度为零,用交叉熵还是 KL 写 loss,梯度逐分量相同。框架里
F.cross_entropy与手写-(p_hat * log p).sum()的反向完全一致。 - 加权样本 = 修改经验分布:给样本加权 $\sum_i w_i\log p_\theta(x_i)$ 等价于把 $\hat p$ 换成重加权分布 $\hat p_w\propto\sum_i w_i\delta_{x_i}$。数据配比、上采样、importance weighting 全是同一个操作:换一个经验分布去贴合。
- 评估的 loss 底因数据而异:不同评测集的 $H(\hat p)$ 不同,跨集比较 loss 绝对值没有意义——要减底,或者干脆比 PPL(下一篇)。同一模型在代码语料上 loss 1.5、在诗歌语料上 2.8,可能说明的只是诗歌的内在熵更高。
这条推论还有一个反向用法:想估算某领域数据的"内在熵",拿一个强模型在其上训练到饱和,残差 loss 就是 $H(\hat p)$ 的经验上界。预训练报告里"loss 收敛到某平台"的平台高度,一半由模型能力决定,另一半由这个底决定。
编码视角与两个边界备注
交叉熵还有一个值得知道的读法:它是对 $p^*$ 的样本用"为 $p_\theta$ 优化的编码"来传输时的平均码长。香农编码给符号 $x$ 分配长度 $-\log p_\theta(x)$ 的码字,平均长度恰是 $H(\hat p,p_\theta)$;而最优码(知道真实分布)的长度是 $H(\hat p)$。KL 散度因此是"用错分布设计的编码浪费的平均比特数"。大模型时代这个视角突然变得实际:$\sum_t-\log_2 p_\theta(x_t)$ 直接配合算术编码就是真压缩器,loss 数值就是压缩率——"预测即压缩"的等价性不是比喻。
两个边界备注收尾。一是 label smoothing:把 one-hot 换成 $(1-\epsilon)\,\text{one-hot}+\epsilon/K$ 的软化目标,等价于把 $\hat p$ 换成一个熵更大的分布,交叉熵形式不变、$H(\hat p)$ 这个底抬高——它防的是模型对训练标签过度自信,本质是在经验分布里掺先验。二是并非所有生成模型都走 MLE:GAN 用的是 JS 散度类的判别目标,扩散模型优化的是 score matching 损失——等价三角只在"显式似然"的模型家族里成立,这也是为什么不同家族的样本质量-似然关系经常对不上。
最后补一个估计理论角度的注脚:最大似然在正则条件下是渐近最优的——Cramér-Rao 下界说任何无偏估计的方差都不低于 Fisher 信息的逆,而 MLE 在 $N\to\infty$ 时达到这个界。交叉熵训练继承了这份统计效率的家底:它不是众多可写损失中随手挑的一个,而是频率派框架下方差最小的那个。当然,渐近最优不回答有限样本的一切问题,过拟合与泛化缺口(前面"贴合对象是 $\hat p$ 不是 $p^*$"的警告)依然要靠数据与正则去填。
数值验算
十几行 numpy 把恒等式钉在数上。验算的习惯值得养成:等价关系这类"恒成立"的结论,用随机数打破过一次才算数——如果哪天 assertion 挂了,挂的不是数学而是你对某个符号的理解。
import numpy as np
rng = np.random.default_rng(0)
# 经验分布:4 类,计数 [50, 30, 15, 5]
counts = np.array([50, 30, 15, 5])
p_hat = counts / counts.sum()
logits = rng.normal(size=4)
p_theta = np.exp(logits) / np.exp(logits).sum()
ce = -(p_hat * np.log(p_theta)).sum() # 交叉熵
h_data = -(p_hat * np.log(p_hat)).sum() # 数据熵
kl = (p_hat * np.log(p_hat / p_theta)).sum() # 前向 KL
assert np.isclose(ce, h_data + kl)
print(f"CE={ce:.4f} H(data)={h_data:.4f} KL={kl:.4f}")
# CE=1.22xx H(data)=1.05xx KL=0.16xx,且 CE ≥ H(data) 恒成立
跑一遍你会发现:无论 logits 怎么随机,$CE-H(\hat p)=KL\ge0$ 恒成立,而交叉熵的数值大部分时间花在数据熵这个动不了的底上。看训练 loss 绝对值时心里要有这把尺。
小结
最大似然经取对数、除 $N$ 变为经验交叉熵,减去常数数据熵变为前向 KL,三者对 $\theta$ 等价。等价不代表信息等价:似然交代统计出身,交叉熵给出 loss 数值,KL 给出下界 $H(\hat p)$ 与"贴合对象是经验分布"的警告,KL 的不对称方向则决定了 mode-covering 与 mode-seeking 的行为分野。
实操层面把三条等价浓缩成一句检查口诀:看到"我们在做最大似然",立刻换算成"我们在最小化前向 KL,下界是数据熵,贴合的是经验分布"——每个名词都对应一个可以追问的坑位。下一篇把这个下界换算成工程上更顺手的指标:困惑度的信息论含义。