Skip to content

fix(predict): correct class_name for pretrained COCO models - #1051

Merged
Borda merged 10 commits into
developfrom
fix/988
May 19, 2026
Merged

Borda merged 10 commits into
developfrom
fix/988

Conversation

@Borda

@Borda Borda commented May 18, 2026

Copy link
Copy Markdown
Member

This pull request fixes and improves how COCO class IDs are mapped to class names in predictions, especially for pretrained COCO models that use sparse category IDs (with gaps) rather than contiguous indices. It ensures correct class name assignment for both pretrained and fine-tuned models, and adds comprehensive tests to cover these scenarios and prevent regressions.

COCO class ID mapping improvements:

  • Added logic in predict (in rfdetr/detr.py) to detect when a model is a pretrained COCO checkpoint (using sparse COCO category IDs) and properly map those IDs to class names, rather than assuming a direct index. This fixes incorrect class name assignments for COCO-pretrained models. [1] [2]
  • Introduced _SORTED_COCO_IDS at import time for efficient mapping from COCO category IDs to class names. [1] [2]

Testing and regression coverage:

  • Added multiple parameterized and scenario-specific tests to ensure correct class name mapping for:
    • Pretrained COCO models with sparse IDs,
    • Pretrained models with different dataset_file values,
    • Fine-tuned models with contiguous IDs,
    • Custom class names with high num_classes.
      These tests prevent regressions and cover edge cases reported in previous issues.

  • Drop _dataset_file in ("coco", None) guard from _is_coco_pretrained: pretrained COCO checkpoints packaged via Roboflow have dataset_file="roboflow", causing PR fix: correct class_name lookup for pretrained COCO models #1005 fix to never fire
  • Two conditions now sufficient: num_logit_slots > n AND class_names == COCO_CLASS_NAMES
  • Build sparse _class_id_to_name dict pairing sorted COCO IDs with class_names; raw ID 18 → "dog" instead of class_names[18] = "sheep"
  • Add _SORTED_COCO_IDS module-level constant to avoid re-sorting on every predict() call
  • Add 4 regression tests: sparse mapping (parametrized 3/18/27), dataset_file="roboflow" guard, fine-tuned direct-indexing guard, custom-names guard

resolves #988

- Drop `_dataset_file in ("coco", None)` guard from `_is_coco_pretrained`: pretrained COCO checkpoints packaged via Roboflow have `dataset_file="roboflow"`, causing PR #1005 fix to never fire
- Two conditions now sufficient: `num_logit_slots > n` AND `class_names == COCO_CLASS_NAMES`
- Build sparse `_class_id_to_name` dict pairing sorted COCO IDs with class_names; raw ID 18 → "dog" instead of `class_names[18]` = "sheep"
- Add `_SORTED_COCO_IDS` module-level constant to avoid re-sorting on every predict() call
- Add 4 regression tests: sparse mapping (parametrized 3/18/27), dataset_file="roboflow" guard, fine-tuned direct-indexing guard, custom-names guard

