1.11.1

data-privacy-stack/presidio1.11.1Sep 30, 2026by Borda

Upgrading?

AI Summary

This release serves as a correctness patch for RF-DETR, fixing silent failures in LoRA checkpoint loading, TensorRT inference input validation, and COCO crowd region evaluation metrics.

Key Highlights

  • LoRA backbone checkpoints now load correctly instead of silently failing.
  • TensorRT inference now raises explicit errors for invalid inputs (device, dtype, non-contiguous) rather than returning wrong results.
  • Crowd-region mAP evaluation now matches pycocotools standards.
  • API renamed: `RFDETRModelModule.clip_gradients` is now `configure_gradient_clipping`.

Breaking Changes

  • `RFDETRModelModule.clip_gradients` renamed to `configure_gradient_clipping`.
  • `TRTInference` now raises `ValueError` for invalid inputs instead of returning wrong detections.
  • `TensorRTExporter.build_engine` now raises `ValueError` for `dynamic_batch=True` ONNX without specific config.
  • `RFDETR.from_checkpoint()` now raises `ValueError` instead of `KeyError: 'args'` for invalid checkpoints.

New Features

  • Added `rfdetr.export._benchmark` helpers for latency and memory measurement.
  • Added `decode_pil_image` and `decode_pil_image_bytes` for direct PIL decoding.
  • Added `CrowdRegion` and `crowd_regions_from_coco` utilities for evaluation.
  • Added `rfdetr.utilities.package.is_installed()` for dependency checking.
  • Added `Exporter.check_dependencies` as an overridable classmethod hook.

Full Release Notes

RF-DETR 1.11.1 is a correctness patch. It turns silent wrong results into loud, correct ones:

- **LoRA backbone** — `backbone_lora=True` checkpoints trained on a random encoder, no error. Now loads correctly.
- **TensorRT inference** — wrong-device/dtype/non-contiguous inputs returned wrong detections, no error. Now refused.
- **Crowd-region mAP** — val/test mAP overcounted false positives on COCO crowd regions. Now matches pycocotools.

**Most users need no action.** 4 of the 5 "breaking" changes only affect code that was already getting a wrong result or an uncaught `KeyError` — this release just stops hiding it. See the Migration guide for exact before/after code.

**The one real API change**: `RFDETRModelModule.clip_gradients` → `configure_gradient_clipping`. Only affects code that calls `clip_gradients` directly, or relies on `super().clip_gradients(...)` inside an override.

Everything else is a bug fix or documentation update.

## ✨ Spotlights

### `backbone_lora=True` checkpoints silently trained a random encoder — now fixed

`RFDETR.from_checkpoint()`, `RFDETRSmall(pretrain_weights=...)`, and `train()` all loaded a LoRA checkpoint *before* wrapping the encoder with LoRA, so none of the stored PEFT-named weights matched — the encoder silently stayed at random initialization, and `evaluate()` scored near zero with no error.

```python
# Before (1.11.0): silent — encoder never actually reloads
model = RFDETRLarge(pretrain_weights="checkpoint_best_total.pth", backbone_lora=True)
model.evaluate()  # mAP50:95 ≈ 0.0001 — looks broken, no exception

# After (1.11.1): encoder is wrapped before load, weights match
model = RFDETRLarge(pretrain_weights="checkpoint_best_total.pth", backbone_lora=True)
model.evaluate()  # mAP50:95 ≈ 0.6221 — same as the in-memory trained model
```

