03.07-Agent学习记录-熵、交叉熵与KL散度

前几篇用概率描述不确定性,也认识了概率分布。现在把问题推进一步:如果一个模型会给不同结果分配概率,我们怎样描述它有多不确定,又怎样判断这些概率分得好不好?

舒翱移动端 / 全栈 / Agent 应用

正文

这就会遇到熵、交叉熵和 KL 散度。它们经常一起出现在模型训练中,但回答的问题各不相同。为了看清区别,先假设会议资料只分两类:“通知”和“纪要”。本文的数字都是教学假设,不代表实际资料比例或模型效果。

假设一个简化的数据来源,产生通知的概率为 0.75,产生纪要的概率为 0.25。记作分布 p = [0.75, 0.25],坐标顺序固定为“通知、纪要”。在还没看到下一份资料时,知道通知更常见,但仍不能确定下一份一定是什么。

我们先给单次结果定义一个量:自信息,也可以直观理解为这次结果带来的“意外程度”。一个结果被分配的概率为 pᵢ,自信息写成 -log₂(pᵢ)。这里 log₂ 是以 2 为底的对数,可以先把它当作一种转换规则:概率越小,转换后的值越大。信息量与熵的定义

例如,概率 1/2 对应 1,概率 1/4 对应 2,概率 1/8 对应 3。概率减半,信息量增加 1。这种规则适合描述“越少见的结果,出现时越出乎原先预期”。这里衡量的是概率模型中的意外程度,不是在给一份资料的重要性打分。

对刚才的数据来源,一次通知的信息量约为 0.415,一次纪要的信息量为 2。把每种结果的信息量按出现概率加权平均,就得到熵:

H(p) = -Σ pᵢ log₂(pᵢ)

H(p) = 0.75 × 0.415… + 0.25 × 2
     ≈ 0.811

Σ 表示把各类别对应的项相加。以 2 为底时,这里的单位是 bit,中文常写“比特”。熵描述的是一个分布下平均有多少不确定性,不是某一个样本错了多少。

如果两个类别各有一半概率,熵就是 1 bit。若通知概率为 1、纪要概率为 0,类别已经确定,熵就是 0。对固定的有限类别数,均匀分布具有最大的熵。计算中把 0 × log(0) 对应的项按极限记作 0,而不是直接让程序计算 0 乘无穷。

因此,二分类里的 p = [0.5, 0.5] 比 [0.99, 0.01] 更不确定。但低熵并不能证明判断正确:模型把一份纪要误判成通知,同时给通知 99% 概率,它很确定,却确定错了。熵的高低与现实事实是否符合,是两件需要分别检查的事。

接下来让一个模型给预测概率 q。假设它总是预测 q = [0.5, 0.5],不管下一份通知还是纪要,都给一半概率。我们想衡量:真实结果按 p 出现,但模型按 q 分配概率,会得到多大的平均负对数分数?

这就是交叉熵:

H(p, q) = -Σ pᵢ log₂(qᵢ)

注意两处字母的分工:p 决定怎样加权,因为我们关心真实来源下各结果出现的频率;q 放在对数里面,因为要评估模型给实际结果分了多少概率。两个分布必须针对相同类别,并使用相同的类别顺序。交叉熵与熵的关系

我们的 q 两项都是 0.5,每种结果的负对数都是 1,交叉熵就等于 1 bit。如果模型改成 q = p,交叉熵会降到约 0.811 bit。这个数据来源本身还有不确定性,即使概率分得完全正确,也不需要把每次还未出现的结果都确定下来。

前面的模型只知道资料来源的总体比例。如果额外提供文档正文,就可能利用正文判断类别,此时要讨论给定正文后的条件分布。不确定性和可达到的平均损失基准也会变化。因此,0.811 bit 只是刚才信息条件下的熵,不能拿来当作所有文档分类模型都无法突破的统一下限。

再假设另一个模型预测 q = [0.1, 0.9]。数据里通知更多,它却把通知的概率压得很低,交叉熵会升到约 2.529 bit。这个值是在既定的 p 和评分规则下算出来的,不是一个能直接跨越所有任务比较的“能力总分”。

把三种情况放在一起,会更清楚:

模型预测 q 交叉熵 H(p,q) 比 p 自身熵多出的部分
[0.75, 0.25] 约 0.811 bit 0
[0.5, 0.5] 1 bit 约 0.189 bit
[0.1, 0.9] 约 2.529 bit 约 1.718 bit

最后一列就是这个例子中的 KL 散度,英文 Kullback–Leibler divergence,也叫相对熵。它写作:

