交叉熵与概率校准:从xgboost二分类到四分类花卉模型的置信度优化
2026/9/16 1:26:02 网站建设 项目流程

做分类模型做得久了,你会发现一个很微妙的问题:模型在训练集上准确率99%,业务方看得很开心,结果一到线上,换了一波数据分布,分数就忽上忽下。更让人头疼的是,当你把模型的预测概率(比如sigmoid输出一个0.87)拿给懂行的同事看时,对方一句"这个0.87到底有多可信?"直接把你问住。模型的准确率只能告诉你它猜对了多少,但完全无法告诉你每一次预测到底有多"有把握"。这正是二元交叉熵(Binary Cross-Entropy)和概率校准(Probability Calibration)存在的意义。

我最早正视这个问题,是在用xgboost做二分类模型的时候。当时我用logloss做评估指标,模型AUC做到了0.94,可以说排序能力已经很好。但后来我发现,模型输出的概率值在0.4到0.6之间塞了一大堆样本,完全没法直接用阈值0.5做业务决策。后来我做了Platt缩放,再把概率分布拉宽,业务阈值才终于定得下来。这篇博文我想把这套东西拆开揉碎讲清楚,覆盖从二元交叉熵的数学原理到概率校准的实操落地,顺带把最近很多人问的xgboost二分类校准和四分类花卉模型训练也一起串进来。不管你是刚入门的新手,还是被概率输出折腾过几次的工程师,这篇内容都应该能帮上忙。

1. 从"预测对错"到"预测概率":二元交叉熵在解决什么问题

1.1 准确率是个"哑巴"指标

我们平时最习惯看的指标就是准确率、精确率、召回率、F1。这些指标有一个共同特点:它们都把模型的输出"硬编码"成类别,然后跟真实标签比。比如阈值设为0.5,预测概率0.51和0.99都会被判定为正类,它们在准确率眼里没有任何区别。可真实的业务场景里,0.51和0.99不仅是"两个都猜对"的差别,0.51意味着模型自己都没太大把握,0.99才是真正高置信度的判断。

举一个最简单的例子。两个模型,准确率都是95%。模型A在预测正样本时,输出概率基本集中在0.9以上,而在预测负样本时概率基本在0.1以下,这说明模型对自己的判断非常笃定。模型B的准确率虽然是95%,但它的概率输出基本都在0.5附近晃荡,属于"勉强蒙对"。如果你是业务方,需要在预算有限的情况下只对"模型最有把握"的样本做处理,你会选谁?显然是模型A。所以准确率不能回答"模型有多确定",概率输出背后隐藏的置信度信息,才是做决策时真正值钱的东西。

这也是二元交叉熵大显身手的地方。它不关心模型最终"分对"还是"分错",而是关心模型给出的概率分布和真实标签的吻合程度。一个预测概率0.99、真实标签为正的样本,loss很小;一个预测概率0.51、真实标签为正的样本,loss要大得多。这种"软性"的反馈信号,是准确率这类硬指标永远给不了的。

1.2 最大化似然:交叉熵的统计直觉

先看一个最简单的公式。对一个二分类问题,假设模型针对单个样本输出的概率是 p,真实标签是 y(y 取0或1)。二元交叉熵的单个样本形式是:

L = - [ y · log(p) + (1 - y) · log(1 - p) ]

这个公式看起来人畜无害,但拆开后信息量很大。当 y=1 时,L = -log(p);当 y=0 时,L = -log(1-p)。也就是说,模型只会在真实标签对应的那个方向上计算惩罚。如果模型对正样本给了一个很大的 p,-log(p) 就很小;如果 p 很小,-log(p) 就非常大,相当于"重罚"了模型把正样本判断成负样本的概率。

这其实就是在最大化对数似然(Maximum Log-Likelihood)。你可以把 p 看成模型对"这个样本是正类"的概率估计,那么1-p 就是"这个样本是负类"的概率估计。对真实标签 y 来说,模型给出的整体概率就是 p^y · (1-p)^(1-y),取对数正好就是上面的 L 反过来。所以最小化交叉熵,本质上等于最大化真实标签在模型预测概率分布下的对数似然。一句话总结:交叉熵希望模型"对的时候自信,错的时候很惨"。

