1.9.0

expressjs/express1.9.0Jul 29, 2026by Borda

AI Summary

A major release introducing configurable training (optimizer/scheduler), multi-GPU keypoint training, and new export formats including ExecuTorch and native CoreML.

Key Highlights

  • Native CoreML export support for .mlpackage
  • ExecuTorch export support for .pte
  • Multi-GPU and multi-node keypoint training under DDP
  • Configurable optimizer and LR scheduler

Breaking Changes

  • `albumentations` and `kornia` extras merged into `augment`
  • Default augmentation backend changed from Albumentations to torchvision
  • Unrecognised `train()` kwargs now raise `ValueError`

New Features

  • Native CoreML export
  • ExecuTorch export
  • TensorRT export improvements
  • In-memory evaluation via `RFDETR.evaluate()`
  • Multi-GPU keypoint training under DDP
  • Configurable optimizer and LR scheduler
  • Configurable `TrainConfig.scale_jitter`
  • Torchvision-native augmentation backend

Full Release Notes

RF-DETR v1.9.0 makes training more configurable and deployment more portable. The training optimizer and LR scheduler are now pluggable (any `torch.optim` name, dotted import path, or callable), keypoint/pose models can train under multi-GPU and multi-node DDP, and models export to ExecuTorch (`.pte`) and native CoreML (`.mlpackage`) for on-device inference, alongside an improved TensorRT export path. Checkpoint loading is also hardened: `RFDETR.from_checkpoint()` now defaults to safe (`weights_only=True`) deserialization. The default augmentation backend changes in this release β€” see the migration guide before upgrading if you rely on the previous default.

## ✨ Spotlights / highlights

### ExecuTorch export

```python
model = RFDETRSmall()
model.export(format="executorch", backend="xnnpack")  # or "coreml", "qnn"
```

### Native CoreML export

```python
model = RFDETRSmall()
model.export(format="coreml", coreml_precision="float16")  # .mlpackage, no ONNX intermediary
```

### Multi-GPU / multi-node keypoint training

```python
RFDETRKeypointPreview().train(
    dataset_dir="...",
    strategy="ddp",
    devices=4,
    grad_accum_steps=1,
)
```

### Configurable optimizer & LR scheduler

```python
from rfdetr.config import TrainConfig

TrainConfig(
    optimizer="pytorch_optimizer.Lion",
    lr_scheduler="torch.optim.lr_scheduler.OneCycleLR",
    lr_scheduler_kwargs={"max_lr": 1e-3, "total_steps": 10_000},
)
```

### Safe checkpoint loading by default

```python
model.from_checkpoint("checkpoint.pth")  # now weights_only=True by default
model.from_checkpoint("legacy_checkpoint.pth", trust_checkpoint=True)  # opt-in for trusted files
```

## πŸ”„ Migration guide

### Breaking changes

**`albumentations` and `kornia` extras merged into `augment`**

| Old extra                                | New extra               |
| ---------------------------------------- | ----------------------- |
| `rfdetr[train]` (implied albumentations) | `rfdetr[train,augment]` |
| `rfdetr[kornia]`                         | `rfdetr[augment]`       |

There is no `[kornia]` compatibility alias β€” `pip install 'rfdetr[kornia]'` fails after upgrading.

**Default resize interpolation changed** β€” pixel values and mAP may shift. The default resize backend changed from Albumentations to torchvision. To restore the previous behaviour:

```bash
pip install 'rfdetr[augment]'
```

```python
from rfdetr.datasets.aug_configs import AUG_CONFIG
train_config = TrainConfig(aug_config=AUG_CONFIG, ...)
```

Installing `rfdetr[augment]` is not by itself sufficient to pin behaviour β€” pass `augmentation_backend="torchvision"` explicitly to pin it regardless of what's installed.

**Unrecognised `train()` kwargs now raise `ValueError`** β€” `TrainConfig` uses `extra="forbid"`; a typo'd kwarg that previously trained silently with defaults now raises immediately with a suggestion.

### Removed

