☰
损失函数选择与调参实战:从交叉熵到Focal Loss的深度解析
2026/10/19 14:02:24 网站建设 项目流程

1. 损失函数到底在优化什么?先破除几个固有印象

刚开始接触深度学习的时候,不少人都有过这样的阶段:模型不收敛,第一反应是换网络结构、调学习率,或者干脆把优化器从SGD换成Adam,很少有人会第一时间怀疑损失函数选错了。其实损失函数才是整个训练过程的"指挥棒",它定义了模型朝着什么方向优化、以什么标准衡量"对错",比网络结构更直接地影响最终效果。我见过太多案例:网络结构一模一样,只改了一个损失函数,模型从完全学不动直接变成收敛又快又稳。这篇文章就从原理到实践,把常见损失函数掰开揉碎讲清楚,适合正在做分类、回归、检测、分割、对比学习任务的开发者,尤其是踩过"模型不收敛""Loss降不下去""指标和Loss走势不一致"这类坑的人。

先说一个最常见的误区:很多人觉得损失函数值越低,模型就一定越好。这句话只对了一半。损失函数是训练目标,评估指标才是业务目标,两者经常不是一回事。比如训练一个人脸识别模型,用Softmax交叉熵做损失,Loss可以降到很低,但测试集上的人脸验证准确率可能停滞在98%上不去;换成ArcFace这类带角度间隔的损失函数,Loss数值反而更高,但验证准确率却能突破99%。原因就在于损失函数的设计本身就带有"任务先验"——它决定模型学到的特征长什么样。Softmax交叉熵学出来的特征可能是分散的、方向不统一的,而带margin的损失函数强制特征在超球面上形成类内紧凑、类间分离的分布。理解这一点,才算真正开始理解损失函数。

另一个容易忽视的事实是:损失函数的可导性、数值稳定性、对异常值的鲁棒性,直接决定了训练过程是否顺利。举个例子,MSE(均方误差)在分类任务上用,梯度会随着预测概率接近0或1而变得非常小,模型训练速度会越来越慢;而交叉熵在同样情况下梯度依然稳定。这些差别不是理论上的细枝末节,而是实实在在影响训练效率和最终精度的关键因素。

这篇文章不会上来就铺一堆公式,而是从每个损失函数"解决什么问题""梯度有什么特性""在什么场景下用最合适"三个角度展开,配合我实际项目中踩过的坑和验证过的调参经验。读完你至少能回答三个问题:我的任务应该选哪个损失函数?为什么?如果模型不收敛,损失函数是不是该背锅?

2. 分类任务的主战场:交叉熵及其变种到底强在哪

2.1 交叉熵的梯度特性为什么比MSE更适合分类

先从最基础的二分类交叉熵说起。公式长这样:

[ L = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(p_i) + (1-y_i) \log(1-p_i)] ]

其中 (y_i) 是真实标签(0或1),(p_i) 是模型预测的正类概率。很多人只是背过这个公式,但没想过它和MSE的本质差别。我们把sigmoid函数套进去,看看交叉熵对logits (z) 的梯度:

[ \frac{\partial L}{\partial z} = p - y ]

这个形式极其简洁:梯度大小等于预测值和真实值的差,方向指向真实值。预测概率0.9、真实标签1,梯度就是0.1,更新幅度小,说明模型已经比较接近了;预测概率0.9、真实标签0,梯度就是0.9,更新幅度大,说明模型错得离谱需要大幅修正。这种"错得越多、改得越狠"的特性,让训练过程非常稳定。

再看MSE配sigmoid的梯度:

[ \frac{\partial L}{\partial z} = 2(p - y) \cdot p \cdot (1-p) ]

问题就出在 (p \cdot (1-p)) 这一项。当预测概率接近0或1时,这一项趋近于0,梯度被压缩得极小。也就是说,模型在明显犯错(比如真实标签1但预测概率0.01)和明显正确(预测概率0.99)时,梯度都很小,只有预测概率在0.5附近时梯度才比较大。这带来的直接后果是:训练初期模型参数随机初始化,预测概率通常在0.5附近,梯度还可以;但随着训练推进,预测开始偏向两极,梯度反而越来越小,模型很容易陷入"半桶水"状态,不收敛到最优解。