很多人把交叉熵理解成"两个分布的差异程度",这个角度也没问题。真实标签 y 可以看成一个在0/1两点上的确定性分布,模型预测是一个在 [0,1] 上的软分布。交叉熵越小,说明两个分布越接近,模型的预测越贴近真实标签的分布形态。这个理解在后面的多分类扩展里特别有用。

2. 公式与直觉:二元交叉熵每一部分都是"信号"

2.1 为什么用 log 而不是线性惩罚

一个很常见的疑问是:为什么不直接用 (p - y)^2 或者 |p - y|,非要绕一圈用 log?这要说回模型训练的本质。我们不仅仅希望模型"错得少",还希望模型在面对错误时能产生足够大的梯度,让参数更新得更快、更坚决。

log 函数有一个特点:曲线在接近0时非常陡,在接近1时比较平缓。这意味着当模型输出一个极端错误的概率(比如真实正样本却给到 p=0.001),-log(p) 会接近无穷大,惩罚极其强烈。反过来,如果模型已经做得不错了(比如 p=0.95 对应真实正样本),-log(p) 很小,惩罚有但不会破坏已经学好的参数。这种"错得越离谱罚得越狠"的非对称性,非常符合分类任务的需求。

如果用线性惩罚 |p - y|,模型在 p=0.99 和 p=0.51 时,只要它们跟真实标签方向一致,惩罚都是一样的。这会让模型不追求"确定性",反正0.51和0.99在目标函数里没有本质区别。分类模型就慢慢变成一个"及格万岁"的模型,输出的概率越来越模糊,最后就是一团浆糊。log 的形式强制让模型意识到:0.99 才是好答案,0.51 只是勉强及格。

2.2 对比均方误差:梯度饱和是致命的

我在给学生讲损失函数时,最喜欢做的一个对比实验是:同样的二分类任务,一个用 BCE,一个用 MSE(均方误差),看最后模型学出来的概率分布。MSE 版本往往学得很慢,而且概率很容易卡在0.5附近。

原因是数学上的。假设模型输出 z,经过 sigmoid 后得到概率 p = σ(z)。MSE 对 z 的梯度是:

∂MSE/∂z = 2(p - y) · p(1 - p)

BCE 对 z 的梯度是:

∂BCE/∂z = p - y

看出差别没有?MSE 的梯度里多了一个 p(1-p) 项。当模型输出很自信的时候,比如 p=0.98,p(1-p) 只有 0.0196,梯度被压缩得很小。模型已经错了,但梯度趋近于0,参数几乎不动,这叫梯度饱和。反过来,当模型输出在0.5附近时,p(1-p) 取到最大值0.25,梯度反而大,模型会被持续往"0.5附近"这个区域拉扯。久而久之,模型就卡在"半懂不懂"的状态里出不来。

BCE 就没有这个问题。梯度是 p - y,线性且干净。p=0.98、真实标签 y=1 时,梯度是 -0.02(很小,说明方向正确且进入收尾阶段);p=0.98、真实标签 y=0 时,梯度是 0.98(很大,模型被强力拉回)。这种梯度的干净程度,让它成为神经网络二分类的事实标准。甚至可以说,sigmoid + BCE 是天生一对,你很少看到 sigmoid + MSE 的组合能在分类任务上表现好。

3. 概率校准:模型说80%就真该是80%吗

3.1 概率校准问题:模型输出到底可不可信

先抛一个概念:概率校准(Probability Calibration)指的是模型预测的概率值应该和真实事件发生的频率保持一致。换句话说,如果模型对一百个样本都给出0.8的预测概率,那么这些样本里大约应该有80个真实为正类。如果实际只有60个,那模型就是过度自信(overconfident);如果实际有90个,那就是不够自信(underconfident)。

