标签平滑:为什么正确类别目标不是1−ε

黎 浩然/ 22 10 月, 2026/ 大语言模型/LARGELANGUAGEMODEL/LLM, 教程/TUTORIAL, 计算机/COMPUTER/ 0 comments

采用非零label_smoothing时,正确类别的目标概率通常不再是1,交叉熵也不再以接近0为理想终点。若使用均匀分布混合,三分类、平滑系数0.3、标签为第0类时,目标是(0.8,0.1,0.1),不是(0.7,0.15,0.15)。这一个差别,会同时改变损失、梯度与最优logit间距。

文章目录
  1. 先确认epsilon究竟分给了谁
  2. 预测越自信,平滑损失不一定越低
  3. 非零损失下限,可以从目标熵算出来
  4. 平滑两次,不是仍然使用同一个epsilon
  5. 用有限差分核对目标,而不是只看loss能否下降
  6. 训练目标与评估口径应分别记录
  7. 来源与补发说明

这里把标签平滑拆成一份可以手算、可以执行的目标函数:先核对分配规则,再解释高置信预测为何可能被往回拉,以及为什么不能把平滑后的训练损失直接当作普通NLL。Read in English。

先确认epsilon究竟分给了谁

PyTorch 2.8的CrossEntropyLoss定义将label_smoothing描述为原始标签与均匀分布的混合。本文限定单样本、C≥2、没有类别权重、没有忽略项,令ε为混合比例,qⱼ=(1−ε)·1[j=y]+ε/C。

均匀分布包含正确类别,所以它也收到ε/C。取C=3、ε=0.3,正确类别得到0.7+0.1=0.8,另外两类各为0.1。若另一个实现只把0.3分给两个错误类别,就得到(0.7,0.15,0.15);两种规则都能形成概率分布,却不是同一个目标。

排查跨实现差异时,不要只对照参数名和ε值。把真实目标向量打印出来,检查总和、正确类别质量、错误类别分配。边界也有明确含义:ε=0恢复硬标签,ε=1则完全变成均匀目标,不再保留这个样本的类别指向。它仍是一份损失,不能理解成“忽略该样本”。C变化时,同一个ε的每类分配也会变化;复制某个三分类推导到大词表时,需要重新代入类别数。

原始方法的公式可在2015年Inception论文预印本v3第7节核对。这里使用的是公开预印本中的方法定义,不把它包装成近期突破,也不复述图像分类成绩来承诺今天任务会获益。

硬标签:(1,0,0)
均匀分布:(1/3,1/3,1/3)
混合:0.7×硬标签+0.3×均匀
目标:(0.8,0.1,0.1)
原创目标图:均匀混合也把概率分给正确类别。

预测越自信,平滑损失不一定越低

固定目标q,定义L=−Σⱼqⱼlog pⱼ,p由logits z的Softmax得到。无权重且Σq=1时,可改写L=logΣⱼexp zⱼ−Σⱼqⱼzⱼ,逐项求导便得到∂L/∂zⱼ=pⱼ−qⱼ。这个推导不需要把ε当成某个神秘惩罚系数。

对p=(0.98,0.01,0.01),硬标签对正确类logit的导数是0.98−1=−0.02,梯度下降还会推高它。平滑目标给出的导数却是0.98−0.8=0.18,梯度下降会降低它;两个错误类别各为0.01−0.1=−0.09。预测类别仍正确,但置信程度已经超过这个训练目标希望达到的位置。

这不是“模型正确却被错误标签惩罚”的运行时异常,而是优化目标改变后的正常结果。它能解释一次梯度的方向,不能证明训练后的准确率、校准程度或分布外表现一定更好。后者需要独立数据和实际实验。

预测p:(0.98,0.01,0.01)
硬目标:正确类梯度−0.02
平滑目标:正确类梯度+0.18
固定目标下:梯度为p−q
原创梯度对照:同样预测正确,两种训练目标可以给出相反方向。

非零损失下限,可以从目标熵算出来

对正的q,交叉熵可以分成H(q)+KL(q∥p)。因为KL不小于0,允许自由选择概率分布时,最小值在p=q处达到,等于目标熵H(q)。三分类例子的下限约为0.639032;不能因为训练损失长期不低于这个数,就先断言优化器失效。

在p=q=(0.8,0.1,0.1)时,正确类别与任一错误类别的logit差可以为log(0.8/0.1)=log 8,约2.07944,整体加同一个常数不影响概率。硬标签则把理想概率放在边界(1,0,0),有限logits不能精确达到这个边界。

这里的下限针对单一、可自由拟合的目标分布。一个共享参数模型面对许多不同样本,未必能让每个样本都恰好达到q;类别权重、额外正则项和归约方式也会改变读数。把0.639032当作所有模型的预计收敛值,同样是误用。

更适合保留的诊断量,是同一固定目标下“当前损失减去目标熵”的差距。它在本例恰好是KL;不混入其他损失时,这比要求所有训练配置的原始交叉熵都降到同一标尺更有解释力。

平滑两次,不是仍然使用同一个epsilon

假设数据管线先把硬标签变成q₁=(1−ε₁)eᵧ+ε₁u,损失端又按比例ε₂混入同一个均匀分布u。展开后q₂=(1−ε₂)(1−ε₁)eᵧ+[1−(1−ε₂)(1−ε₁)]u,因此有效平滑比例是ε_eff=1−(1−ε₁)(1−ε₂)。

两次都使用0.3,最终不是0.3,也不是简单相加的0.6,而是0.51。三分类目标从(0.8,0.1,0.1)变成(0.66,0.17,0.17)。这段是混合分布的代数推导,不假定某个训练框架一定替你重复平滑;应检查实际数据与损失路径是否存在两次变换。