我实际测试过,用纯MSE训练一个两层全连接网络做MNIST二分类,迭代200轮准确率还在90%左右徘徊;换成交叉熵,同样结构、同样学习率,50轮就能到97%以上。这不是玄学,是梯度流形决定的差异。所以记住一个原则:分类任务优先考虑交叉熵,不要图省事用MSE。

2.2 多分类场景下的Softmax交叉熵与标签平滑

多分类任务用到的是Softmax交叉熵,Softmax把logits转成概率分布,然后和one-hot标签做交叉熵。公式不再展开,但我想重点说说训练过程中的两个实际痛点。

第一个痛点是:模型过于自信。Softmax交叉熵会把所有概率压到正确类别上,当训练集有噪声或类别本身有重叠时,模型会强行记住那些错误标注,导致过拟合严重、泛化能力下降。这时候标签平滑(Label Smoothing)就派上用场了。做法很简单,把one-hot标签中的1替换成 (1-\epsilon),其余类别均匀分配 (\epsilon/(K-1))((K) 是类别数)。实践中 (\epsilon) 取0.1效果最好。我自己在图像分类任务里试过,加标签平滑后测试集准确率通常能提升0.3到1个百分点,而且训练曲线更平滑。这背后的原理是:标签平滑相当于给模型一个"兜底"的置信度,避免它把所有概率孤注一掷,特征空间被拉得更宽松,泛化能力自然更好。

第二个痛点是:类别不均衡时交叉熵会被多数类带偏。假设你做一个缺陷检测任务,正常样本占99%,缺陷样本占1%。用普通交叉熵训练,模型只要全部预测为正常,Loss就已经很低了,但它对缺陷类别完全无感。最简单的解决办法是给损失函数加权重:少数类的损失项乘以一个系数,增大它对梯度的贡献。公式变成:

[ L = -\frac{1}{N} \sum_{i=1}^{N} [\alpha \cdot y_i \log(p_i) + (1-y_i) \log(1-p_i)] ]

(\alpha) 通常设为多数类样本数除以少数类样本数,或者按经验直接取3到10之间的值。但要注意,权重过大容易导致训练初期梯度震荡剧烈,建议配合学习率warmup一起使用。不过这种静态权重只是治标,更系统的方案是Focal Loss,我后面会专门展开。

2.3 从Softmax到ArcFace:度量学习中的损失函数进化

如果说交叉熵是分类任务的基石,那么基于间隔(Margin)的损失函数就是人脸识别、行人重识别等细粒度检索任务的关键进化。Softmax交叉熵虽然能把类别分开,但学到的特征在度量空间里不满足"类内紧凑、类间分离"的严格要求。换句话说,它学到的决策边界是线性的,对于"判断两张脸是不是同一个人"这种需要特征距离度量的任务不够用。

ArcFace的做法是在Softmax之前对特征和权重向量做归一化,然后在角度空间里加上一个间隔 (m)。改造后的损失函数迫使模型在超球面上把同类别的特征聚拢在一起,不同类别之间至少要隔一个固定的角度。这个设计非常精妙:它不改变网络结构,只改损失函数,就能让特征分布发生质变。实践中的经验是,(m) 值一般取0.5,特征维度设512,归一化后的特征缩放系数 (s) 设为64。我在一个人脸识别项目里对比过,普通Softmax在LFW(人脸验证基准)上的准确率约98.2%,换成ArcFace后直接到99.4%,提升非常可观。

这里想提醒一点:ArcFace类损失虽然效果好,但训练难度也更高。它对数据质量更敏感,错误标注的数据会造成严重的梯度污染,所以使用前务必做好数据清洗。另外,这类损失函数在类别数量特别大(比如百万级身份)时,矩阵计算会占用大量显存,需要配合分布式训练或者采样策略来缓解。

3. 回归任务中的MSE、MAE与Huber:一个关于鲁棒性的选择题

3.1 三个基础损失函数的梯度行为对比