我曾经训练过一个文本分类模型,在测试集上 AUC 0.96,看着非常漂亮。但把预测概率画成直方图后发现,模型对绝大多数负样本都给出了0.99以上的"确信"判断。也就是说,模型对"不犯错"这件事过度自信了。这种模型做排序没问题,但如果要用概率值做阈值判断、做人机配合的置信度门槛,就会出岔子。比如我想挑出"模型最确定为正"的前5%样本做人工复核,结果模型把50%的负样本都推到了极高概率,整个策略直接崩了。

量化校准程度最常用的指标是期望校准误差(Expected Calibration Error,ECE)。做法是把所有样本按预测概率分桶(比如每隔0.1一桶),在每个桶内计算平均预测概率和真实正样本率,再按样本量加权算误差。ECE越低,说明概率越可靠。这里有个很关键的细节:ECE 衡量的不再是"排序对不对",而是"概率值本身准不准"。

3.2 温度缩放:只用一个参数完成校准

温度缩放(Temperature Scaling)是我个人最喜欢的校准方法,因为它极度简单,但效果出奇好。做法是在模型最后的 logits(也就是进入 sigmoid 或 softmax 之前的输出)上除以一个常数 T,再求概率。T 就是温度参数。T=1 相当于什么都不做;T>1 会让概率分布变得更平坦(降低模型自信);T<1 会让概率分布更尖锐(提高自信)。

温度缩放不改变模型的预测类别方向,只改变"自信程度",所以它不会破坏模型的排序能力(AUC 不变),但能明显改善概率校准。T 的取值不需要重新训练模型,只需要在验证集上最小化交叉熵。对二分类来说,就是:

pred_calibrated = sigmoid(logits / T)

然后用网格搜索或者 scipy.optimize 找一个让验证集 BCE 最小的 T。

用代码来写的话,一个极简的实数优化就够:

import numpy as np from scipy.optimize import minimize from sklearn.metrics import log_loss def temperature_scale(logits, y_true, init_t=1.0): def objective(t): probs = 1.0 / (1.0 + np.exp(-logits / t)) return log_loss(y_true, probs) # log_loss 就是二元交叉熵 result = minimize(objective, x0=init_t, method='nelder-mead') return result.x[0]

注意,温度缩放的模型已经不能再用原始训练集上的表现来评估了,一定要用模型没见过的验证集去拟合 T,否则会过拟合。我在实际项目中见过不少人把 T 在训练集上求,结果验证集上的校准误差反而变大,最后还把锅甩给方法本身。其实只是使用姿势不对。

4. 从二分类到四分类:花卉模型里的交叉熵演化

4.1 多分类交叉熵是二元交叉熵的自然延伸

热词里提到的"训练四分类花卉模型玫瑰图片",其实就是交叉熵从二分类走向多分类的经典场景。四分类不比二分类复杂多少,逻辑上只是把 sigmoid 换成 softmax,把二元的 BCE 变成多元的 Categorical Cross-Entropy(CCE)。

softmax 的作用是把一组实数 logits 变成总和为1的概率分布。假设花卉分类有四类:玫瑰、向日葵、郁金香、薰衣草,模型最后一层输出四个 logits:z1、z2、z3、z4,softmax 后得到 p1、p2、p3、p4。CCE 的计算公式是:

L = -sum(y_i · log(p_i))

其中 y_i 是 one-hot 标签。因为 one-hot 向量里只有一个位置为1,其他都是0,所以这个求和其实只取真实类别对应位置的 -log(p_i)。这和二元交叉熵里"只看真实标签那一项"的逻辑完全一致。

我在做花卉识别的时候,遇到过一种情况:图片里玫瑰占主体,但背景里有几朵向日葵,模型经常把置信度分散在玫瑰和向日葵之间。这时候 CCE 就起作用了。它不要求模型在其余类别上都输出0,只要求真实类别上的概率尽量高。如果模型给了玫瑰0.7、向日葵0.2、其他两个各0.05,loss 是 -log(0.7),不算大;但如果模型觉得向日葵更像主体,把玫瑰压到0.2,loss 就会跳到 -log(0.2),惩罚立刻变大。

4.2 四分类花卉模型的三个实操关键点