Measured: RF-DETR Large `@640`, LoRA-tuned on 262 COCO person images. ([#1543](https://github.com/roboflow/rf-detr/pull/1543))

### `last.ckpt` and interval checkpoints now carry enough to reload

```python
# Before (1.11.0)
RFDETR.from_checkpoint("output/last.ckpt")  # KeyError: 'args'

# After (1.11.1)
model = RFDETR.from_checkpoint("output/last.ckpt")  # rebuilds trained resolution/architecture
```

Files written by 1.11.0 and earlier can't be repaired in place — `from_checkpoint` now raises a named `ValueError` pointing at `checkpoint_best_ema.pth` and `training_config.json` instead. ([#1561](https://github.com/roboflow/rf-detr/pull/1561))

### Val/test mAP now matches pycocotools on COCO crowd regions

Detections inside `iscrowd=1` regions no longer count as false positives. Numbers shift on crowd-labelled data — Nano COCO val2017: 0.4802 → 0.4842 mAP. Training is unchanged. ([#1532](https://github.com/roboflow/rf-detr/pull/1532))

### `TRTInference` refuses inputs TensorRT would misread

```python
# Before (1.11.0): silent wrong output
trt_model(image_tensor.to(memory_format=torch.channels_last))  # 13 detections → 0, no error

# After (1.11.1): explicit refusal
trt_model(image_tensor.to(memory_format=torch.channels_last))
# ValueError: Input 'input' is not contiguous (strides (...)), and TensorRT reads it as dense
# row-major memory. Pass tensor.contiguous().
```

([#1546](https://github.com/roboflow/rf-detr/pull/1546))

### `RFDETRModelModule.clip_gradients` renamed → `configure_gradient_clipping` (Breaking)

```python
# Before (1.11.0)
class MyModule(RFDETRModelModule):
    def clip_gradients(self, optimizer, gradient_clip_val=None, gradient_clip_algorithm=None): ...


# After (1.11.1)
class MyModule(RFDETRModelModule):
    def configure_gradient_clipping(self, optimizer, gradient_clip_val=None, gradient_clip_algorithm=None): ...
```

Moves the keypoint fp16 clipping fix onto the Lightning hook meant for it — `clip_gradients` itself now reverts to Lightning's base implementation. Narrower than it looks: `configure_gradient_clipping`'s non-fused branch calls `self.clip_gradients(...)` (dynamic dispatch, not `super()`), so a subclass overriding only `clip_gradients` with self-contained logic still runs unchanged. Actually affected: code calling `clip_gradients` directly, a subclass override relying on `super().clip_gradients(...)` for RF-DETR's old fused-aware logic, and any `clip_gradients` override on the fused-AdamW path (never reached there, in 1.11.0 or 1.11.1 — see `MIGRATION.md` for the full breakdown). ([#1537](https://github.com/roboflow/rf-detr/pull/1537), [#1549](https://github.com/roboflow/rf-detr/pull/1549))

## 🔄 Migration guide

5 breaking changes — 1 API rename, 3 stricter-validation changes, 1 exception-type change. All are covered in full, with before/after code, in [MIGRATION.md](./MIGRATION.md); none were previously documented in `docs/getting-started/migration.md`.

A new overridable classmethod, `Exporter.check_dependencies` (`src/rfdetr/export/base.py`), lets a custom exporter subclass judge whether the host has what it needs to build, separately from `_check_capabilities` judging the request. Not documented yet in `docs/exports/blueprint.md` — only relevant to third-party `Exporter` subclasses, no action needed for `RFDETR.export()` callers. ([#1542](https://github.com/roboflow/rf-detr/pull/1542))

## 📝 Notable changes

### 🚀 Added

- `rfdetr.export._benchmark` (private): `measure_latency` and `measure_memory` helpers shared by the new per-hardware export cookbooks (CUDA-event timing on GPU, wall-clock/RSS otherwise). Replaces the ONNX-only `rfdetr.export._onnx.inference._onnx_runtime`, which is removed. ([#1530](https://github.com/roboflow/rf-detr/pull/1530))
- `decode_pil_image` / `decode_pil_image_bytes` (`rfdetr.datasets.io_utils`) — decode straight to a PIL image under the same decoder policy as the array-out decoders, without the NumPy round trip. ([#1551](https://github.com/roboflow/rf-detr/pull/1551))
- `CrowdRegion` / `crowd_regions_from_coco` (`rfdetr.datasets.coco`) — reads `iscrowd=1` annotations back from a COCO API for evaluation metrics that need to score them. ([#1532](https://github.com/roboflow/rf-detr/pull/1532))
- `resize_masks_nearest` (`rfdetr.evaluation.matching`) — nearest-neighbor mask resize used by the new crowd-region evaluation path. ([#1532](https://github.com/roboflow/rf-detr/pull/1532))
- `rfdetr.utilities.package` (new module): `is_installed(name)` — checks whether a package is importable without importing it, used by the new fail-fast TensorRT dependency check. ([#1542](https://github.com/roboflow/rf-detr/pull/1542))
- `Exporter.check_dependencies` (`src/rfdetr/export/base.py`) — new overridable classmethod hook; see Migration guide. ([#1542](https://github.com/roboflow/rf-detr/pull/1542))

### ⚠️ Breaking Changes

- `RFDETRModelModule.clip_gradients` is renamed to `configure_gradient_clipping`; `clip_gradients` reverts to Lightning's base implementation. Only affects direct callers of `clip_gradients`, a `super().clip_gradients(...)` call inside an override, or an override on the fused-AdamW path — a self-contained `clip_gradients` override still runs on the non-fused path via `self.clip_gradients(...)` dispatch. See `MIGRATION.md`. ([#1537](https://github.com/roboflow/rf-detr/pull/1537), [#1549](https://github.com/roboflow/rf-detr/pull/1549))
- `TRTInference` now raises `ValueError` for an input on another device, of another dtype, or non-contiguous, instead of returning wrong detections. ([#1546](https://github.com/roboflow/rf-detr/pull/1546))
- `TensorRTExporter.build_engine` now raises `ValueError` on a `dynamic_batch=True` ONNX unless its `TensorRTConfig` sets `dynamic_batch=True` and `max_batch_size`. `RFDETR.export()` is unaffected. ([#1542](https://github.com/roboflow/rf-detr/pull/1542))
- `RFDETR.from_checkpoint()` on a checkpoint with no `"args"` now raises `ValueError` instead of `KeyError: 'args'`. ([#1561](https://github.com/roboflow/rf-detr/pull/1561))
- Loading a `backbone_lora=True` checkpoint without `peft` installed now raises `ImportError` instead of silently loading a random encoder. ([#1543](https://github.com/roboflow/rf-detr/pull/1543))

### 🌱 Changed

- Export cookbooks restructured per hardware target (`export-cuda`/`export-cpu`/`export-mobile`/ `export-apple`), replacing 4 per-format ones; adds first coverage for ONNX, OpenVINO, LiteRT, CoreAI. ([#1530](https://github.com/roboflow/rf-detr/pull/1530))
- `RFDETR.from_checkpoint()` no longer restores `device` from `model_config` — the loading host's default wins; pass `device=` explicitly. ([#1534](https://github.com/roboflow/rf-detr/pull/1534), [#1561](https://github.com/roboflow/rf-detr/pull/1561))
- `[coreai]` extra pins `coreai-torch==0.4.3`, widens Python range to `<3.15`, and declares a uv conflict with `[tflite]`. ([#1527](https://github.com/roboflow/rf-detr/pull/1527))
- The `e2e_onnxruntime` pytest marker is renamed `e2e_onnx` in `pyproject.toml`. Contributor-facing only: `pytest -m e2e_onnxruntime` now silently selects nothing (pytest doesn't error on an unmatched `-m`) — update local invocations and CI configs to `e2e_onnx`. ([#1530](https://github.com/roboflow/rf-detr/pull/1530))
- `amp_dtype="auto"` now picks fp16 on CUDA GPUs without native bf16 (T4, V100); bf16 only when every selected GPU is Ampere or newer. Loss curves/checkpoints across this change are not comparable on pre-Ampere GPUs. ([#1538](https://github.com/roboflow/rf-detr/pull/1538))
- Val/test mAP now ignores detections on COCO crowd regions, matching pycocotools. ([#1532](https://github.com/roboflow/rf-detr/pull/1532))
- `TrainConfig.clip_max_norm` now rejects a negative value at construction instead of silently training unclipped. ([#1537](https://github.com/roboflow/rf-detr/pull/1537), [#1549](https://github.com/roboflow/rf-detr/pull/1549))

### ❌ Removed

- `rfdetr.export._onnx.inference._onnx_runtime` (private ONNX-only benchmark helper) — superseded by `rfdetr.export._benchmark`. ([#1530](https://github.com/roboflow/rf-detr/pull/1530))

### 🔧 Fixed

- YOLO datasets stored under a directory named `images` now resolve their labels directory correctly. ([#1557](https://github.com/roboflow/rf-detr/pull/1557))
- `last.ckpt`/interval checkpoints record model class, config, class names, and rfdetr version; `from_checkpoint` no longer loses the dataset's class names. ([#1561](https://github.com/roboflow/rf-detr/pull/1561))
- COCO training on non-JPEG images (or JPEG without `simplejpeg`) is back to 1.10 decode speed — up to 27% faster per batch on large BMP files. ([#1551](https://github.com/roboflow/rf-detr/pull/1551))
- `format="coreai"` works with `coreai-torch` 0.4.3. ([#1527](https://github.com/roboflow/rf-detr/pull/1527))
- `from_checkpoint("checkpoint_best_total.pth")` rebuilds the trained architecture instead of falling back to class defaults. ([#1534](https://github.com/roboflow/rf-detr/pull/1534))
- Keypoint fp16 training clips the real gradient (was clipping before GradScaler unscale, silently stalling training). ([#1537](https://github.com/roboflow/rf-detr/pull/1537), [#1549](https://github.com/roboflow/rf-detr/pull/1549))
- `amp_dtype="auto"` no longer selects emulated bf16 on T4/V100 — Colab T4 Nano step 443ms → 226ms in fp16. ([#1538](https://github.com/roboflow/rf-detr/pull/1538))
- Crowd-region detections no longer counted as false positives in COCO eval. ([#1532](https://github.com/roboflow/rf-detr/pull/1532))
- `TRTInference.build_engine` no longer truncates an existing `.trt` file on a failed build. ([#1546](https://github.com/roboflow/rf-detr/pull/1546))
- An undeserializable TensorRT engine reports a named `RuntimeError` instead of `AttributeError`. ([#1546](https://github.com/roboflow/rf-detr/pull/1546))
- `TRTInference(device=...)` now loads and runs the engine on that device (was mixing GPUs). ([#1546](https://github.com/roboflow/rf-detr/pull/1546))
- TensorRT export refusal messages name working export settings instead of a bare flag. ([#1546](https://github.com/roboflow/rf-detr/pull/1546))
- `backbone_lora=True` checkpoints reload their trained backbone (was silently random-init; measured val mAP50:95 0.0001 → 0.6221). ([#1543](https://github.com/roboflow/rf-detr/pull/1543))
- `RFDETR.export(format="tensorrt")` without `tensorrt` installed fails before the ONNX export with a named `ImportError`. ([#1542](https://github.com/roboflow/rf-detr/pull/1542))
- `compile=True` with default `multi_scale` stops recompiling the transformer per resolution. ([#1539](https://github.com/roboflow/rf-detr/pull/1539))
- COCO segmentation datasets mixing annotated and box-only instances keep every mask. ([#1558](https://github.com/roboflow/rf-detr/pull/1558))
- Fixed JSON serialization in the COCO val-subset builder. ([`fd3bb991`](https://github.com/roboflow/rf-detr/commit/fd3bb991), no PR — direct commit)

### 📚 Documentation

- Documented `TrainConfig.eval_backend` in the advanced training guide. ([#1526](https://github.com/roboflow/rf-detr/pull/1526))
- Scoped the static INT8 export limit to TFLite specifically. ([#1559](https://github.com/roboflow/rf-detr/pull/1559))

## 🏆 Contributors

- **Jirka Borovec** (@Borda, [LinkedIn](https://linkedin.com/in/jirka-borovec)) — restructured export cookbooks by hardware target, replacing four per-format notebooks; fixed JSON serialization in the COCO val-subset builder; unified export CI jobs into one matrix.
- **Lương Thanh Hoàng Phú** (@lthphuw, [LinkedIn](https://linkedin.com/in/phu-lth)) — hardened `TRTInference` to reject mismatched device/dtype/contiguity instead of returning silently wrong detections; fixed checkpoints to record training args and model config so `from_checkpoint` no longer raises `KeyError`; fixed LoRA backbone reload, which had silently stayed at random init.
- **Raghav Rathi** (@raghav-rathi, [LinkedIn](https://www.linkedin.com/in/raghavrathi00/)) — fixed keypoint gradient clipping under fp16, which ran before GradScaler unscale and silently stalled training; fixed `amp_dtype="auto"` selecting emulated bf16 on GPUs without native support; excluded COCO crowd-region detections from val/test mAP.
- **Mohammad Hijjawi** (@MohammadHijjawi97, [LinkedIn](https://www.linkedin.com/in/mohammadhijjawi)) — fixed COCO segmentation to keep all masks when an image's first annotation has no `segmentation` field; fixed YOLO labels-directory resolution for datasets nested under an `images` directory.
- **Christoph Deil** (@cdeil, [LinkedIn](https://www.linkedin.com/in/christophdeil)) — fixed CoreAI export compatibility with `coreai-torch` 0.4.3 after it removed `AIProgram.optimize()`.

*Automated contributions from claude[bot], pre-commit-ci[bot], Copilot Autofix powered by AI, copilot-swe-agent[bot], OpenAI Codex, Claude Sonnet 5, Claude Opus 5 (1M context), and Claude Opus 5.5 supported this release.*

---

**Full changelog**: https://github.com/roboflow/rf-detr/compare/1.11.0...1.11.1

Related Repositories