回归任务最常用的损失函数有三个:MSE、MAE、Huber。它们的公式分别如下:

[ L_{MSE} = \frac{1}{N} \sum_{i=1}^{N} (y_i - \hat{y}_i)^2 ]

[ L_{MAE} = \frac{1}{N} \sum_{i=1}^{N} |y_i - \hat{y}_i| ]

[ L_{Huber} = \frac{1}{N} \sum_{i=1}^{N} \begin{cases} 0.5 (y_i - \hat{y}_i)^2, & \text{if } |y_i - \hat{y}_i| < \delta \ \delta (|y_i - \hat{y}_i| - 0.5\delta), & \text{otherwise} \end{cases} ]

MSE对误差的惩罚是平方级的,所以误差为2的样本贡献的损失是误差为1的样本的4倍,这让它天然偏向"讨好大误差样本"。反过来,MAE对误差是线性惩罚,误差2和误差1是2倍关系,对所有样本一视同仁。Huber则是两者的折中:误差小于 (\delta) 时用平方项,让训练后期收敛更平稳;误差大于 (\delta) 时用线性项,避免离群点主导梯度。

从梯度角度看,MSE的梯度是 (2(y - \hat{y})),随误差线性增大。这意味着一个误差为10的离群点,梯度是误差为1样本的10倍,整个batch的梯度方向会被它拽着走。MAE的梯度是常数(正负1),不管误差多大,梯度大小都一样,鲁棒性更强,但也意味着在误差接近0的区域它不会自动缩小步长,收敛到最优解附近时容易来回震荡。Huber的梯度在 (|\text{error}| < \delta) 时随误差线性变化,在 (|\text{error}| > \delta) 时固定为 (\delta),既有MSE的收敛精度又有MAE的鲁棒性。

3.2 实际项目里怎么选:从自动驾驶的边界框回归说起

我在做一个基于视觉的物体距离估计项目时,一开始用的是MSE。训练集里偶尔会出现标注噪声——某些目标的真实距离标注错了,误差可能达到3到5米。你猜怎么着?模型为了迁就这些错误标注,把正常样本的预测也带偏了,最终在测试集上的平均误差比不训练还差。这就是MSE的典型困境:离群点污染梯度。

后来我换成了Huber损失,(\delta) 设为1.0,问题立刻缓解。误差小于1米的样本正常精修,误差大于1米的大错误不再以平方级放大,模型对标注噪声的容忍度明显提高。这在自动驾驶、工业检测这类数据采集成本高、噪声不可避免的场景里非常关键。

对比一下三个损失函数最合适的场景:

损失函数优势劣势典型应用场景
MSE收敛精确、梯度稳定、处处可导对离群点极其敏感噪声可控的仿真数据、数值稳定的回归
MAE对离群点鲁棒收敛点附近震荡、0点不可导存在明显标注噪声的任务
Huber兼顾MSE和MAE需要调 (\delta)大多数真实世界回归任务

这里给出一个可参考的选择逻辑:如果你的数据经过严格清洗、离群点极少,MSE可以放心用;如果数据质量一般,且你不想花太多时间处理异常值,直接上Huber,(\delta) 从1.0开始调,然后根据验证集表现微调。(\delta) 越小模型越接近MAE,越大越接近MSE。我个人偏好先用Huber( (\delta) 取1.0)作为baseline,再根据训练集Loss曲线判断:如果Loss出现突然的大跳变,说明离群点多,把 (\delta) 调小;如果收敛精度不足,把 (\delta) 调大。

3.3 一个被低估的变体:Log-Cosh与分位数损失

除了这三个基础损失,还有两个在特定场景中表现优秀的变体值得提一嘴。

Log-Cosh损失定义为:

[ L = \frac{1}{N} \sum_{i=1}^{N} \log(\cosh(y_i - \hat{y}_i)) ]

它和Huber很接近,但好处是处处二阶可导,优化器(特别是涉及Hessian矩阵的二阶方法)用起来更顺滑。缺点是 (\cosh) 在极大误差下可能数值溢出,需要在实现中添加一个判断分支来处理大误差的情况。我用Log-Cosh做过一个人体关键点检测的回归头,训练稳定性和收敛速度都比Huber稍好。

