YOLOv5模型的损失函数计算总结
- 11 Feb, 2026
本文以YOLOv5模型的v6.0/v6.1版本为基础,详细总结和解释了损失函数各个部分的计算流程。
YOLOv5模型的损失函数由三个部分组成:
- 目标框定位损失,Box Loss
- 目标置信度损失,Obj Loss
- 分类损失,Cls Loss
其中,边界框回归损失采用了CIoU(Complete IoU)损失,而目标置信度和分类损失均使用二元交叉熵(BCE)损失。
目标置信度损失Obj Loss
YOLOv5的目标置信度损失Obj Loss是唯一一个正样本和负样本(背景)都要参与计算的损失项。它的核心任务是教模型回答一个问题:“这个网格里到底有没有物体?如果有,这个预测框的可信度有多高?”
此外,在进行损失计算的过程中,build_targets所返回的正样本列表中,所有正样本的置信度标签值并非固定是1,而是作为正样本的这个预测框与真值框的IOU。也就是说,正样本与真值框之间的重合度越高,这个正样本的置信度标签值也就越高。这就是YOLOv5损失计算所采用的软标签(Soft Label)策略:
- 所有的负样本 Target ($t_{obj}$) = 0
- 所有的正样本 Target ($t_{obj}$) = CIoU Score
整个目标置信度损失 L_{obj} 的计算可以分为四个步骤。
1.预测值 (p_{obj})的预处理
YOLOv5模型的前向推理流程在三个特征层(P3, P4, P5)输出预测张量。对于置信度通道,其推理输出的是未经激活的数值。因为计算置信度损失值使用二元交叉熵BCE算法,因此要首先对模型输出的 Logits 值进行 Sigmoid 激活,将数值映射到 (0, 1) 区间。
$$ p_{obj} = \sigma(\text{logits}) $$
2.构建目标值 (t_{obj})
如YOLOv5模型损失函数的背景知识总结一文所总结的,YOLOv5模型损失函数计算类ComputeLoss中的build_targes负责基于训练样本的真值框列表以及各个检测层的Anchor列表构建并返回一个正样本列表。
此处计算目标置信度损失需要构建目标值 $t_{obj}$:
- 首先初始化一个与预测特征图形状完全一样的全零张量。
- 然后遍历以上build_targets返回的所有正样本:
- 计算当前作为正样本的预测框(Pred Box)与真值框(GT Box)的CIoU值。
- 然后将该 CIoU 值填入全零张量中对应的坐标位置 (b, a, gj, gi)。
- 最终得到的 $t_{obj}$ 的结果就是一个大部分位置是 0(背景),少数位置是 $0 \sim 1 $ 浮点数(前景 IoU)的 Target 张量。
3.计算二值交叉熵 (BCE Loss)
上面有了预测值 $p_{obj} $ 和 目标值 $ t_{obj}$ ,就可以计算其二元交叉熵损失了。YOLOv5 使用 PyTorch 的BCEWithLogitsLoss。对于针对单个预测框而言,其计算公式是:
$$ L_{obj_grid} = - [ t_{obj} \cdot \log(p_{obj}) + (1 - t_{obj}) \cdot \log(1 - p_{obj}) ] $$
- 对于负样本 ($t_{obj}=0$):前半部分消失,只优化后半部分 $\log(1-p_{obj})$,迫使 $ p_{obj} $ 趋近于 0。
- 对于正样本 ($t_{obj}=\text{CIoU}$):前后两部分都存在,迫使 $p_{obj}$ 趋近于 CIoU 值。
此外,如YOLOv5模型损失函数的背景知识总结所描述的,如果通过超参数开启了Focal Loss功能,还需要对其进行Focal Loss处理。目的是压制负样本背景框的损失,提升正样本的损失权重。
以上公式计算的是一个预测框的置信度损失值,而一个检测层的置信度损失,则是该层输出的所有预测框计算置信度损失的总和:
$$ L_{obj}^L = \sum_{b=1}^{B} \sum_{i=1}^{G} \sum_{j=1}^{G} \sum_{a=1}^{A} L_{obj_grid}(b, i, j, a) $$
其中 B 是 Batch Size,G 是网格尺寸,A=3 是每个网格设置的 Anchor 数量,默认为3。
4.层级加权平衡 (Layer Balancing)
因为小目标的特征信息少,背景干扰多,回归难度大,模型需要更强的梯度信号来学习如何检测它们。所以在对三个检测层的置信度损失求和得到总的置信度损失时,还需要对各个检测层的损失值加权求和:对输出小目标特征信息的 P3 层乘以更高的权重,对输出大目标特征信息的 P5 层乘以较小的权重,以强迫模型更加重视高分辨率特征图(P3)上的预测结果,从而提升小目标的召回率和准确性。
$$ L_{obj}^{total} = 4.0 \cdot L_{obj}^{P3} + 1.0 \cdot L_{obj}^{P4} + 0.4 \cdot L_{obj}^{P5} $$
再次强调一下,只有置信度损失的计算流程中,会被负样本考虑在内,以下的类别损失以及定位框损失均不考虑负样本。
类别损失Cls Loss
类别损失的目标非常清晰:对于被确定为正样本的预测框,它必须正确识别出该物体属于哪个类别。 类别损失 $L_{cls}$ 的计算流程具有以下两个关键特征:
- 只计算正样本: 和定位框损失 $L_{box}$ 一样,只有那些被分配了真实框的正样本(也就是build_targets所返回的正样本列表)才参与类别损失的计算。模型推理输出的两万多个负样本检测框(即背景框)的类别损失为零,不参与梯度回传。
- 多类别支持: 其目标是从所有可能的 C 个类别中,能够正确识别出目标的具体类别。
在YOLOv5中,类别损失同样采用标准的二值交叉熵损失BCE,但在工程实现上有一些巧妙的处理,使其能应用于多类别分类。其详细计算流程包含以下四个步骤。
预测值 ($p_{cls}$)的预处理
与置信度损失的计算流程相同,首先是要定位正样本。基于模型前向推理的输出张量以及模型在各个预测层所预设的Anchor框列表,调用build_targets函数提取出所有正样本的列表。后续类别损失值的计算只在这些正样本上进行计算。
因为要进行BCE计算,从build_targets返回的正样本列表中得到其中所包含的类别预测 Logits,然后对这些 Logits 进行 Sigmoid 激活。模型针对每个预测框,都会输出一个 C 维度的向量,其中 C 是总类别数(例如 COCO 数据集 C=80)。对每个类别输出的预测值都通过 Sigmoid 激活,将每个类别的分数独立地映射到 [0, 1] 区间,从而得到每个类别的预测概率_ $p_{cls}$。
构建目标值 ($t_{cls}$)
构造一个与正样本 $p_{cls}$ 维度相同的目标张量 $ t_{cls}$。其维度为$ [\text{Num_Pos_Samples}, C]$。对其中的标签赋值:
- 对于其中的每个正样本,找到它对应真值框所标注的真实类别 k,在 $t_{cls}$ 向量的第 k 个位置上赋值 1,其余 C-1 个位置全部赋值0。
最终的结果就是,我们得到了一组稀疏的 one-hot 编码来作为下一步进行BCE计算的目标值。
在YOLOv5的损失计算流程中,为了防止模型对标签过拟合,其在训练中还会使用一种标签平滑(Label Smoothing)的技术。 大致就是将真实类别所设置的 t=1 的目标值稍微降低,将 t=0 的目标值稍微提高。
- 例如,对于某个正样本的类别标签设置而言,不是设置 $ t={1, 0, 0, \dots}$,而是 $t={0.95, 0.005, 0.005, \dots}$。
其目的是鼓励模型预测的概率不要过于绝对(如 1.0),从而提升模型的泛化能力和鲁棒性。
计算二值交叉熵 (BCE Loss)
$L_{cls}$ 的计算依赖于 BCE,但BCE的计算是针对每个类别独立计算的,然后对所有类别的损失求和。
假设 i 是正样本的索引,k 是类别的索引,$p_{i,k}$ 是模型预测的第 i 个样本属于类别 k 的概率,$t_{i,k}$ 是真实标签(0或1)。那么针对单个样本的单个类别 k 的损失公式就是:
$$ L_{cls}(i, k) = - [ t_{i,k} \cdot \log(p_{i,k}) + (1 - t_{i,k}) \cdot \log(1 - p_{i,k}) ] $$
由于 t_{i,k} 只有在真实类别 $k_{gt}$ 处为 1,在其他 C-1 个类别处为 0,这个计算可简化为:
- 对于真实类别 $k_{gt}$:损失为 $-\log(p_{i, k_{gt}})$,迫使模型提高对正确类别的预测概率。
- 对于错误类别 $k_{wrong}$:损失为 $-\log(1 - p_{i, k_{wrong}})$,迫使模型降低对所有错误类别的预测概率。
类别总损失的聚合
最后,将所有正样本在所有类别上的损失进行聚合(将每个正样本在 C 个类别上的损失加起来),就得到最终的 $L_{cls}$。
$$ L_{cls}^{total} = \sum_{i=1}^{\text{Num_Pos_Samples}} \sum_{k=1}^{C} L_{cls}(i, k) $$
目标框定位损失Box Loss
在YOLOv5中,定位损失采用的是 CIoU Loss(Complete IoU Loss,完整交并比损失)。它的核心目标是:对于被确定为正样本的预测框,准确地调整其位置、大小和长宽比,使其尽可能地与真实框(GT)重合。
相比于普通的IOU指标,CIoU Loss 不仅仅关注预测框与真值框的重叠面积,还引入了中心点距离和长宽比一致性这两个惩罚项,从而提供了更全面、更稳定的梯度信号,极大地提升了模型的定位精度。CIoU Loss 的完整定义是:
$$ L_{CIoU} = 1 - IoU + R_{CIoU} $$
其中,$R_{CIoU}$ 是 CIoU 的惩罚项,它由中心点距离项和长宽比一致性项构成。
$L_{box}$ 的计算流程如下所述。
筛选正样本并解码
这一点与以上计算类别损失相同。首先是定位正样本,即仅从 build_targets 函数生成的正样本列表中,取出对应的预测框(Logits),然后将模型输出的偏移量解码成真实的归一化坐标 (x, y, w, h)。
与类别损失相同,定位损失的计算同样只考虑build_targets所返回的正样本列表,不考虑其他的背景负样本。
计算 IoU 和 CIoU
基于每个正样本预测框,计算这个预测框与真值框之间的 IoU ,以及针对CIoU计算流程的距离和长宽比惩罚项。最终将所有项代入 CIoU Loss 的计算公式,计算每个正样本的 CIoU 损失 $L_{CIoU}$ 。
目标定位框的损失值聚合
对所有正样本的 $L_{CIoU}$ 值进行求和(通常会进行平均)得到总的定位框损失 $L_{box}$ 。
总损失
经过以上三个部分的独立计算,就可以得到一个批次(batch size)的目标定位框总损失 $L_{box}$,目标置信度总损失 $L_{obj}$ 以及分类总损失 $L_{cls}$。整体的损失则是这三个损失的加权和:
$$ L_{total} = \lambda_{box}.L_{box} + \lambda_{obj}.L_{obj} + \lambda_{cls}.L_{cls} $$
其中的 $\lambda_{box}$ , $\lambda_{obj}$ 和 $\lambda_{cls}$ 分别对应于三个损失的加权权重,在超参数文件中进行设置,分别对应于超参数文件中的box,obj和cls设置项:
lbox *= self.hyp["box"]
lobj *= self.hyp["obj"]
lcls *= self.hyp["cls"]
bs = tobj.shape[0] # batch size
return (lbox + lobj + lcls) * bs, torch.cat((lbox, lobj, lcls)).detach()
至此,针对训练过程中一个批次输出图片推理输出的完整损失值就计算出来了。