Deprecated in earlier releases, removed as of v1.9:

- `rfdetr.util.*` and `rfdetr.deploy.*` import paths (deprecated since v1.6) β†’ `rfdetr.utilities.*`, `rfdetr.assets.coco_classes`, `rfdetr.training.drop_schedule`, `rfdetr.training.param_groups`, `rfdetr.visualize.data`, `rfdetr.models.heads.segmentation`, `rfdetr.export`
- `build_namespace(model_config, train_config)` (deprecated since v1.7) β†’ `build_model_from_config` / `build_criterion_from_config`
- `load_pretrain_weights(nn_model, model_config, train_config)`'s `train_config` argument (deprecated since v1.7) β†’ call `(nn_model, model_config)`
- `start_epoch`, `do_benchmark`, `callbacks` kwargs on `.train()`/`.evaluate()` (deprecated since v1.7) β†’ `resume=`, `rfdetr.export.benchmark`, PTL `Callback` objects respectively
- Misplaced config fields β€” `TrainConfig.{group_detr, ia_bce_loss, segmentation_head, num_select}` β†’ `ModelConfig`; `ModelConfig.cls_loss_coef` β†’ `TrainConfig` (deprecated since v1.7)
- `RFDETRLarge`'s silent fallback to `RFDETRLargeDeprecatedConfig` on checkpoint/config incompatibility β€” now raises the original error; use `RFDETRLargeDeprecated` directly for legacy Large weights

### Deprecated in v1.9 β†’ Remove in v1.11

- `RFDETR.optimize_for_inference()` renamed to `RFDETR.inference()` (same signature) β€” old name kept as an alias, emits `FutureWarning`
- `TrainConfig.lr_drop` and `lr_min_factor` β€” pass through `lr_scheduler_kwargs` instead

Full details, including code before/after examples for every item above: `docs/getting-started/migration.md` β†’ "Upgrade 1.8 β†’ 1.9".

## πŸ“ Notable changes

### πŸš€ Added

