☰
微调时loss曲线一直降,效果却变差?一文讲透loss骗人的原因与监控方案
2026/10/24 4:45:17 网站建设 项目流程

我一直有个习惯:训练跑起来之后,第一件事不是看准确率,而是盯 loss 曲线。loss 降了,心里踏实;loss 不动,就开始焦虑。如果你也有这种感觉,那这篇文章大概率能帮你省下几周的无效调参时间——因为在微调场景里,loss 这个指标不仅会骗人,而且骗得有理有据、骗得让人毫无防备。它是最容易让从业者“自嗨”的指标,没有之一。这不是说 loss 没用,而是它的作用被我们严重高估了。这篇内容来自我自己踩过的一些坑,适合正在做模型微调、指令微调或者任何深度迁移学习任务的开发者参考,尤其是刚入门、习惯拿 loss 曲线当“健康指标”的朋友。

1. 先搞清楚:loss 到底在衡量什么

1.1 你优化的是代理目标,不是业务目标

先复习一个老概念。深度学习里,我们从来没直接优化过“业务成果”。做文本分类,业务目标是准确率、召回率、F1;做生成任务,业务目标是回答有没有用、格式对不对、逻辑通不通;做推荐,业务目标是点击率、转化率。但我们训练的时候,优化器手里的唯一信号是 loss——它是所有这些目标的“代理”。代理的意思是,它只是近似地、间接地反映目标,而不是目标本身。

我常打的一个比方:loss 是考卷里的“模拟题”,业务指标才是“高考题”。模拟题做得好,不一定高考就考得好,尤其是当你发现模拟题出得和真题风格不一致的时候。微调阶段最大的问题就是,我们很多人的训练流程里只有模拟题成绩(loss),从来不看真题成绩(业务指标),最后模型上线翻车了才回头找原因。

1.2 loss 曲线的天然诱惑:它给了你“正在变好”的控制感

loss 曲线之所以诱人,是因为它每一轮都在更新。你可以看着它从 2.1 慢慢降到 1.8、再到 1.5,那种平滑下行带来的“掌控感”,是任何指标都替代不了的。而业务指标往往不是每步都更新的——你不可能每 100 步就跑一遍完整评测集,也没法实时让真人给生成结果打分。于是你只能盯着 loss,用它的变化来推测模型好坏。

问题是,loss 的变化方向和业务指标的变化方向,在微调阶段有相当高的概率是不一致的,而且越接近收敛、越容易背离。我见过太多团队,训练日志里 loss 一路走低,看起来一切尽在掌握,结果 lr_scheduler 还没走完,验证集上的效果已经退化到和没训差不多。这种“loss 自嗨”几乎每个搞过微调的人都经历过,只是很多人没刻意总结过为什么。

1.3 loss 是训练集上的记忆信号,不是泛化信号

一个更本质的点:训练时你看到的 loss,几乎都是训练集或验证集上的经验风险。经验风险只能告诉你“模型对当前数据的拟合程度”,它不能告诉你“模型在新数据上的表现”。而我们在微调场景下最关心的是后者,也就是泛化能力。

这就像学生每天做同一本练习册,练习册上的题正确率越来越高,但期末考试换成新题就不一定了。loss 下降充其量说明模型正在适应你喂给它的数据分布,至于这个适应是“学会了规律”还是“背下了答案”,仅凭 loss 曲线是区分不了的。要区分,只能靠独立评测。

2. loss 在微调场景下更容易骗人的五个原因

2.1 训练集 loss 下降,常常就是过拟合的开始

微调阶段和预训练阶段有个本质区别:预训练数据以亿计,微调数据往往只有几千条到几十万条。数据量小,模型容量大,就极容易过拟合。过拟合的典型信号之一,就是训练集 loss 持续下降、验证集 loss(或验证集业务指标)反向恶化。