尤其是已有软标签、蒸馏分布或样本混合时,先确认目标语义,再决定是否继续向均匀分布混合。相同参数数值并不保证相同有效目标。本文不把所有软标签都归为标签平滑,也不声称二次混合必然是错误设计。

用有限差分核对目标,而不是只看loss能否下降

下面实际执行Python标准库计算:检查两种分配规则、ε边界、过度自信时梯度反向、三个logit的有限差分、目标熵下限、有限间距,以及双重平滑。Softmax的稳定计算方式沿用减最大值的推导,这里不重复扩写。

# Standard-library objective and finite differences; no PyTorch execution.
from math import exp,log,fsum,isclose,isfinite
checks=0
def check(ok):
    global checks
    assert ok
    checks+=1
def target(c,y,e):
    if c<2 or not 0<=y<c or not isfinite(e) or not 0<=e<=1:
        raise ValueError('invalid target configuration')
    return [(1-e)*(j==y)+e/c for j in range(c)]
def lp(z):
    m=max(z); a=m+log(fsum(exp(t-m) for t in z))
    return [t-a for t in z]
def ce(z,q):
    if len(z)!=len(q) or not z or not all(isfinite(t) for t in z):
        raise ValueError('invalid logits or length')
    if not all(isfinite(t) and t>=0 for t in q) or not isclose(fsum(q),1):
        raise ValueError('invalid probability target')
    return -fsum(a*b for a,b in zip(q,lp(z)))
q=target(3,0,.3)
check(all(isclose(a,b) for a,b in zip(q,[.8,.1,.1])))
check(isclose(sum(q),1))
check(target(3,0,0)==[1.,0.,0.])
check(all(isclose(t,1/3) for t in target(3,0,1)))
wrong=[.7,.15,.15]
check(not all(isclose(a,b) for a,b in zip(q,wrong)))
z=[log(.98),log(.01),log(.01)]
p=[exp(t) for t in lp(z)]
check(p[0]-q[0]>0 and p[0]-1<0)
for j in range(3):
    a=z.copy(); b=z.copy();a[j]+=1e-5;b[j]-=1e-5
    numerical=(ce(a,q)-ce(b,q))/(2e-5)
    check(isclose(numerical,p[j]-q[j],rel_tol=1e-7,abs_tol=1e-9))
opt=[log(t) for t in q]
h=-fsum(t*log(t) for t in q)
check(isclose(ce(opt,q),h) and h>0)
check(ce(z,q)>h)
check(isclose(opt[0]-opt[1],log(8)))
q2=[.7*t+.3/3 for t in q]
check(all(isclose(a,b) for a,b in zip(q2,target(3,0,.51))))
for e in (-.1,1.1,float('nan')):
    try:target(3,0,e)
    except ValueError:check(True)
    else:check(False)
for bad_z,bad_q in [([0.,0.],[1.]),([0.,0.],[.8,.8]),([0.,0.],[1.1,-.1])]:
    try:ce(bad_z,bad_q)
    except ValueError:check(True)
    else:check(False)
print(checks,'objective checks passed')
print('target',q,'minimum',h,'overconfident loss',ce(z,q))
print('double smoothing',q2,'finite logit gap',log(8))

程序没有运行PyTorch、训练模型或评测数据集。它证明列出的目标函数与数值导数相符;对项目集成,仍需在实际loss调用上对照无归约输出、目标格式和梯度,确认没有类别权重、忽略规则或额外混合改变前提。

代码中的ce会拒绝长度不匹配、非有限logits以及负数或未归一化目标,并有三个对应反例。它仍是单样本教学函数;批次、类别权重和mask不在实现范围内。演示把这些条件写出来,是为了防止正常的有限差分掩盖了错误的目标格式。

训练目标与评估口径应分别记录

对q=(0.8,0.1,0.1)且预测p=q,平滑交叉熵约0.639032,而原始标签对应的NLL是−log 0.8,约0.223144。两个数字描述同一次预测,却回答不同问题。不要把平滑训练损失直接代入exp当作按原始标签计算的困惑度,再与普通NLL配置比较。

准确率只看最终类别排序,无法独自反映这些概率差异;概率校准还需要另外的评价口径。保存ε、类别数、目标构造、权重、mask与归约规则,才能判断一次损失变化究竟来自模型还是定义。关于其他目标变换,站内pos_weight与原始概率讨论的是二分类权重,机制不同,不能互换修正公式。

若这些目标向量、熵下限和有限差分帮你定位了标签平滑的差异,欢迎在文末自愿支持。最容易复用的起点,是先用三类数据复现同一目标,再接回真实训练管线。

来源与补发说明

CrossEntropyLoss 2.8 · Inception preprint v3, Section 7 · Preprint version history

依据原计划日期前已有的PyTorch 2.8定义与2015年12月11日修订的论文预印本核对。原创推导和标准库检查不等于训练复现。保留2026年10月22日09:00北京时间文章日期,实际补发时间另行记录;这不表示文章此前已公开。

支持

如果文中的解释或示例帮你解决了问题、节省了时间,欢迎自愿打赏支持本站。

微信支持二维码,点击查看大图
微信
支付宝支持二维码,点击查看大图
支付宝
Buy Me a Coffee,点击支持本站
Buy Me a Coffee

二维码可点击放大。更多支持方式见支持页面。

Share this Post

Leave a Comment

您的邮箱地址不会被公开。 必填项已用 * 标注

*
*