1.9.2
NousResearch/hermes-agent1.9.2Aug 11, 2026by Borda
Upgrading?
AI Summary
Performance and correctness release optimizing the matcher and fixing COCO dataset handling.
Key Highlights
- Breaking: Hierarchical COCO label filtering uses shared label mapping
- Matcher is ~51% faster with ~73-76% lower memory usage
- Training resume from `BestModelCallback` restores per-callback state
Breaking Changes
- Hierarchical COCO label filtering (unannotated grouping categories no longer consume a label slot)
Full Release Notes
RF-DETR 1.9.2 is a fix-and-performance release: one breaking change, no new public APIs. Hierarchical COCO datasets — most commonly Roboflow exports carrying a synthetic unannotated grouping category — now get a correct, shared label mapping across `train`/`valid`/`test`, closing a case where per-class metrics could silently corrupt on the smaller split. The matcher's compact cost-matrix path is faster and lower-memory on real batches, training-resume from `BestModelCallback`'s lightweight checkpoints now restores per-callback state instead of restarting cold, and a handful of training/eval fixes round it out.
## ✨ Spotlights / highlights
### Breaking: hierarchical COCO datasets get a correct, shared label space
Roboflow COCO exports prepend a synthetic root category (unannotated, `supercategory: "none"`) that every real class lists as its own `supercategory`. It never carried annotations but still consumed a label slot — training such a dataset built an *N+1*-class head instead of *N*.
```python
from rfdetr.datasets.coco import filter_parent_categories, annotated_category_ids
categories = [
{"id": 0, "name": "project-root", "supercategory": "none"},
{"id": 1, "name": "car", "supercategory": "project-root"},
{"id": 2, "name": "truck", "supercategory": "project-root"},
]
anns = {"annotations": [{"category_id": 1}, {"category_id": 2}]}
kept = filter_parent_categories(categories, annotated_category_ids(anns))
[c["name"] for c in kept]
# -> ['car', 'truck'] — the unannotated root no longer takes a label slot
```
For datasets where a *parent* category does carry its own annotations, label indices are now derived once from the `train` split and shared into `valid`/`test`, so a grouping category annotated in one split but not another no longer shifts that split's label indices independently of the others.
> ⚠️ **Checkpoints trained before 1.9.2 keep their old head width and label ordering.** Evaluating one against a re-filtered dataset misaligns per-class metrics (an existing `UserWarning` fires). See the migration notes below.
### Matcher: faster and lower-memory on real COCO batches
`HungarianMatcher`'s detection-only cost matrix is now built padded to each batch's `max(T_i)` target count instead of the cross-image `sum(T_i)`, when a fast eligibility check passes — identical results on eligible batches, automatic full-computation fallback otherwise.
| | before | after | change |
| -------------------- | ---------- | ---------- | ------------- |
| Matcher time | — | — | ~51% faster |
| Peak CUDA memory | — | — | ~73–76% lower |
| Training step (A100) | 288.364 ms | 232.457 ms | — |
The saving scales with target-count evenness across a batch — a batch where nearly all targets sit in one image sees little to no improvement.
### Training resume restores per-callback state
Resuming from one of `BestModelCallback`'s four lightweight checkpoints (`checkpoint_best_regular.pth`, `checkpoint_best_ema.pth`, `checkpoint_best_total.pth`, `last_ema.pth`) previously restarted best-score tracking, EMA, and early-stopping cold, silently. It now restores that state:
```python
model.train(
dataset_dir="my_dataset",
resume="output/checkpoint_best_ema.pth",
output_dir="output", # must match the original run for best-score restore
)
```
## 📝 Notable changes
### 🌱 Changed
- **`HungarianMatcher` compact-path speedup** — detection-only cost matrix padded to `max(T_i)` instead of `sum(T_i)`; ~51% faster matcher, ~73–76% lower peak CUDA memory on real COCO batches. Compact path also copies only diagonal cost blocks to CPU and batches its safety-gate sweeps into one sync. (#1297, #1281, #1312)
- **Deterministic-algorithm coverage** — `seed_all()` now also enables `torch.use_deterministic_algorithms(True, warn_only=True)`; ops without a deterministic kernel warn at execution time instead of raising. (#1307)
- **`predict()`** — pins CPU image tensors before the CUDA transfer. (#1313)
- **Two-stage query selection** — avoids materialising repeated top-k gather indices. (#1278)
- **Evaluation matching** — counts labels on host instead of device. (#1276)
- **Keypoint postprocessing** — skips redundant CUDA presence checks. (#1282)
### 🔧 Fixed
- **`BestModelCallback` resume** — resuming from a lightweight checkpoint (`checkpoint_best_*.pth`, `last_ema.pth`) now restores per-callback state instead of restarting best-score tracking, EMA, and early-stopping cold; a warning distinguishes checkpoints that intentionally omit optimizer state from ones that predate callback-state persistence entirely. (#1318)
- **Rich epoch progress bar** — no longer corrupted or duplicated by training-time log calls under `RichProgressBar(leave=True)`. (#1316)
- **`_kp_active_mask` false-positive warning** — loading a pre-keypoint-support checkpoint no longer warns about a deterministic schema buffer as a missing parameter. (#1302)
- **Deferred CUDA-device move** — an index-less `torch.device("cuda")` is normalised to the current device index before comparison, fixing spurious re-moves of every parameter on every call. (#1311)
- **Legacy query-embedding fallback** — only warns when it actually truncates weights. (#1301)
- **`eval_ema_only`** — no longer logs an empty validation pass when the base metric is empty; EMA metrics (`val/ema_mAP_50_95`, `val/ema_mAP_50`, `val/ema_mAR`, per-class AP, `val (ema)` summary table) are computed instead, and `val/F1` is no longer silently dropped. (#1289)
- **`ModelContext.reinitialize_detection_head`** — raises a clear `RuntimeError` instead of `AttributeError: 'NoneType'` after `RFDETR.inference(inplace=True)` clears the weights. (#1283)
- **`evaluate()`** — builds its datamodule from the resolution-override config. (#1280)
### ⚠️ Breaking Changes
- **Hierarchical COCO label filtering** — unannotated grouping categories no longer consume a label slot; `train`/`valid`/`test` now share one label mapping derived from `train`. Checkpoints trained before this change need retraining against the new label space — see [Migration guide](MIGRATION.md). (#1303)
## 🏆 Contributors
- **@JESUSROYETH** — matcher perf (padded cost matrix, diagonal-only CPU copy, batched safety-gate sync), `BestModelCallback` resume-state restore, Rich progress-bar fix, `eval_ema_only` fix, and five other training/inference fixes
- **@atikulmunna** ([LinkedIn](https://www.linkedin.com/in/aimunna/)) — guarded `ModelContext.reinitialize_detection_head` against cleared weights; strict-typed `rfdetr.detr` and `datasets.yolo` module boundaries
- **@Jonathan-Jesni** — strict-typed `rfdetr.datasets.save_grids` module boundary
- **@Borda** ([LinkedIn](https://linkedin.com/in/jirka-borovec)) — hierarchical COCO label-filtering fix and release maintenance
---
**Full changelog**: https://github.com/roboflow/rf-detr/compare/1.9.1...1.9.2Related Repositories
public-apis/public-apis★ 491,139
A collective list of free APIs
yt-dlp/yt-dlp★ 200,072
A feature-rich command-line audio/video downloader
microsoft/markitdown★ 191,496
Python tool for converting files and office documents to Markdown.
Significant-Gravitas/AutoGPT★ 187,704
AutoGPT is the vision of accessible AI for everyone, to use and to build on. Our mission is to provide the tools, so that you can focus on what matters.
langgenius/dify★ 159,165
Build Agentic workflows, RAG pipelines, with rich AI model and tool support on one collaborative workspace. Deploy on cloud, VPC, or self-hosted, so teams move from prototype to production without rebuilding the stack.