分位数损失(Quantile Loss)则是另一个完全不同的思路,它专门用于预测条件分位数,公式为:

[ L = \frac{1}{N} \sum_{i=1}^{N} \rho_\tau (y_i - \hat{y}i), \quad \rho\tau(e) = \begin{cases} \tau |e|, & e \geq 0 \ (1-\tau)|e|, & e < 0 \end{cases} ]

其中 (\tau) 是目标分位数,比如0.5对应预测中位数。这在不确定性估计、需求预测、金融风险度量等场景非常有用。因为 (\tau) 可以取多个值(如0.1、0.5、0.9),你就能用同一个模型同时输出预测区间。这个思路在很多竞赛项目中是拿分的关键技巧,但在常规业务开发中很少被用到,算是一个值得收藏的进阶知识。

4. Focal Loss与样本不平衡:为什么"难样本"才是训练的关键

4.1 从交叉熵到Focal Loss的推导逻辑

前面提到,类别不均衡时可以用静态权重给少数类加分,但这个方案有一个深层次问题:它没有区分"容易样本"和"困难样本"。比如目标检测场景,一张图里有几千个候选框,绝大多数是容易分类的负样本(背景),这些样本即使单个损失很小,但因为数量巨大,它们加起来的梯度贡献会淹没那些数量稀少但难以分类的正样本(前景目标)。静态权重给正样本加权,虽然能减少正负样本数量差异的影响,但那些"已经被分类正确的困难负样本"依然会贡献无意义的梯度。

2017年提出的Focal Loss就是专门针对这个问题的。它的核心思想:在交叉熵基础上加一个调制因子,让容易样本的损失被压低,难样本的损失被保留。公式如下:

[ L_{focal} = -\alpha_t (1 - p_t)^\gamma \log(p_t) ]

其中 (p_t) 是模型对真实类别 (t) 的预测概率,(\alpha_t) 是类别权重,(\gamma) 是聚焦参数。当 (p_t) 接近1时(容易样本),((1-p_t)^\gamma) 接近0,损失被大幅压低;当 (p_t) 接近0时(困难样本),调制因子接近1,损失几乎不受影响。

这个设计的精妙之处在于:它不依赖任何显式的"样本难度"标注,而是用模型自己的预测概率来自动判断难度。训练初期所有样本的预测概率都不高,调制因子作用不大,模型正常学习;训练后期容易样本的预测概率高,损失自动衰减,模型把注意力集中在那些"怎么都学不会"的困难样本上。

4.2 实践中Focal Loss的调参套路

Focal Loss有两个超参数:(\alpha) 和 (\gamma)。我的调参经验是:

  • (\gamma) 控制调制强度。(\gamma=0) 时Focal Loss退化为带权重的交叉熵,等于没有聚焦;(\gamma=1) 时调制力度适中;(\gamma=2) 是最常用的默认值;(\gamma=3) 以上对困难样本的聚焦过强,容易被错误标注的样本带偏,除非数据质量极高否则不建议。
  • (\alpha) 是类别权重,和普通交叉熵的类别权重作用相同,主要用来平衡正负样本的数量差异。如果数据集中正负样本比例为1:100,(\alpha) 可以设为0.75或0.9。但注意,(\alpha) 和 (\gamma) 之间有耦合:(\gamma) 越大,模型对少数类的聚焦越强,(\alpha) 可以适当调小;反之亦然。

我实际用Focal Loss做目标检测的边框分类头时,效果显著:负样本占总样本比例超过95%,普通交叉熵训练出的模型对正样本的召回率只有60%左右,换成Focal Loss( (\gamma=2),(\alpha=0.75))后召回率提升到85%以上,同时误报率没有明显恶化。这个提升主要来自Focal Loss对困难正样本的关注——有些小目标、遮挡目标、模糊目标,在普通交叉熵下它们的损失被海量容易样本稀释,学到一定阶段就停滞了;Focal Loss强制模型持续关注它们,最终把这些硬骨头啃下来。