但很多人只看训练集 loss,因为它每个 step 都在更新,而验证集指标可能一两个 epoch 才评估一次。等验证集指标终于跑出来,发现已经崩了的时候,模型可能已经过拟合了好几个 epoch。我在实际项目里见过一种更讽刺的情况:训练 loss 降到了 0.05,验证集准确率却从 90% 掉到 60%。为什么会这样?因为微调数据里往往有重复样本。模型只要记住那几千条重复数据的标准答案,训练 loss 就能压得极低,但这种“记忆”完全无法泛化到验证集的同分布新样本上——尤其当验证集和训练集同源采样时,这种风险更隐蔽。

2.2 数据噪声会让 loss 下降的方向和“正确”方向完全不同

微调数据很少是干净的。指令微调数据里有错误答案、劣质翻译、标注不一致,这些噪声在数据集中占比可能只有 5%,但足以把 loss 的下降方向带偏。

举个例子。做文本分类微调,你有 1000 条样本,其中 50 条标签打错了。模型开始会正常学,学到后期,它的 loss 在这 50 条错误样本上会显得很高。优化器为了压掉这些 loss,就会调整决策边界去迎合错误标签。表现为:训练 loss 继续降,但验证集 F1 在某个点之后开始掉。如果你只盯着训练 loss,你根本不会在正确的时间点做 early stopping,而是会等它彻底过拟合。

更麻烦的是,很多人把训练集和验证集都放在同一个清洗流程里,验证集里也有噪声。这个情况下 loss 会表现出一种“假收敛”:训练 loss 和验证 loss 都降得不错,但你去人工检查模型输出时,会发现它在很多简单 case 上犯低级错误。因为验证集里的噪声样本,把评估结果也一起“污染”了。

2.3 生成任务里 loss 存在不敏感区间

如果是文本生成类微调,比如做指令微调,loss 的欺骗性比分类任务更严重。原因在于 token 级别的交叉熵对答案质量的敏感度很低。

假设一个回答有 100 个 token,模型在关键的第 80 个 token 上预测错了,导致整句话含义完全相反。但从 loss 的数值看,这 100 个 token 里只有 1 个 token 错了,loss 只上升了一点点。反过来,如果模型在每个 token 上的置信度都稍微均匀一点,loss 可能上升更多,但生成结果反而更稳、更合理。

还有一个我印象很深的点:beam search 的生成质量和 loss 之间没有单调关系。我做过一个实验,同一个模型,loss 更低的那版 checkpoint,用 beam search 生成的结果反而更差。原因在于 beam search 是逐 token 寻优的搜索过程,它对模型给出的概率分布形状非常敏感;而 loss 是平均化的指标,它把每个 token 的误差揉在一起。一个在长尾 token 上概率稍微更准的模型,loss 数值会更好看,但 beam search 核心路径上的概率可能反而更差。

2.4 推理策略和评测方式,loss 全都管不着

这点最容易被忽略:loss 是在训练阶段的优化目标,但模型上线后的表现,取决于你和推理策略之间的配合。同一个 checkpoint,温度设 0.1 和设 0.9,生成结果差异巨大;用 greedy decoding 还是 sampling,输出风格也差很多。这些推理策略层面的变量,不会在 loss 上体现分毫。

更直接的场景是:微调时你用的是“teacher forcing”式的交叉熵训练——也就是每个位置都喂真实的上一 token。但推理的时候模型用的是自回归生成——每一步都吃自己上一步生成的 token。训练和推理的不一致,本身就是 gap 的来源。这种 gap 导致的生成质量下降,loss 是一点都看不出来的。所以很多生成模型微调完,loss 曲线漂亮得可以拿去当教材配图,但一测实际生成就是答非所问,原因就在这里。

2.5 数据泄漏和“背题”现象:loss 越低,反而越要警惕

还有一种更隐蔽的“自嗨”场景:数据泄漏。比如微调数据里混入了测试集的相似样本,或者用未经过去重处理的公开数据做评测。这种情况下,模型并不是学会了通用的规律,而是直接把评测集里的答案背下来了。