D_KL(p || q) = Σ pᵢ log₂(pᵢ / qᵢ)

H(p, q) = H(p) + D_KL(p || q)

符号 p || q 标明比较方向。可以把它理解为:以 p 为参照,使用 q 分配概率,相比使用 p 自身,多付出了多少平均负对数代价。对合法的离散概率分布,KL 散度非负,p 和 q 相同时为 0。KL 散度的方向与基本性质

它通常不对称。这个例子中 D_KL([0.75,0.25] || [0.5,0.5]) 约为 0.189 bit,调换方向后约为 0.208 bit。参照分布改变,加权方式也随之改变。所以它称为“散度”,不能直接当作前面学习的欧几里得距离,更不能把两个方向混写。

零概率也有明确后果。如果 p 中某个类别可能发生,而 q 对这个类别分配严格的 0,那么相应的交叉熵和 KL 散度会变成无穷。它表达的意思是:模型认定一个实际可能发生的结果绝不发生。真实程序还需要处理浮点精度、数值稳定和零值约定,不能简单忽略这项后继续声称公式没有变化。

机器学习里通常不知道真实分布 p。训练集只能提供观察到的样本。对于一份标注为“通知”的资料,可以把这个样本的目标写成 [1, 0],交叉熵就变成 -log(q通知)。如果模型给正确类别 0.8,损失比只给 0.2 更小。多个样本的损失再按约定求和或平均,用来指导训练。

这里每份资料的真实类别,来自标注或其他任务依据,不是由模型概率自己决定。只给模型最有把握的类别打勾,再把这些结果当成可靠真值,无法保证学到正确的分类边界。

交叉熵也不同于只数“猜对几次”的准确率。对同一份真实通知,预测 [0.6, 0.4] 和 [0.99, 0.01],取最高概率类别时都猜对了;后者给正确类别的概率更高,负对数损失更小。反过来,如果实际是纪要,第二种预测会受到更大的损失。这种评分会区分预测的把握程度,但要判断概率是否可靠,仍需用独立样本观察:被预测为某种概率的事件,实际发生比例是否相符。

即便比较同一种损失,也要让任务、数据分布和计算口径可比。只挑容易的资料,平均交叉熵可能下降,却不代表模型在原本的资料范围中进步了。

语言模型预测下一个 Token 时,也可以把目标 Token 看作实际观察到的类别,通过负对数概率评估预测。每个位置都有当时的上下文,所以要考虑的是给定上下文后的条件分布。算出一段文本的平均损失,还要说明哪些位置被计入、怎样处理填充以及采用什么平均方式。

实现中常用自然对数 ln,对应单位 nat;也可以用以 2 为底的对数,对应 bit。两者只是缩放不同,但引用数字时必须统一。不能把用 ln 得到的损失,与用 log₂ 得到的数值原样对比。模型还常输出未经归一化的分数,再由相应运算转成概率;训练库的交叉熵接口可能直接接收这些分数,需要按接口约定使用。交叉熵接口对输入分数和目标的约定

还要留意本文的范围:这里讨论有限离散类别。连续变量的概率密度不同于单点概率,相关的微分熵也有不同性质,例如可能为负,不能把本文所有直觉直接搬过去。

有了这些区分,读训练日志时就更容易理解:熵先描述一个分布的不确定性,交叉熵根据目标结果评价预测概率,KL 散度比较两个分布之间有方向的差异。它们帮助定义训练目标,但最终的 Agent 是否找对资料、是否执行正确、是否完成用户任务,仍要使用对应的评估标准。下一篇继续解释,训练程序怎样根据损失的变化方向调整参数。


当前学习编号:03.07 熵、交叉熵与 KL 散度。
下一学习编号:03.08 导数、梯度与链式法则。后续还有其他学习编号。

关联分支:概率基础对应 03.04 概率与条件概率、03.06 分布、期望与方差;损失与训练对应 04.08 损失函数与优化目标、03.08 导数、梯度与链式法则、07.04 梯度下降与优化器;语言生成对应 08.12 自回归生成与下一个 Token 预测;预测概率怎样评估,对应 23.04 分类、回归与概率校准指标、23.01 模型评估与完整系统评估。

系列阅读

本篇学习编号:03.07 熵、交叉熵与 KL 散度。

上一篇: 03.06 分布、期望与方差 。

下一篇: 03.08 导数、梯度与链式法则 。

延伸阅读

返回全部文章

搜索项目和文章

输入关键词,查找项目或文章。

使用 Tab 选择结果,按 Esc 关闭。