第一点:训练时用 logits 而不是 softmax 之后的概率做损失。很多框架的损失函数(比如 PyTorch 的 CrossEntropyLoss,TensorFlow 的 CategoricalCrossentropy with from_logits=True)都内置了 softmax 和 log 的融合。这个融合不仅仅是省事,更是数值稳定性的需要。直接对 softmax 结果取 log,当概率接近0时会产生无穷大或 NaN,而框架内部用 log_softmax 计算可以避免精度溢出。我自己踩过这个坑,早期在自研代码里先手动 softmax 再 log,训练到一半 loss 直接变成 NaN,排查了很久。

第二点:类别不均衡会直接扭曲概率输出。假设数据集里玫瑰图片占了80%,其他三类各占不到7%。如果不做任何处理,模型很容易学成一个"偏科生":看到什么都倾向玫瑰,输出概率整体上偏自信。简单的做法是给少样本类别加权重,让它们在损失函数里的地位更高。PyTorch 里可以直接给 CrossEntropyLoss 传 weight 参数,权重一般可以设为"样本量的倒数"。

第三点:训练增强不能太激进。对花卉分类来说,随机裁剪、翻转、颜色抖动都有效,但过度的颜色扰动会让模型对花瓣色彩信息变得不敏感,导致概率输出整体涣散。我做过一次对比,颜色增强强度提高2倍后,准确率只掉了0.3%,但验证集上的平均置信度从0.84降到0.71,校准误差明显变大。概率校准对增强策略的敏感性,很多人是忽略了的。

5. xgboost二分类模型的概率校准落地

5.1 树模型与神经网络:同样的BCE,不同的概率味道

xgboost 做二分类时,目标函数用的正是二元交叉熵(也叫 logloss)。从数学上看,xgboost 和神经网络在二分类上用的是同一个损失函数,但两者输出的概率质量却常常差异很大。神经网络天然受 softmax 和权重衰减的约束,概率分布相对柔和;而树模型在分裂叶子节点时,只需要让每个叶子内部的样本纯度变高,很容易在某些叶子上塞满同类别样本,导致输出概率'虚高'。

举个我在信贷场景里的例子(业务上对概率真实度要求极高):xgboost 模型在验证集上 logloss 很低,但把预测概率直方图画出来后,发现大量负样本的概率集中在0.99以上。用 AUC 评估没问题,但一旦用"预测概率大于0.95"作为通过规则,就会发现误杀率远高于预期。树模型尤其是深层树+少量样本时,叶子节点可能就几个样本,几个正样本一扎堆,叶子就给一个接近1的概率。这是树模型概率虚高的常见根源。

5.2 Platt缩放和Isotonic回归怎么选

针对树模型的概率校准,工业界最常用的两个方案是 Platt Scaling(逻辑回归校准)和 Isotonic Regression(保序回归)。

Platt Scaling 在二分类里就是用一个带截距的逻辑回归模型,把原始预测概率作为特征,拟合真实标签,得到新的校准概率。它的优点是稳定、不容易过拟合,缺点是只能用单调的变换,表达能力有限。适合样本量不大、原始概率偏差比较规则的情况。

Isotonic Regression 是一个非参数的保序回归,它可以把原始概率映射到新的概率上,不限定映射形状,完全由数据驱动。它能拟合更复杂的偏差模式,但需要足够多的样本才能学得稳。经验法则:数据量超过1万条,可以放心用 Isotonic;数据量只有几千条,优先用 Platt。如果原始概率和真实频率的关系已经大致是单调的,两者差别不会大;但如果是 S 型或更扭曲的关系,Isotonic 优势明显。

5.3 校准后的阈值要怎么重新定

校准会改变概率的绝对数值,但不改变样本间的相对排序。所以校准前你用的阈值0.5,校准后不一定还合适。一个非常容易掉的坑是:模型校准后,业务方拿着以前定的0.5阈值去跑,发现召回率掉了一截,立刻怀疑是校准搞坏了模型。其实校准只是把概率拉回到真实频率附近,之前0.5阈值之所以"好用",恰恰是因为原始概率严重扭曲,碰巧在0.5附近分开了好坏样本分布。