背题的直接表现就是训练 loss 和验证 loss 都很低,业务指标也非常高——但你换个稍微有点分布偏移的测试集,效果立刻跳水。我见过有人拿着这种模型报喜,号称准确率从 80% 提到了 95%,结果重新整理评测集之后,真实水平直接打回原形。这种数据泄漏带来的假象,比过拟合可怕得多,因为它会让团队误判模型的实际能力,做出错误的上线决策。

3. 一个真实案例:loss 一直降,效果却崩了

3.1 背景与配置

我来说一个自己经历过的案例,细节做了脱敏处理,但过程非常典型。当时接了一个任务,要做某个领域的指令微调,基座模型是一个 7B 规模的开源预训练模型,训练数据大概 2 万条指令-回答对,验证集 2000 条,来自同一个数据源但做了去重。

训练配置用的是 LoRA 微调,rank 设为 16,学习率 2e-4,训练 3 个 epoch,batch size 32,混合精度。日志平台里每 100 步记录一次训练 loss,每个 epoch 结束跑一次验证集 loss 和验证集上的 ROUGE-L。整套配置看得出来吗?当时我心里觉得挺“标准”的,问题恰恰出在这个“标准”上。

3.2 过程复盘:指标间完全脱节

训练开始之后,训练 loss 从 1.2 一路降到 0.4,肉眼可见的丝滑。验证集 loss 也从 1.3 降到了 0.8,看着问题不大。我甚至已经有“这次稳了”的错觉。

真正发现问题是在第二个 epoch 结束后的手动抽检。我把验证集里的一部分生成结果打印出来看,发现模型输出的格式已经开始出问题:该分段的地方没有分段,该结束的地方绕来绕去不结束,甚至有些回答开始出现“呃”“嗯”这种无意义填充。但此时训练 loss 还在继续下降。

到了第三个 epoch,验证集 ROUGE-L 不升反降,比第一个 epoch 结束时还低了 3 个点。也就是说,模型在最该继续变好的阶段,实际效果已经在退化,而训练 loss 曲线还保持着一路向下的姿态。如果当时不看验证集生成样本,只看 loss,我大概率会在这个“最佳”checkpoint 上停下来,然后带着一个过拟合模型上线。

3.3 排查逻辑与结论

回头排查,最后定位到的核心原因是过拟合加上数据噪声叠加。那 2 万条数据里有一些重复度较高的模板,LoRA 其实很容易把它们“背”下来,导致训练 loss 越来越低。但验证集去重做得比较好,模型在新样本上的泛化能力并没有同步提升,一个 epoch 之后就达到最佳点了。

这件事给我留下一个固定流程:热身的第一个 epoch 过后,每个 checkpoint 都必须做样本级抽检,而不是只看指标。尤其是生成类模型,人工看 20 到 30 条输出比任何单一数值指标都靠谱。你可以很快建立起“模型正在变好还是变坏”的直觉——这种直觉是 loss 曲线永远给不了你的。

4. 那到底该盯哪些指标?实操监控方案

4.1 验证集指标优先,且要与业务对齐

先把原则立住:验证集指标永远优先于训练集 loss,业务相关指标优先于通用指标。

具体做法是,在训练前先明确一个“主指标”,这个主指标必须和业务目标对齐。分类任务就用 F1 或准确率;检索任务就用 Recall@K;生成任务就用 ROUGE/BLEU 作为粗筛,加上人工抽检作为最终判断。主指标确定之后,所有的 early stopping、checkpoint 选择、学习率调整,都应该围绕它来做,而不是围绕 loss。

如果你的任务没有一个现成的量化指标,比如“回答有没有帮助”,那也要在训练前设计一个可重复的人工评价框架,哪怕只是 5 级打分。没有评价框架就开始调参,本质上就是闭着眼睛开车。