- **Native CoreML export** β€” `RFDETR.export(format="coreml")` produces a `.mlpackage` (mlprogram, iOS 16+) directly from `torch.export`, no ONNX intermediary; `coreml_precision="float32"|"float16"` controls compute precision. Install with `pip install 'rfdetr[coreml]'` (macOS only, `coremltools>=8.0,<10.0`). Distinct from ExecuTorch's `format="executorch", backend="coreml"` `.pte` path. (#1235, #1244)
- **ExecuTorch (`.pte`) export** β€” `RFDETR.export(format="executorch")` for XNNPACK CPU, Core ML, and experimental Qualcomm QNN backends; static-shape deformable-attention export, fail-fast validation for unsupported dynamic batching. (#1142, #1231, #1237)
- **TensorRT export improvements** β€” `RFDETR.export(format="tensorrt")` (alias `"trt"`) builds `.trt` engines in-process; configurable `fp16: bool = True` precision with automatic FP32 fallback. (#853, #1231)
- **`RFDETR.evaluate(*, split="test"|"val", **kwargs)`** β€” runs COCO evaluation (mAP, mAR, macro-F1, per-class AP) on the in-memory model without a checkpoint reload. (#1134)
- **Multi-GPU / multi-node keypoint (pose) training under DDP** β€” keypoint models train with `strategy="ddp"`/`"auto"`, `devices>1`, `num_nodes>1`. Sharded strategies (FSDP/DeepSpeed) remain unsupported and now fail with a clear error. (#1232)
- **Configurable training optimizer** β€” `TrainConfig.optimizer: str | Callable = "adamw"` plus `optimizer_kwargs`. (#1006)
- **Configurable LR schedulers** β€” `TrainConfig.lr_scheduler: str | Callable = "step"` plus `lr_scheduler_kwargs`, `lr_scheduler_interval`, `lr_scheduler_monitor`; end-to-end `ReduceLROnPlateau` support. (#1217)
- **`TrainConfig.scale_jitter: bool = True`** — independent control of the resize→crop→resize training branch, decoupled from `aug_config`. (#1037)
- **Torchvision-native augmentation backend + selectable backends** β€” `AugmentationBackend.TV`/`.ALBU`/`.KORNIA`; `augmentation_backend="torchvision"` always pins torchvision. (#1112)
- **Mask-aware dataset grids** β€” instance-segmentation label validation renders masks in `save_grids`. (#1014)
- **`TrainConfig.eval_ema_only: bool = False`** β€” opt-in EMA-only evaluation. (#1225)

### ⚠️ Breaking Changes

- **Augmentation backend default** β€” training/validation/export now resolve to torchvision-native transforms unless Albumentations is installed; `[train]` no longer bundles Albumentations/Kornia. See migration guide. (#1112)
- **Unrecognised `train()`/`evaluate()` kwargs now raise `ValueError`** instead of silently training with defaults. (#1178)

### 🌱 Changed

- Always save EMA-named checkpoints (`checkpoint_best_ema.pth`, `last_ema.pth`) when `monitor_ema` is set; `checkpoint_best_total.pth` records provenance. (#1216)
- Epoch-level train loss shown in the training progress bar. (#1211)
- Improved training performance β€” foreach EMA update, gated validation loop, TF32 enabled. (#1226)
- Improved evaluation performance β€” removed per-iteration GPU sync in matching. (#1225)
- Matched-pair IoU targets in the loss computation now use new O(N) `elementwise_box_iou`/`elementwise_generalized_box_iou` helpers instead of building the full NxN pairwise matrix and reading its diagonal, reducing peak GPU memory during loss calculation. (#1245)
- `[tensorrt]` no longer installs `pycuda` — it's only needed for `TRTInference`'s async benchmarking mode, now under the separate `[tensorrt-bench]` extra. The standard export→engine path is unaffected. (#1246)

### πŸ—‘οΈ Deprecated

- `RFDETR.optimize_for_inference()` β†’ `RFDETR.inference()` (same signature). (#1212)
- `TrainConfig.lr_drop` / `lr_min_factor` β†’ `lr_scheduler_kwargs`. (#1217)

### ❌ Removed

- `rfdetr.util.*`, `rfdetr.deploy`, `build_namespace()`, `load_pretrain_weights()`'s `train_config` arg, `start_epoch`/`do_benchmark`/`callbacks` train() kwargs, misplaced `TrainConfig`/`ModelConfig` fields, `RFDETRLarge`'s silent legacy-config fallback β€” all deprecated since v1.6/v1.7, removed as scheduled. (#1218)
- `[kornia]` pip extra β€” folded into `[augment]`, no compatibility alias. (#1142, #1112)

### πŸ”§ Fixed

- First `predict()`/`inference()` call no longer silently breaks subsequent `backward()` gradients. (#1178)
- Optimized keypoint models correctly return `sv.KeyPoints`. (#1210)
- `predict()` resize antialias disabled to match training/val preprocessing. (#1206)
- ONNX export at non-native resolution no longer crashes. (#1207)
- Keypoint DDP training no longer hangs on the out-of-schema loss guard (graph-connected zeros instead of detached). (#1232)
- `window_block_indexes` override now correctly forwarded to DINOv2. (#1224)
- Non-square Albumentations training resize no longer inflates every image to `max_size`. (#1112, #1183)
- **`RFDETR.from_checkpoint(..., trust_checkpoint=True)` now actually works** β€” it previously bypassed the safe-load check only for the checkpoint's metadata read; model construction silently reloaded the same file without the caller's trust setting and raised anyway. (#1239)
- Segmentation evaluation now resizes ground-truth masks directly to each prediction's own pixel grid instead of each image's original resolution, removing a lossy round trip vs. the mask head's native grid β€” segm mAP is computed on consistent pixel grids. (#1241)
- `pip install 'rfdetr[onnx]'` (and `[tflite]`) no longer hangs building `onnxsim` from source on CPython 3.11/3.13 and Linux aarch64 β€” the `onnxsim<0.6.0` pin resolved to a version with no prebuilt wheels for those targets; now `onnxsim>=0.7.0`. (#1242)

### πŸ”’ Security

- Safe checkpoint loading by default β€” `RFDETR.from_checkpoint()` uses `weights_only=True`; opt into full pickle deserialization via `trust_checkpoint=True` for trusted/legacy files. (#1179)
- TensorRT export no longer shells out to `trtexec` β€” engines build in-process via the `polygraphy` Python API, removing the subprocess/shell-injection surface entirely. (#853)

---

## πŸ† Contributors

- **Anatoly Ryabchenko** (@anatoly-ryabchenko, [LinkedIn](https://www.linkedin.com/in/anatoly-ryabchenko/)) β€” ExecuTorch (.pte) export; `RFDETR.evaluate()` in-memory COCO eval
- **Robin Cole** (@robmarkcole, [LinkedIn](https://www.linkedin.com/in/robmarkcole/)) β€” dataset augmentation refactor onto torchvision-native transforms with a selectable Albumentations/Kornia backend
- **Michael Mohamed** (@michaelmohamed) β€” multi-GPU/multi-node DDP keypoint (pose) training
- **M. Fazri Nizar** (@mfazrinizar, [LinkedIn](https://www.linkedin.com/in/mfazrinizar)) β€” third-party training optimizer support; epoch-level train loss in the progress bar
- **Stefan Schneider** (@hinogi) β€” strict-mypy typing cleanup across export, models, evaluation, platform, and utilities
- **Jonas Pirner** (@pirnerjonas) β€” mask-aware dataset grids for instance-segmentation label validation
- **Omkar Kabde** (@omkar-334, [LinkedIn](https://www.linkedin.com/in/omkar-kabde/)) β€” decoupled the resize scale-jitter branch from `aug_config` via the new `scale_jitter` flag
- **Brian Cong** (@congbrian, [LinkedIn](https://www.linkedin.com/in/brian-cong-babb042a0/)) β€” native CoreML export; typed `drop_schedule`/`models.math`; fixed the ExecuTorch export level-dim shape mismatch
- **Γ–mer GΓΌnaydΔ±n** (@siromermer, [LinkedIn](https://www.linkedin.com/in/%C3%B6mer-g%C3%BCnayd%C4%B1n-17811b216)) β€” fixed YOLO split-directory resolution to honor `data.yaml` paths
- **Deependu** (@deependujha) β€” fixed a spurious `pyDeprecate` CLI warning
- **Peter Robicheaux** (@probicheaux, [LinkedIn](https://www.linkedin.com/in/peter-robicheaux-01958813b/)) β€” docs: NAS platform availability note, citation author correction
- **Matvei Popov** (@Matvezy, [LinkedIn](https://www.linkedin.com/in/matvezy)) β€” platform-vs-paper NAS comparison chart in the README
- **ARDA7787** (@ARDA7787) β€” fixed a resource leak by closing the HTTP response with a context manager in `_download_file`
- **Erik** (@Erol444, [LinkedIn](https://linkedin.com/in/erik-kokalj)) β€” GA4 tracking on the docs site
- **Sergii Bondariev** (@sergii-bond, [LinkedIn](https://www.linkedin.com/in/sergiibondariev/)) β€” reduced peak GPU memory in the loss computation's box-IoU matching
- **Takeshi Watanabe** (@take-cheeze) β€” fixed the `[onnx]`/`[tflite]` install hang caused by a stale `onnxsim` pin
- **Jirka Borovec** (@Borda, [LinkedIn](https://linkedin.com/in/jirka-borovec)) β€” safe checkpoint loading by default, TensorRT export rewrite onto in-process polygraphy (no more `trtexec` subprocess), configurable LR schedulers, always-saved EMA checkpoints, removed the 1.9.0-scheduled deprecated APIs, TensorRT fp16 export, segmentation-eval mask-resize fix

---

**Full changelog**: https://github.com/roboflow/rf-detr/compare/1.8.3...1.9.0