实际项目中要注意Focal Loss的一个副作用:它会让训练Loss的绝对数值变得很小(因为容易样本的损失被压制了),导致Loss曲线看起来"下降很快",容易让人误以为模型已经收敛。这时候一定要同时监控验证集指标(如AP、召回率),而不要只盯着Loss看。

Focal Loss的思路已经超出了分类损失的范畴,它的"调制因子"方法论还被推广到了其他场景,比如检测任务中的IoU损失变体、分割任务中的边界感知损失等。理解它的核心机制,比背住一个公式更有价值。

5. 对比学习与InfoNCE:当损失函数开始构造"学习信号"

5.1 自监督学习为什么需要新的损失函数

近几年的自监督学习大放异彩,SimCLR、MoCo、BYOL这些方法都建立在同一个底层损失函数之上:InfoNCE。它解决的问题可以概括为:在没有人工标注的情况下,如何定义"什么样的表示是好的"?

思路是构造正负样本对。从同一张图的两个不同视角(比如随机裁剪、颜色扰动)提取出的两个特征,视为一对正样本;从不同图片提取出的特征,视为负样本。模型要做的就是拉近正样本之间的距离,推开负样本之间的距离。这本质上是一个多分类问题:给定一个查询特征,在K个候选特征中找出那个正确匹配的正样本。

InfoNCE的公式如下:

[ L = -\log \frac{\exp(q \cdot k_+ / \tau)}{\sum_{i=1}^{K} \exp(q \cdot k_i / \tau)} ]

其中 (q) 是查询特征,(k_+) 是正样本(匹配项),(k_i) 是包括正样本在内的所有候选特征,(\tau) 是温度系数。这个公式看起来和交叉熵几乎一样,但内涵完全不同:交叉熵的类别是预先定义的语义类别,而InfoNCE的"类别"是样本对本身,是动态生成的。这就让模型从"学一个固定分类器"变成了"学一个度量空间"。

5.2 温度系数的物理意义与调参经验

InfoNCE里最关键的参数是温度系数 (\tau)。它的作用和控制梯度的"软硬程度":(\tau) 越大,所有候选样本的相似度都被"压平",分布更均匀,梯度更温和;(\tau) 越小,相似的样本对和不同的样本对在损失中的差异被放大,梯度更"锐利",模型会更激进地拉开正负样本。

从物理角度看,温度系数 (tau) 控制了特征空间的聚散程度。当 (tau) 很小时(比如0.05),损失函数对"负样本中有和正样本相似的个体"非常敏感,模型会把很大力气花在区分这些难以区分的负样本上,特征空间会被拉得很开。当 (tau) 取大值(比如1.0),模型则趋于温和,特征空间相对松散。

实际训练中,(\tau) 的取值直接决定效果,我踩过一次大坑:一开始用默认的0.1,训练了100个epoch后线性评估准确率只有60%;后来把 (\tau) 降到0.05,同样训练到100个epoch,准确率涨到72%。这个差别非常大,所以建议在做对比学习实验时先把 (\tau) 作为一个核心超参数来重点调,而不是随便设一个值。

温度系数的调参方向可以参考:数据增强很强、任务难度高时,用小 (\tau)(0.03~0.1)让模型更锐利;batch size特别大(负样本多)时,可以适当增大 (\tau)(0.1~0.3),避免梯度过于激进。另外,(\tau) 也不是越小越好,太小会导致训练很不稳定,Loss波动巨大,特征空间被过度压扁,反而损失泛化能力。

5.3 从InfoNCE到度量学习的统一视角

把InfoNCE、Focal Loss、ArcFace放在一起看,会发现它们的本质都是"控制特征空间中的距离关系"。ArcFace在超球面上加固定角度间隔,Focal Loss根据预测概率动态调节梯度权重,InfoNCE用温度系数控制相似度的分布锐度。它们的共性在于:深度模型的特征表示,归根结底是在学一个距离度量,而损失函数定义了"距离多远才合适"。