4.2 样本级人工抽检应该固定成流程

这是我个人最推荐的一种“指标”:每隔固定步数(比如每 500 步或每个 epoch),从验证集随机抽 20 到 30 条样本,把模型的输出打印出来肉眼过一遍。不要只看训练器的日志,也不要只看 loss 曲线,一定去“读”模型实际生成的东西。

做法很简单:把模型生成的文本和真实答案并排打出来,快速标记是否有明显问题——格式错误、重复、跑题、幻觉。只要连续两个 epoch 的抽检结果开始变差,即使 loss 还在降,也该考虑回滚或 early stopping。这个操作看起来“不智能”,但它能捕获到一切数值指标都可能遗漏的定性退化。

4.3 辅助动态指标:梯度范数、权重更新幅度、激活分布

除了验证集指标,还有一些训练动态指标可以作为辅助判断。

第一,梯度范数。训练正常时,梯度范数会在一个合理区间内波动。如果梯度范数突然暴涨或归零,通常意味着训练出了问题,比如学习率过大、数据异常、或者已经进入了过拟合后期。第二,权重更新幅度。LoRA 这类参数高效微调方法里,如果权重更新的幅度大得离谱,那模型原始能力可能已经被破坏,生成结果往往崩坏。一个比较实用的检查方法:对比微调前后的输出,对同一组 prompt 做差异统计,如果差异过大,说明微调破坏性太强。第三,激活分布或 logits 分布。如果模型输出的 logits 越来越尖锐,说明模型对自己的预测越来越“自信”,但这种自信不一定代表正确——尤其在过拟合时,模型会变得过度自信。

4.4 落地方案:把指标组织到一张表里

我自己的做法是:训练过程中同时开三块监测面板。第一块是损失曲线,包括训练 loss 和验证 loss,但只作为“是否有异常波动”的粗筛。第二块是业务指标曲线,比如每 K 步跑一次验证集上的主指标,这个才是真正用于决策的信号。第三块是抽检面板,每 K 步自动把若干条生成结果和 prompt 打印到日志里,方便人工扫一眼。

这三块信息合在一起,才能组成一套相对完整的训练监控体系。只盯着其中任何一块,都会产生盲区。顺便说一句:如果你用在线日志平台记录这些指标,记得在实验里同时记录数据版本、模型版本、超参数,否则后面想复盘的时候会非常痛苦。

4.5 early stopping 和 checkpoint 策略该怎么定

基于上面的判断,checkpoint 保存策略建议这样设计:每个 epoch(或者每隔固定步数)保存一个带编号的 checkpoint,绝不只在训练结束时保存一次。选择最终模型时,不要在训练 loss 最低点挑,也不要在最后一个 epoch 挑,而是在验证集主指标最高点所在的 checkpoint 附近再精修几天。

early stopping 的 patience 也建议以验证集业务指标为准,而不是看 loss。比如设定“如果验证集主指标连续 2 个 epoch 没有提升,就回滚到最佳点并停止训练”。这套策略看起来很保守,但能杜绝“loss 自嗨”带来的大部分损失。

4.6 关于学习率和收敛的一个额外提醒

很多人习惯看到 loss 不降了就认为“模型已经收敛”,然后提前结束训练。但微调场景里,loss 不降很可能只是因为学习率过低,或者数据里的噪声样本在拖后腿。这时候不是停止训练,而是应该调整学习率、重新计算数据筛选策略,或者干脆判定当前数据量已经不够支撑进一步优化。

反过来,loss 还在降也不代表应该继续训练。回到前面的案例,训练 loss 一直降到底,结果业务指标早就崩了。所以 loss 曲线的“趋势”只能用作训练是否稳定的参考,不能用作是否应该停止的决策依据。

5. 常见问题速查:训练现场速查表

5.1 训练 loss 一直降,但验证 loss 开始上升