正确的方式是校准完成后,重新在验证集上画 PR 曲线或 ROC 曲线,根据业务可接受的精确率/召回率重新寻找阈值。我在实践中通常会在校准前记录原始概率的百分位数(比如P50=0.72),校准后找接近业务容忍度的阈值。这里也推荐大家用 reliability diagram(可靠性图)来辅助判断:横轴是模型预测概率分桶,纵轴是真实正样本率,理想情况应该贴着对角线。

6. 常见问题与排查技巧实录

6.1 "模型概率一直靠近0.5,怎么调都没用"

这大概是分类模型实践者最常遇到的困惑。模型概率集体往0.5挤,本质上是模型没有得到足够强的信号把正负样本切开。我从经验和排查顺序上列一张表,大家可以直接照着查:

表现常见原因排查方向
所有预测集中在0.4-0.6特征区分度不足,模型只能学会微弱偏好检查特征与标签的单变量相关性,考虑特征工程
训练集上也是0.5附近学习率过大或模型容量太小调低学习率,适当增加模型深度/迭代轮数
训练集很好,验证集全挤在0.5数据分布偏移,或有信息泄露导致的虚假信号做时间切片验证,检查特征是否在未来才可取
使用MSE或自定义损失函数梯度饱和让模型卡在模糊区换回二元交叉熵,配合sigmoid

有一个容易被忽略的点:类别极度不均衡时(比如正样本只有1%),即使模型学得不错,概率输出往往也偏低。这时可以先用加权交叉熵(给少数类更大的权重)训练,再在验证集上做温度缩放或 Platt 校准。先加权再校准,比纯加权更稳。

6.2 校准前后一定要盯的几个指标

校准不是无损操作。虽然它不改变 AUC,但会改变精确率和召回率的平衡点,也会影响你的业务指标。所以我每次做校准项目,都会要求自己记录四样东西:校准前的 logloss、校准后的 logloss、校准前的 ECE、校准后的 ECE。logloss 下降说明概率质量整体提升,ECE 下降说明概率值更贴近真实频率。

如果你发现校准后 logloss 上升了,别急着否决校准。此时要先看两个数值:一个是排序指标(AUC/Gini)是否稳定,另一个是可靠性图是否更贴近对角线。有时候 logloss 微升但 ECE 明显下降,说明校准把分布拉均匀了,个别极端值反而偏离了,这在业务上可能可以接受。核心原则是:先确认校准的目标是"更准的概率值",而不是"更低的数学指标"。目的不同,评估方式就不同。

6.3 独家技巧:把校验集拆成"校准集"和"评估集"

这是我踩过几次坑之后总结出来的一个建议。做概率校准最忌讳的就是用训练集算校准参数,再用同一个验证集去报告校准效果。正确做法是:在原始训练集里再切出一部分作为"校准集",专门用来拟合温度 T 或 Platt 系数;而"评估集"只用来最终报告校准前后的指标。我在一个实际项目里试过,如果只在单一验证集上又校准又评估,ECE 会显得比真实水平低大约20%——看起来效果好,实际上方法在上线后明显退化。

另外一个实操细节:温度缩放和 Isotonic Regression 都不是越复杂越好。先跑一次最简单的 Platt Scaling,画出可靠性图,如果图基本贴着对角线,就不用上 Isotonic。非参数方法在小样本下容易学进噪声,反而把校准搞得更糟。

我个人在实际操作中的体会是,交叉熵和概率校准是一体两面的事。交叉熵负责在训练阶段教模型"如何把概率输出得尽量准确",而校准是在训练结束后帮模型"修正残留下来的系统性偏差"。很多人只盯着模型排序能力,却忘了概率本身也是模型交付的一部分。一个能告诉你"这件事有87%的把握"的模型,和一个只说"这事很可能发生"的模型,在业务决策里的价值完全不在一个量级。

最后再分享一个小技巧:如果你在做任何带 sigmoid 或 softmax 输出的模型,建个习惯,每个迭代周期后把验证集的预测概率直方图打出来看一眼。不需要多复杂的分析,就看两点:分布是不是太集中在0.5附近,是不是有明显的双峰但双峰之间没有过渡。这两种情况都是模型在概率表达上出问题的早期信号。早发现早处理,比最后校准救火要省事得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询