理解这个统一视角很重要。如果你遇到一个新任务,找不到现成的损失函数可用,可以尝试从这个角度去设计:定义正样本对和负样本对,定义合适的距离度量,然后选定一个控制"距离松紧"的超参数,一个问题就变成了一套可训练的度量学习方案。我做过一个商品检索项目,直接沿用InfoNCE的框架,把分类头的交叉熵换成了对比学习式的损失函数,在没有额外标注的情况下,检索准确率提升了约8个百分点。

6. 损失函数的工程细节:从数值稳定性到可视化诊断

6.1 数值稳定性:log-sum-exp技巧与混合精度下的陷阱

损失函数的数学公式看起来干干净净,落地到代码里却到处是坑。最典型的就是Softmax交叉熵的logits过大导致的数值溢出,以及Inf/NaN问题。实现时建议始终使用框架提供的融合算子,比如PyTorch的CrossEntropyLoss,底层会做log-sum-exp的数值稳定处理,比自己用裸的softmax + log + nll_loss更安全。

混合精度训练(AMP)下损失函数更容易出问题。我自己遇到过:开了AMP之后,Loss曲线前几百步完全正常,某个step突然变成NaN,然后整个训练崩溃。排查了很久,发现是某一层输出出现了极大值,在FP16下溢出成了Inf,梯度反向传播后权重被污染。解决办法有两个方向:一是检查前向计算是否有不稳定的中间步骤(比如某些激活函数在大数值下溢出),二是在损失函数里加一个输出裁剪或梯度裁剪(grad clip)。多数情况下,torch.nn.utils.clip_grad_norm_设置为1.0到5.0就能解决绝大多数崩溃问题。

另外要牢记:不同损失函数的前向数值范围差异很大。MSE的Loss值通常在1附近,交叉熵的Loss值通常在0到5之间,Focal Loss的Loss值可能只有0.01到0.1。如果你在中途切换损失函数,学习率也必须跟着调整。我在实践中总结的经验是:Loss数量级每变化一个量级,学习率尝试同比例缩放。

6.2 损失函数的可视化诊断:不只是看曲线下降

不少人的训练监控只做一件事:把Loss曲线打在屏幕上看它下降。这样其实远远不够。真正的诊断至少要关注三个维度:

第一个是训练Loss和验证Loss的差距。两者同时下降、差距小,说明模型正常;训练Loss降、验证Loss不变或上升,说明过拟合,此时不是改损失函数,而是加正则化或数据增强;两者都不降,才考虑是不是损失函数选错了。

第二个是Loss曲线的"形状"。正常的训练曲线应该是前几百步快速下降,然后逐渐趋于平缓,整个过程噪声适中。如果曲线呈阶梯状下降,说明学习率太大或者batch内样本分布极端;如果曲线像锯齿一样剧烈震荡,说明梯度不稳定,可能需要更小的学习率或者更大的batch;如果曲线完全平直,说明模型根本没有学到东西,此时第一个要检查的就是损失函数的梯度是否为0。

第三个是分模块的梯度统计。我习惯于在训练时额外统计每个层的梯度L2范数,看它们在训练过程中是否分布合理。如果某些层梯度一直为0,可能是网络结构的问题;如果某一层梯度比其他层大几个数量级,可能导致梯度爆炸,损失函数的选择也会影响梯度分布的均衡性——比如某些损失函数对浅层的梯度贡献远大于深层,导致底层特征学不好。

6.3 损失函数的中断切换与多任务加权

在实际项目中,很少有一成不变的损失函数组合。最常见的是一个多任务场景,比如同时做目标检测(需要分类损失 + 回归损失),或者图文检索(需要对比损失 + 分类损失)。多任务损失函数的加权是一个经常被忽视的细节:简单地把两个损失相加,往往会导致数值大的一方主导训练。

我处理多任务损失的策略是:先用一个小实验统计各部分Loss的数量级,然后给它们设置不同的初始权重,目标是在训练初始step时各部分Loss的数值接近。这样做的原因很简单——如果分类Loss是5,回归Loss是0.1,那么即使回归任务对最终效果更重要,它的梯度贡献也会被淹没。可以用GradNorm这类方法自动学习权重,但大多数项目里手动设置就足够了。