这是教科书级别的过拟合信号,没什么好犹豫的:模型开始记忆训练数据,但丧失泛化能力。此时优先回滚到验证 loss 最低点对应的 checkpoint,然后考虑减少训练轮数、增加数据增强、提高 dropout,或者引入早停机制。

但如果验证 loss 上升的同时,验证集业务指标也在上升,那就出现了“指标背离”现象。这种情况偶尔会发生,通常是因为业务指标和 loss 的度量方式不一致——比如分类任务里 F1 对阈值不敏感,而 loss 对置信度很敏感。这种时候以业务指标为准,不用过度关注 loss 的上升。

5.2 loss 震荡很剧烈正常吗

要看阶段。训练初期 loss 震荡大是正常的,尤其是学习率比较高时。但到训练中后期,如果训练 loss 还是大幅震荡,就要排查了:batch size 是否太小、学习率是否需要衰减、数据里是否存在标注噪声大的样本。

这里有个经验值供参考:如果训练 loss 的震荡幅度和它的绝对值在同一个量级,问题比较大。应该先降到一个小数量级,再做进一步判断。

5.3 两个任务的 loss 能直接比大小吗

不能。loss 的绝对数值和任务类型、数据规模、token 数量、标签分布都有关系,跨任务比较 loss 没有意义。

我见过有人搞对比实验时,把 A 任务的 loss 0.5 和 B 任务的 loss 0.2 放在一起比较,得出结论说 B 任务“训得更好”。这个结论站不住脚,因为两个任务的 loss 量纲都不一定相同。正确的比较方式是只看同一个任务、同一种数据分布下的相对变化,而不是跨任务比绝对值。

5.4 loss 不降了,但我觉得还能继续训

那你的“觉得”不能只建立在感觉上。先确认三件事:学习率是否还有下降空间、验证集业务指标是否还在上升、人工抽检是否还在改善。如果这三件事都还在往好的方向发展,那继续训练没问题。如果业务指标已经不再提升,即使 loss 还能降,也不建议继续——你大概率只是在过拟合的边缘反复试探。

5.5 怎么判断过拟合和欠拟合

欠拟合的表现是训练 loss 和验证 loss 都很高,业务指标低于预期。过拟合的表现则是训练 loss 很低、验证 loss 高,并且两者之间存在明显 gap。

有个更细的经验:如果训练 loss 已经降到接近 0 但验证 loss 还很高,说明模型容量大、数据不够或正则化不足,优先增加数据或正则项。如果训练 loss 降不下去、验证 loss 也跟着高,可以考虑增大模型容量、调低正则、或检查数据质量。

6. 写在最后的个人经验

6.1 我踩过几次坑之后形成的固定动作

我现在做微调时的固定动作是:训练开始前先手工看 30 条验证集真实样本;每个 epoch 结束,打印 20 条新样本的输出对比;训练结束后,回滚到验证集指标最佳的 checkpoint,再做 100 条脱敏样本的人工评测。只有这套流程全部走完,我才会把模型交给下一环节。

我知道这个流程“很重”,但微调阶段的隐性成本本来就很高。一次错误的 early stopping、一个被 loss 曲线误导的选择,浪费的不仅是训练时长,还有后续评测、人力抽检、部署回滚的整个链路。相比之下,多花十几分钟看样本输出,真的是最便宜的保险。

6.2 最后的自检问题清单

每次训练准备结束前,我都会问自己几个问题:如果我现在把模型上线,它会不会在训练数据之外的世界里犯低级错误?如果只给一个指标来判断模型好坏,我会选 loss 吗?如果验证集换一批数据,我的结论还成立吗?

这三个问题里只要有一个回答得不踏实,就说明训练监控体系还有漏洞。而这个漏洞的根源,往往就是一开始太信任那个看起来永远在下降的 loss 曲线。希望这篇内容能让你在下次微调时,少走一段“自嗨”的弯路。

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

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

立即咨询