本文是《Ai大模型训练教程》系列实战篇,详解语言模型训练中损失函数如何选择:交叉熵/负对数似然的优化目标、Label Smoothing 的作用与参数建议,以及困惑度PPL与loss的换算与正确评估方式,并给出可直接落地的实验对照与排查清单。
语言模型训练的损失函数怎么选:Cross-Entropy、Label Smoothing与困惑度解读
在 Ai大模型训练教程 这套系列里,损失函数(loss)是把“模型输出得好不好”量化成一个可优化目标的核心部件。对语言模型而言,最常见的是 Cross-Entropy(交叉熵)/ Negative Log-Likelihood(负对数似然)。但当你把模型做大、数据变复杂、训练更久之后,会遇到一些实际问题:训练集 loss 降得很快但泛化一般;模型对某些 token 预测过于自信;PPL(困惑度)看起来很好但生成质量不一定同步提升。
本文聚焦“语言模型训练该怎么选损失函数”,并把 Cross-Entropy、Label Smoothing(标签平滑) 与 困惑度 PPL 的关系讲清楚,给出可落地的选择建议、实现步骤与排查思路。
1. 语言模型的训练目标:最大似然与 token 级预测
以自回归语言模型为例,训练目标是让模型在给定上下文时,把下一个 token 的概率分布预测得尽可能接近真实分布。对于一段 token 序列:
[
(x_1, x_2, \dots, x_T)
]
模型学习条件概率:
[
P(x_t | x_{<t})
]
如果把真实 token 视作 one-hot 标签,那么最常用的损失就是 token 级的负对数似然:
[
\mathcal{L} = -\sum_{t=1}^{T} \log p_\theta(x_t | x_{<t})
]
这等价于交叉熵(Cross-Entropy)在 one-hot 标签下的形式。
1.1 为什么“默认选交叉熵”是合理的
- 统计意义清晰:最大化训练数据似然(MLE)。
- 实现稳定:框架都高度优化(softmax + log + NLL)。
- 指标直观:与困惑度 PPL 可直接对应,便于训练监控。
但交叉熵也有典型副作用:当数据存在噪声、标签并非严格确定(语言其实有多种合理下一个 token),模型可能被迫学成“过于自信”的尖峰分布,从而影响校准(calibration)与泛化。
2. Cross-Entropy(交叉熵)到底在优化什么
对单个位置 t,设词表大小为 V,模型输出 logits (z\in\mathbb{R}^V),softmax 后得到概率 (p)。真实 token 为 i,则交叉熵损失:
[
\mathcal{L}_t = -\log p_i
]
其中:
[
p_i = \frac{e^{z_i}}{\sum_{j=1}^{V} e^{z_j}}
]
2.1 一个非常具体的数值直觉
- 如果模型给正确 token 的概率是 0.9:loss = -log(0.9) ≈ 0.105
- 如果概率是 0.5:loss ≈ 0.693
- 如果概率是 0.1:loss ≈ 2.303
loss 对“低概率正确答案”惩罚非常重,这有助于快速纠正错误,但也会鼓励模型把概率推到极端(尤其在训练后期)。
2.2 训练实现的关键细节(实操)
在大模型训练中,你通常不会手写 softmax,而是使用融合算子:
- PyTorch:
torch.nn.CrossEntropyLoss(内部包含log_softmax + nll_loss) - Hugging Face:
labels传入后模型内部返回loss
实操注意点:
- ignore_index(忽略 padding):batch 对齐时 padding token 不应参与 loss。
- shift(标签右移):自回归 LM 训练要让位置 t 预测 t+1。
- 混合精度:用
bf16/fp16时,优先使用框架提供的融合交叉熵,避免数值不稳定。
3. Label Smoothing(标签平滑):它解决什么问题
Label Smoothing 的核心思想:不要把真实标签当作 100% 确定的 one-hot,而是给其他类别留一点点概率质量,防止模型变得过度自信。
3.1 数学形式
对词表大小 V,平滑系数 (\varepsilon\in[0,1]),真实 token 为 i。原 one-hot 分布 q:
- (q_i = 1)
- (q_{j\ne i} = 0)
平滑后分布 q':
- (q'_i = 1 - \varepsilon)
- (q'_{j\ne i} = \varepsilon/(V-1))
损失变为:
[
\mathcal{L}_t = - \sum_{j=1}^{V} q'_j \log p_j
]
3.2 语言模型里为什么特别有用
语言任务天然有多解:
- “我今天要去 ___” 可能是 “上班/学校/超市/旅行…”
- 数据里标注只有一个 token,但其他 token 并非完全错误
Label Smoothing 相当于承认“标注并不完美”,从而:
- 降低过拟合与过度自信
- 改善概率校准(输出概率更可信)
- 在一些任务上提升泛化(尤其小数据、噪声数据、或强正则需求时)
3.3 代价与误区
- 困惑度可能变差:因为你不再严格优化 one-hot 的 NLL,训练 loss 的可比性会变复杂。
- 过大 ε 会伤害可分性:模型学不到“就应该把正确 token 概率打得很高”。
- 对极大词表的均匀平滑并不总是最优:V 很大时,把 ε 均匀摊到 V-1 个 token 上,单个 token 的概率极小,但正则项仍会影响梯度结构。
3.4 实操:ε 取多少更合理
经验建议(从易到难):
- 小模型/数据较少/噪声较多:
ε=0.05 ~ 0.2 - 中大型 LM 预训练:更常见
ε=0.01 ~ 0.1,需要结合验证集指标选 - 已经有很强正则(大量数据 + dropout + weight decay + 早停):可以从
ε=0开始做对照实验
推荐你在训练脚本里做一个最小网格:ε ∈ {0, 0.05, 0.1},只跑 5%~10% 训练步数先看趋势,再决定是否全量训练。
3.5 PyTorch 实现步骤(可直接改进训练代码)
做法 A:直接使用支持 label smoothing 的交叉熵(较新版本 PyTorch 支持):
torch.nn.CrossEntropyLoss(label_smoothing=ε, ignore_index=pad_id)
做法 B:自己构造 smoothed target(更灵活,可做非均匀平滑),伪步骤:
- 得到
log_probs = log_softmax(logits) - 初始化
q'为ε/(V-1) - 将正确 token 位置设为
1-ε - loss =
-(q' * log_probs).sum(dim=-1) - 对 padding 位置 mask 掉,再按 token 数量求平均
大模型训练中通常更推荐做法 A(融合算子更快),除非你要做“按同义词集合平滑”等高级策略。
4. 困惑度(Perplexity, PPL)怎么解读:它与 loss 的关系
困惑度是语言模型最常用的可读指标之一。对平均 token 级交叉熵(以自然对数为底)(\bar{\mathcal{L}}),困惑度定义为:
[
\mathrm{PPL} = \exp(\bar{\mathcal{L}})
]
如果你用的是以 2 为底的对数(bit),则是 (2^{\bar{\mathcal{L}}})。大多数深度学习框架里的交叉熵默认是自然对数,因此常见写法是 ppl = exp(loss)。
4.1 PPL 的直观含义
可以把 PPL 理解成“模型平均每一步有多少种等可能的选择”。
- PPL=1:完美预测(每步都确定)
- PPL=10:相当于每步有 10 个差不多的候选
注意:这只是直觉类比,不是严格等价。
4.2 为什么 PPL 低不等于生成质量一定好
PPL 衡量的是对数据分布的拟合程度,但生成质量还受以下影响:
- 解码策略(greedy / beam / top-k / top-p / temperature)
- 偏好对齐(RLHF/DPO 等会改变“人类偏好”的输出而非纯似然)
- 数据质量与分布:拟合了“坏数据”也能有低 PPL
- 长文本一致性:PPL 是 token 级平均,可能掩盖长程问题
因此在预训练/续训阶段,PPL 是硬指标;但在指令微调或偏好对齐阶段,PPL 往往不是主目标。
4.3 Label Smoothing 下 PPL 还能直接用吗
需要谨慎。
- 如果你训练用的是 label smoothing 的 loss,那么这个 loss 不再等同于真实数据 one-hot 的 NLL。
- 正确做法:评估时用标准 NLL/CE(ε=0)在验证集上算 PPL。
实操建议:
- 训练时可以用 label smoothing
- 验证时固定用标准 CE(不平滑)计算
val_loss和val_ppl - 这样 PPL 才可与其他实验可比
5. 怎么选:Cross-Entropy vs Label Smoothing(决策清单)
下面给出更工程化的选择建议,你可以直接对照自己的项目。
5.1 默认方案:预训练/续训优先 Cross-Entropy
适用:
- 大规模干净语料预训练
- 你追求极致的 PPL 与训练稳定
- 你需要与公开基线严格可比
做法:
- 用标准 CE
- 重点调:学习率、warmup、weight decay、batch size、梯度裁剪、数据去噪
5.2 何时考虑 Label Smoothing
满足以下任意一条就值得尝试:
- 数据噪声较多(爬虫语料、OCR、ASR 转写等)
- 数据量偏小(垂直领域继续训练,语料有限)
观察到过度自信:
- 训练 loss 很低,但验证 loss 不降或反弹
- 输出分布过尖,top-1 概率经常接近 1
- 你更关心泛化/鲁棒性/校准,而不是极限 PPL
推荐起步:ε=0.05。
5.3 一个可执行的实验模板(省时间)
- 固定数据、模型、训练步数、随机种子
- 跑 3 组:ε=0 / 0.05 / 0.1
每组记录:
- 标准验证 CE(ε=0)
- 验证 PPL
- 下游任务/人工评测(如果有)
- 生成时的“胡编率/重复率/毒性”等质量指标(如你们有内部评测)
- 如果 ε=0.05 在验证 CE 与下游质量上更优或持平,则保留;否则回退到 CE
6. 常见坑与排查:loss/PPL 看不懂时怎么处理
6.1 训练 loss 降得很快,但验证 PPL 不降
排查顺序:
- 数据泄漏/切分问题:训练与验证是否重复或分布差异极大
- tokenizer 不一致:训练/验证是否用了同一 tokenizer、同一 special tokens
- padding 与 mask:padding 是否被正确 ignore
- label shift 是否正确:是否预测了当前 token 而不是下一个 token
- 过拟合:加 dropout/weight decay,或尝试 label smoothing
6.2 PPL 数值异常大或异常小
- 异常大:通常是 logits 数值爆炸、学习率过高、未做梯度裁剪、或 label/shift 错位。
- 异常小:可能是验证集泄漏、或把 padding 也算进了 loss(padding token 很容易被预测对,从而虚假降低 loss)。
6.3 训练用了 label smoothing,验证也用了导致 PPL “看起来更好”
这是误导性结果。务必在验证阶段用 ε=0 的标准 CE 来算 PPL,保证可比性。
7. 小结:把选择落到“可复现的指标体系”
在 Ai大模型训练教程 的工程实践中,建议你把损失函数选择当作一个“可复现的实验问题”来做,而不是凭感觉:
- Cross-Entropy:预训练/大数据/追求基线可比性时的默认最优解
- Label Smoothing:数据噪声、数据少、或需要更好泛化与概率校准时的有效正则
- 困惑度 PPL:用标准 CE(ε=0)在验证集计算,作为最硬的训练质量指标之一;但不要把 PPL 当作生成质量的唯一标准
下一步你可以在现有训练脚本中加入 label_smoothing 开关,并建立“训练 loss + 标准验证 PPL + 下游评测”的三件套仪表盘,这会比单看训练 loss 更接近真实可落地效果。
Prev:Transformer训练要点:自注意力、位置编码、LayerNorm与残差的工程含义