另一个实用的技巧是:训练过程中分阶段切换损失函数。我在一个图像生成项目里,先只用感知损失跑了100个epoch,让模型学到图像的整体结构;然后加入对抗损失,让细节更逼真。这种阶段性切换比从一开始就混合所有损失更稳定,因为不同的损失函数在训练的不同阶段发挥的作用是不同的。

我还想分享一个生产环境下的小建议:训练时可以把每个分项的独立Loss都记录到日志里(包括每个任务单独的部分),不要只记合并后的总Loss。否则出了问题你根本不知道是哪个子任务在劣化。实践中我碰到过多次:总Loss看起来一直在降,但单独拆分后发现其中一个子任务的损失其实在涨,只是被另一个子任务的下降掩盖了。等到训练结束评估时才发现这个问题,重新训练的成本就高了。

7. 最后一环:损失函数选择的综合决策清单与个人经验

把全文内容压缩成一套可操作的决策清单,方便你下次接到训练任务时快速做选择:

  • 分类任务优先用交叉熵;类别不均衡先试加权交叉熵,效果不显著再上Focal Loss。
  • 回归任务先问自己数据噪声大不大:不大用MSE,大就上Huber,(\delta) 从1.0开始调。
  • 检索/度量学习任务直接考虑ArcFace或InfoNCE,前者适合闭集分类,后者适合开集检索。
  • 多任务场景务必拆分记录各子任务的Loss,并给各子任务设置合理权重。
  • 训练不收敛时,按顺序排查:数据是否有错 -> 学习率是否过大/过小 -> 损失函数数值是否稳定 -> 梯度是否异常,别一上来就改损失函数。
  • 换了损失函数后,学习率和batch size都要重新调,两者和损失函数梯度分布有耦合关系。

关于损失函数,我在实际项目中有几个很深的体会想多说两句。

第一个体会是:损失函数不是越复杂越好。很多团队一上来就用Focal Loss加ArcFace加各种正则项,模型反而更难训练,效果还不如简单的交叉熵。新手的思路往往是"把最先进的损函数都叠上去",而有经验的人会先跑通一个简单的baseline,然后按单个变量逐步替换损失函数,每次改变都能明确观察到效果变化。这种消融式的调参习惯,长期来看效率反而最高。

第二个体会是:损失函数一定要和评估指标对齐。我见过一个做推荐排序的团队,训练用MSE,评估用AUC,两个目标天然不一致,结果无论怎么调参AUC都上不去。后来把损失函数换成BPR Loss或者LambdaLoss这类排序损失,AUC立刻涨了3个百分点。这件事给我留下的印象很深:设计损失函数时,永远先问一句"我最终关心的指标是什么",然后再倒推损失函数的形式。

第三个体会是:多花点时间看损失函数在tensorboard上的分布图,而不是只看数值。Loss分布的形状变化能告诉你很多信息:模型是否过度自信、特征是否聚集、样本难度的分布是什么样的。这些往往比单纯观察Loss的下降曲线更有洞察力。

最后再分享一个实战技巧:当你的训练过程中经常出现Loss突然飙升又恢复的情况,不要急着调学习率,先检查是不是数据加载顺序的问题。有一次我在训练时发现每1000个step Loss就会有大波动,排查了半天,最后发现是数据加载器里有一个特殊的增强操作在部分样本上产生了异常值,导致那一小批样本的损失特别大。这类问题在损失函数层面是看不见的,但会让训练有规律地震荡。数据管线的问题先于损失函数问题,这是排查的优先顺序,千万别本末倒置。

损失函数的世界远不止这篇文章提到的这些,还有针对分割的Dice Loss、针对检测的IoU系列损失、针对生成模型的对抗损失和感知损失、针对排序的LambdaRank损失等等。但掌握了底层原理和调参方法论,面对任何新的损失函数,你都会有清晰的思路去理解它、应用它和调试它。这也正是从"知道公式"到"真正会用"之间最关键的一步。

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

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

立即咨询