---
Co-authored-by: Claude Code <noreply@anthropic.com>
@Borda Borda changed the title fix(predict): correct class_name for pretrained COCO models (#988) fix(predict): correct class_name for pretrained COCO models May 18, 2026
@codecov

codecov Bot commented May 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80%. Comparing base (8162a4c) to head (c3b9985).

❌ Your project check has failed because the head coverage (80%) is below the target coverage (95%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@           Coverage Diff           @@
##           develop   #1051   +/-   ##
=======================================
  Coverage       80%     80%           
=======================================
  Files          101     101           
  Lines         8684    8695   +11     
=======================================
+ Hits          6976    6987   +11     
  Misses        1708    1708           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/rfdetr/detr.py Outdated
Comment thread src/rfdetr/detr.py Outdated
Borda and others added 6 commits May 19, 2026 07:54
Co-authored-by: Jirka Borovec <6035284+Borda@users.noreply.github.com>
For COCO-pretrained models background is implicit (below threshold),
not a sentinel label. COCO category ID 90 is "toothbrush"; the old
`cid == num_logit_slots (=90)` check mislabelled genuine toothbrush
detections as "__background__".

Now builds class_names list via two paths:
- _is_coco_pretrained=True → _class_id_to_name.get(cid, "") unconditionally
- _is_coco_pretrained=False → "__background__" sentinel preserved for fine-tuned

[resolve #R-1] /review finding by foundry:sw-engineer (report: .reports/review/2026-05-19T06-11-05Z/review-report.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
Constant was defined at module level with comment claiming it was
used for COCO sparse-ID mapping, but predict() iterates COCO_CLASSES
directly via enumerate(). The comment was false documentation debt.
COCO_CLASSES is a plain dict in ascending key order (Python 3.7+
insertion-order guarantee), making the sort redundant in any case.

[resolve #R-2] /review finding by foundry:doc-scribe (report: .reports/review/2026-05-19T06-11-05Z/review-report.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
- no-args + COCO names: assert warning fires so callers know mapping won't activate
- no-args + non-COCO names: assert no COCO warning and direct-index mapping used
- COCO-pretrained OOB gap (cid=12): assert empty string + out-of-range warning

[resolve #R-3] /review finding by foundry:qa-specialist (report: .reports/review/2026-05-19T06-11-05Z/review-report.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
Callers reading the docstring alone could not determine why a pretrained
model's class_id=18 maps to "dog" rather than "sheep". Added a second
Note block explaining the two-mode class_name mapping: sparse category-ID
lookup for pretrained COCO checkpoints vs 0-based direct indexing for
fine-tuned models.

[resolve #R-4] /review finding by foundry:doc-scribe (report: .reports/review/2026-05-19T06-11-05Z/review-report.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
Regression test for HIGH-1 fix: in the COCO-pretrained branch the background
sentinel check (cid == num_logit_slots) must not fire, because num_logit_slots=90
is a valid COCO category (toothbrush), not a no-object slot.

[resolve #R-5] /review finding by foundry:qa-specialist (report: .reports/review/2026-05-19T06-11-05Z/review-report.md)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
@Borda
Borda marked this pull request as ready for review May 19, 2026 07:44
Copilot AI review requested due to automatic review settings May 19, 2026 07:44
@Borda Borda added the bug Something isn't working label May 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes predict()’s class_name assignment for COCO-pretrained checkpoints that emit sparse COCO category IDs (with gaps) rather than contiguous 0-based indices, and adds regression tests to cover pretrained vs fine-tuned behavior.

Changes:

  • Add COCO-pretrained detection in RFDETR.predict() and map sparse COCO category IDs to the correct class names.
  • Refine background/no-object handling so COCO category id 90 (“toothbrush”) isn’t mislabeled as __background__.
  • Add multiple regression tests covering sparse-ID mapping, dataset_file variations, and guardrails for fine-tuned/custom models.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/rfdetr/detr.py Implements sparse COCO ID → class name mapping in predict() and adjusts OOB/background handling and warnings.
tests/models/test_predict.py Adds regression tests for COCO-pretrained sparse IDs, dataset_file edge cases, and non-COCO guard behavior.

Comment thread src/rfdetr/detr.py
Comment thread src/rfdetr/detr.py
Comment thread src/rfdetr/detr.py
Borda and others added 3 commits May 19, 2026 10:00
Adds _test_coco_class_name_mapping() called on RFDETRNano at default
resolution after the from_checkpoint round-trip:
- Asserts class_names == COCO_CLASS_NAMES and num_classes == 90
- Runs predict(threshold=0) to exercise all top-k output slots
- Asserts every valid COCO class_id maps via sparse-ID lookup (COCO_CLASSES)
  not 0-indexed (canonical case: class_id=18 → "dog", not "sheep")
- Asserts no detection carries "__background__" (PR #1051 HIGH-1 regression)

---
Co-authored-by: Claude Code <noreply@anthropic.com>
Check 'nano' in base_name.lower() instead of `actual_cls is RFDETRNano`
so both RFDETRNano and RFDETRSegNano exercise the COCO sparse-ID mapping
regression. Issue #988 was originally reported on a Seg model.

---
Co-authored-by: Claude Code <noreply@anthropic.com>
- Branch truly_oob warning: COCO pretrained → "unmapped COCO class_id(s) %s" instead of "out of range [0, N]"; COCO gap IDs (e.g. 12) are numerically in-range but not mapped — "out of range" was misleading
- Fine-tuned path keeps "out of range [0, %d]" (still accurate there)
- Update 2 test assertions (lines 827, 856) to check "unmapped COCO class_id" instead of "out of range"

Addresses Copilot comment #3264551042 on PR #1051.

---
Co-authored-by: Claude Code <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/rfdetr/detr.py
@Borda
Borda merged commit 6769f30 into develop May 19, 2026
30 checks passed
@Borda
Borda deleted the fix/988 branch May 19, 2026 09:33
@Borda Borda mentioned this pull request May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v1.6.4 Wrong predicted class names

2 participants