
Ultralytics RT-DETR / DETR 损失函数全解析models/utils/loss.py源码级指南【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics导读本文深入讲解 Ultralytics 仓库中 DETR 系检测模型的损失计算实现核心是DETRLoss与RTDETRDetectionLoss两个类API 参考文档所指向的模块。读完你将掌握匈牙利匹配器Hungarian Matcher如何为 transformer 解码器输出做最优二分匹配、分类/回归/GIoU 与辅助层损失如何组合与加权、RT-DETR 的对比去噪训练损失denoising loss如何参与反向传播以及各损失增益如何通过模型配置在训练中生效。文章结合当前仓库中ultralytics/models/utils/loss.py、ops.py、nn/tasks.py等源码与调用链逐层展开可作为检测器训练调参与二次开发时的直接参考。一、模块定位为“无 NMS 的端到端检测”而生的损失模块与传统 YOLO 检测头基于 anchor 分配 TaskAlignedAssigner不同DETR / RT-DETR 使用一组可学习的object queries直接预测目标天然是端到端、免 NMS 的范式。其损失函数的关键在于两点先做集合匹配用匈牙利算法把N个 query 预测最优地分配给图上的M个真实目标一对一而非预先确定正负样本再对匹配上的预测算损失分类损失 边框 L1 回归损失 GIoU 损失并对每个中间 decoder 层叠加辅助损失以缓解训练不稳定。本模块即上述范式的损失封装源码位于 ultralytics/models/utils/loss.py与 匈牙利匹配器 ops.py、通用 FocalLoss/VarifocalLoss 共同构成 DETR 系模型的训练损失体系。模块包含两个公开类DETRLoss(nn.Module)基础 DETR 损失计算分类、边框、GIoU 及可选的辅助损失RTDETRDetectionLoss(DETRLoss)继承并扩展额外计算对比去噪训练损失denoising loss。模块顶部依赖关系见 loss.py 第 1-14 行从ultralytics.utils.loss引入FocalLoss、VarifocalLoss从ultralytics.utils.metrics引入bbox_iou从同目录.ops引入HungarianMatcher。下面逐层展开。二、DETRLoss三类基础损失 辅助层损失2.1 构造参数与默认损失增益DETRLoss.__init__的参数loss.py 第 37-78 行决定了损失的全部行为参数与默认值如下参数默认值含义nc80类别数用于构建 one-hot 标签与分类 logits 对齐loss_gain{class: 1, bbox: 5, giou: 2, no_object: 0.1, mask: 1, dice: 1}各损失分量系数mask/dice为未来分割分支预留aux_lossTrue是否为每个中间 decoder 层计算辅助损失use_flTrue是否使用 Focal Loss难易样本调制use_vflFalse是否使用 Varifocal Loss按目标 IoU 赋权use_uni_matchFalse是否用固定层进行辅助分支的标签分配uni_match_ind0use_uni_matchTrue时使用的固定层索引gamma1.5Focal/Varifocal 的聚焦参数控制对难分类样本的关注alpha0.25类别不平衡平衡因子构造时还默认实例化匈牙利匹配器self.matcher HungarianMatcher(cost_gain{class: 2, bbox: 5, giou: 2})即匹配阶段分类代价系数为 2、L1 代价为 5、GIoU 代价为 2并依据开关创建self.flFocalLoss(gamma, alpha)与self.vflVarifocalLoss(gamma, alpha)。需要注意loss_gain与matcher的cost_gain是两套独立的系数前者放大最终的梯度信号后者只用于构造匹配代价矩阵两者职责不同。2.2 匹配索引从何而来HungarianMatcherDETRLoss内部会调用 ops.py 中的HungarianMatcher。它在前向中完成一次最优二分匹配若sum(gt_groups) 0整批无目标直接返回全空索引避免无效计算将pred_scores展开后按use_fl选择sigmoid配合 Focal或softmax归一化分类代价cost_classFocal 风格的正负代价差pos_cost_class - neg_cost_classalpha0.25, gamma2.0否则取-pred_scoresL1 边框代价cost_bbox预测框与 GT 框逐维绝对差求和GIoU 代价cost_giou 1 - IoU(GIoU)综合C class·cost_class bbox·cost_bbox giou·cost_giouNaN/Inf 置 0按gt_groups切分后逐图调用linear_sum_assignment源自ultralytics.utils.ops得到每个 batch 样本的(预测索引 i, GT 索引 j)对。其返回值是长度为 batch 大小的(index_i, index_j)元组列表满足len(index_i) len(index_j) min(num_queries, num_target_boxes)。DETRLoss._get_indexloss.py 第 258-272 行随后把该列表整理成可向量化索引batch_idx每个匹配属于哪张图、src_idx预测端索引与dst_idxGT 端索引。_get_assigned_bboxes第 274-300 行则依据匹配索引把预测框与 GT 框成对抽取出来供回归/GIoU 损失使用。2.3 分类损失Focal / Varifocal / BCE 三选一_get_loss_classloss.py 第 80-119 行负责分类损失。输入约定pred_scores形状(B, N, C)targets形状(B, N)为类别索引。实现细节构造(bs, nq, nc1)的 one-hot 张量并去掉最后一列多出的第nc类作为“无目标”槽位见_get_loss中targets初始填充用gt_scores真实置信度见 2.4对 one-hot 加权得到软标签依据开关选择有 GT 且开启vfl时走VarifocalLossuse_fl时走FocalLoss否则退化为BCEWithLogitsLossYOLO 风格分类损失归一化项为max(num_gts, 1) / nq最后乘上loss_gain[class]。FocalLoss与VarifocalLoss的具体实现在 ultralytics/utils/loss.py 第 22-86 行前者用调制因子(1-p_t)^gamma与alpha因子压降易分负样本后者权重为alpha·sigmoid(pred)^gamma·(1-label) gt_score·label把“质量估计”融入分类监督。2.4 回归损失L1 GIoU以及 IoU 感知的目标置信度_get_loss_bboxloss.py 第 121-154 行输出两个分量loss_bbox{postfix}loss_gain[bbox] · F.l1_loss(pred_bboxes, gt_bboxes, reductionsum) / len(gt_bboxes)loss_giou{postfix}loss_gain[giou] · (1 - bbox_iou(..., xywhTrue, GIoUTrue))的均值。值得留意的是空 GT 保护当len(gt_bboxes) 0时返回pred_bboxes[..., :0].sum()的零梯度张量——源码注释明确指出该写法用于规避 PyTorch 多卡 DDP 的unused gradient报错删除不得。而_get_loss第 302-350 行是单层损失的主编排函数先若未传入调用 matcher 得到索引用_get_index抽取匹配上的预测与 GT随后把targets初始化为全nc“无目标”类别再把匹配到的 GT 类别填回去gt_scores采用预测框detach 后与 GT 框的 IoU使分类目标携带框质量信息这正是 Varifocal 训练范式的基础。2.5 辅助损失逐 decoder 层监督与固定层统一匹配_get_loss_auxloss.py 第 187-256 行对每个中间 decoder 层的(aux_bboxes, aux_scores)重复调用_get_loss并累加loss_class、loss_bbox、loss_giou返回带_aux后缀的字典。两个关键行为当use_uni_matchTrue且未预传match_indices时只用uni_match_ind指定的那一层去跑匈牙利匹配其余辅助层复用同一份索引减少匹配开销若直接传入match_indices则所有辅助层共用该索引RT-DETR 主层匹配结果即这样复用。2.6forward最后一层为主损失其余为辅助损失forwardloss.py 第 352-391 行接收的pred_bboxes/pred_scores形状为(L, B, N, 4)与(L, B, N, C)其中L代表层数含编码器层输出。它取出最后一层pred_bboxes[-1], pred_scores[-1]计算主损失当aux_lossTrue时对前L-1层调用_get_loss_aux累加辅助损失合并返回字典键形如loss_class、loss_bbox、loss_giou、loss_class_aux、loss_bbox_aux、loss_giou_aux支持postfix后缀。batch 数据约定为{cls, bboxes, gt_groups}其中gt_groups记录每张图的 GT 数量供 matcher 切分与损失归一化。三、RTDETRDetectionLoss加入对比去噪训练损失RTDETRDetectionLossloss.py 第 394-462 行继承DETRLoss专为 RT-DETR 设计。其增强点在forwardpred_bboxes, pred_scores preds total_loss super().forward(pred_bboxes, pred_scores, batch) # 标准检测损失 if dn_meta is not None: dn_pos_idx, dn_num_group dn_meta[dn_pos_idx], dn_meta[dn_num_group] match_indices self.get_dn_match_indices(dn_pos_idx, dn_num_group, dn_meta[dn_gt_idx]) dn_loss super().forward(dn_bboxes, dn_scores, batch, postfix_dn, match_indicesmatch_indices) total_loss.update(dn_loss) else: total_loss.update({f{k}_dn: torch.tensor(0.0, deviceself.device) for k in total_loss})要点去噪查询不经过匈牙利匹配因为去噪查询在生成时就知道它要重建哪个 GTget_dn_match_indices静态方法直接把dn_gt_idx复制dn_num_group份与dn_pos_idx一一配对成(src, dst)索引同时校验两者长度一致否则抛错。损失命名带_dn后缀postfix_dn使返回键为loss_class_dn、loss_bbox_dn、loss_giou_dn与主/辅助损失区分。无去噪元数据时补零仍输出*_dn键并置零保证trainer侧loss_names稳定。3.1 去噪查询如何产生get_cdn_group去噪查询的生成在 ops.py 的get_cdn_group它为 GT 框与标签注入噪声构造“重建任务”。其要点每个 GT 复制成2 · num_group份前一半为正样本扰动框/标签后一半为负样本偏移更大见rand_part[neg_idx] 1.0类噪声按cls_noise_ratio·0.5概率随机换标签框噪声以box_noise_scale缩放扰动后经xyxy2xywh并torch.logit逆 sigmoid编码返回padding_cls、padding_bbox、attn_mask保证“匹配查询不可见重建查询、重建查询之间互不可见”见attn_mask构造与dn_meta含dn_pos_idx、dn_gt_idx、dn_num_group、dn_num_splittrainingFalse或num_dn 0或 batch 为 None 时返回(None, None, None, None)。调用方是 RT-DETR 检测头 ultralytics/nn/modules/head.py 第 1583-1598 行dn_embed, dn_bbox, attn_mask, dn_meta get_cdn_group( batch, self.nc, self.num_queries, self.denoising_class_embed.weight, self.num_denoising, self.label_noise_ratio, self.box_noise_scale, self.training, )self.num_denoising、self.label_noise_ratio、self.box_noise_scale即来自 RT-DETR 模型配置见下节训练时由 head 前向注入噪声查询再把dn_meta一路传到损失函数。此外为避免 batch 无 GT 时 DDP 认为denoising_class_embed未使用head.py 第 1613-1615 行 还有一处“触碰权重”的防御写法。四、端到端调用链从模型配置到梯度回传4.1 损失函数被谁实例化RTDETRDetectionLoss并非手动实例化而是由模型自身的init_criterion惰性创建。ultralytics/nn/tasks.py 第 989-993 行def init_criterion(self): from ultralytics.models.utils.loss import RTDETRDetectionLoss return RTDETRDetectionLoss(ncself.nc, use_vflTrue)可见 RT-DETR 默认开启 Varifocaluse_vflTrue。完整调用链为RTDETRDetectionModel.loss()tasks.py 第 995-1041 行预处理 GT 为{cls, bboxes, batch_idx, gt_groups}调用self.predict(img, batchtargets)训练态 head 返回(dec_bboxes, dec_scores, enc_bboxes, enc_scores, dn_meta)loss()依据dn_meta[dn_num_split]用torch.split切分出dn_bboxes/dn_scores与主解码输出把编码器输出enc_bboxes/enc_scores拼在解码层最前面形成第 0 层即dec_bboxes cat([enc_bboxes.unsqueeze(0), dec_bboxes])形状如(7, bs, 300, 4)——这正是前文forward中“主损失用最后一层、辅助损失用其余层”的层来源调用self.criterion((dec_bboxes, dec_scores), targets, dn_bboxes..., dn_scores..., dn_meta...)。从源码看 RT-DETR 实际会返回十余个损失项主 3 辅助 3 去噪 3 以上。loss()反向传播用sum(loss.values())但仅把loss_giou / loss_class / loss_bbox三项对应giou_loss / cls_loss / l1_loss上报用于日志展示。4.2 训练入口与超参数来源训练入口为 ultralytics/models/rtdetr/train.py 中的RTDETRTrainer示例from ultralytics.models.rtdetr.train import RTDETRTrainer args dict(modelrtdetr-l.yaml, datacoco8.yaml, imgsz640, epochs3) trainer RTDETRTrainer(overridesargs) trainer.train()去噪相关超参数num_denoising、label_noise_ratio、box_noise_scale等定义在 RT-DETR 的 YAML 模型配置中例如 ultralytics/cfg/models/rt-detr/rtdetr-l.yaml同目录下还有 rtdetr-l.yaml / rtdetr-x.yaml 等变体由 nn/tasks.py 的 RTDETR 模型组装 解析进 head 模块。其训练注意事项来自 trainer 类注释RT-DETR 使用的F.grid_sample不支持deterministicTrueAMP 训练可能产生 NaN 输出并引发二分图匹配错误训练时需留意。4.3 通用训练流程中的接入loss 只在训练阶段使用导出/推理时被剥离训练结束后序列化快照会把criterion置空见 ultralytics/utils/torch_utils.py 第 847-848 行 与 engine/trainer.py 的相关剥离逻辑因此模型权重文件不含损失模块状态。普通使用者若只想跑推理完全不感知该模块只有深度训练或魔改 DETR 头时才会与其直接打交道。五、实战建议损失分量与收益速查结合源码可归纳以下可直接落地的判断供配置与调参参考关注点源码依据实操结论主损失构成_get_loss_bbox/_get_loss_classloss_giou是主要的框回归信号增益默认 2若要更快收敛可先上调giou增益分类监督方式RTDETRDetectionLoss(nc..., use_vflTrue)RT-DETR 用 Varifocal让分类目标携带预测框 IoUgt_scores由bbox_iou生成修改use_vfl/use_fl即切换范式辅助层损失_get_loss_auxaux_lossTrue编码器与每个解码中间层都被监督训练更稳但计算量增加关闭可提速去噪损失forward的dn_meta分支无 GT 时仍输出*_dn0日志中看到loss_*_dn为 0 属正常空批情形多卡 DDP空 GT 的[..., :0].sum()保护匹配数为零的图会得到零梯度占位切勿自行替换为空张量以免触发 DDP 报错想深入实验的读者可以依次阅读核心损失类 models/utils/loss.py、匹配器与去噪生成 models/utils/ops.py、RT-DETR 模型装配与loss()编排 nn/tasks.py、去噪查询注入点 nn/modules/head.py以及通用损失基元 utils/loss.pyFocalLoss、VarifocalLoss均在文件头部。六、小结ultralytics.models.utils.loss是 Ultralytics 中所有 DETR 系检测模型当前仓库中以 RT-DETR 为代表的训练心脏。DETRLoss用匈牙利匹配把集合预测问题转化为一一对应的监督问题组合 L1/GIoU/VarFocal 三类损失并逐层加辅助监督RTDETRDetectionLoss在此基础上融合对比去噪训练显著降低 decoder 收敛难度。理解本模块的默认增益、层结构L, B, N, ...与_dn后缀的损失命名约定是自定义 DETR 损失、调试训练曲线乃至复现论文改动的第一步。【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考