Fix D-FINE / RT-DETR main loss being computed over the denoising queries - #48528
Open
stefan-it wants to merge 4 commits into
Open
Fix D-FINE / RT-DETR main loss being computed over the denoising queries#48528stefan-it wants to merge 4 commits into
stefan-it wants to merge 4 commits into
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
`DFineForObjectDetectionLoss` and `RTDetrForObjectDetectionLoss` (also used by RT-DETRv2) built the main, Hungarian-matched loss term from the last decoder layer's `logits` / `pred_boxes` over all queries. During training with `num_denoising > 0` these tensors contain the contrastive denoising queries in front of the normal queries; they were only split off for the auxiliary and `dn_*` terms. As the positive denoising queries start next to the ground truth, the matcher assigned most targets to them and the normal queries of the inference layer received almost no positive supervision. Split the denoising queries off the main term as the reference implementations do, and add regression tests for D-FINE and RT-DETR. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
stefan-it
force-pushed
the
fix-detr-denoising-main-loss
branch
from
September 4, 2026 13:34
9883635 to
c0447d9
Compare
Contributor
|
[For maintainers] Suggested jobs to run (before merge) run-slow: d_fine, rt_detr |
Contributor
CI recapDashboard: View test results in Grafana |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes a training bug in the D-FINE and RT-DETR (incl. RT-DETRv2) losses: the main, Hungarian-matched loss term was computed over the contrastive-denoising queries as well, which starves the normal queries of the inference layer of positive supervision.
The bug
DFineForObjectDetectionLoss(src/transformers/loss/loss_d_fine.py) andRTDetrForObjectDetectionLoss(src/transformers/loss/loss_rt_detr.py, also mapped forRTDetrV2ForObjectDetection) receive the last decoder layer'slogits/pred_boxesfrom the model. In training mode withnum_denoising > 0these tensors contain the contrastive denoising (CDN) queries followed by the normal queries, e.g.[batch, 200 + 300, num_labels]. Both functions split the CDN queries off for the auxiliary anddn_*terms (torch.split(..., dn_num_split, dim=2)), but never for the main term:The positive CDN queries are initialized from lightly noised ground-truth boxes, so the matcher of the main term assigns most targets to them. The normal queries of the last decoder layer, the only ones used at inference (
eval_idx = -1), then get almost no positive signal from the main term. Training losses look healthy while validation mAP stalls with low, badly calibrated scores and class confusion, which makes this hard to spot.The reference implementations split the denoising queries before building the main term:
torch.split(out_logits, dn_meta["dn_num_split"], dim=2)→"pred_logits": out_logits[-1])loss_deimv2.pyalready does this for DEIMv2, so it is not affected.Measurements
Fine-tuning
ustc-community/dfine-nano-cocoon a 4-class document layout dataset (6.4k images) with the original D-FINE hyper-parameters. Matching of the main term on a real training batch (8 images, 12 ground-truth boxes) after 7 epochs:The last-layer
loss_vflrestricted to the normal queries was 2.55, while the value entering the training loss was 0.92.Class-aware COCO AP on the validation split (no score threshold), same data, hyper-parameters and schedule:
With the stock loss the model localized boxes fine but labelled nearly everything as a single class with low scores; the class-agnostic AP at the 0.3 score threshold plateaued around 0.4 for 45 epochs, while the original D-FINE repo reaches 0.71 on that metric.
The fix
At the top of both loss functions, before the
config.auxiliary_lossbranch (so it also applies with auxiliary losses disabled):Reproduction
Fails on
mainwithAssertionError: Scalars are not close!, passes with this PR:Tests
test_main_loss_excludes_denoising_queriesintests/models/d_fine/test_modeling_d_fine.pyandtests/models/rt_detr/test_modeling_rt_detr.pytrains a small model with denoising enabled and asserts that the main loss terms equal the loss recomputed on the normal queries alone. Both fail onmainand pass with this PR. The full (non-slow) D-FINE, RT-DETR and RT-DETRv2 test files pass:Side note, not part of this PR: the original D-FINE also applies the fine-grained localization loss (
loss_fgl) to the last decoder layer, whereas the HF main term only hasloss_vfl/loss_bbox/loss_giou. That is a smaller fidelity gap and can be addressed separately.The bug was found while porting a D-FINE fine-tuning pipeline to Transformers, with the analysis done by Claude Fable 5.1 (Claude Code).
Before submitting
Who can review?
@qubvel
🤖 Generated with Claude Code