1.9.4

windmill-labs/windmill1.9.4Aug 24, 2026by Borda

AI Summary

A maintenance release fixing bugs in ONNX/TFLite export (background logit slot, keypoint masks) and augmentation (keypoint flip safety, Albumentations transforms).

Key Highlights

  • Configurable background logit slot for ONNX/TFLite export
  • Fixed keypoint flip safety (empty flip pairs no longer silently corrupt data)
  • Fixed Albumentations `TimeReverse` and `SquareSymmetry` handling
  • `BestModelCallback` no longer scores sanity check as real epoch
  • Fixed TFLite export failing on missing `onnxsim`

Breaking Changes

  • Keypoint training with empty `keypoint_flip_pairs` now disables flip
  • TFLite export helper no longer treats lone rank-4 output as mask

Full Release Notes

RF-DETR 1.9.4 is a maintenance release: no public API removed or renamed, no new public API — the new arguments below sit on private ONNX/TFLite reference helpers. It fixes seven bugs — two in export (ONNX/TFLite background-logit-slot assumption, a keypoint tensor misidentified as a segmentation mask), two silent annotation-corruption bugs in augmentation (keypoint flip with empty flip-pairs, Albumentations `TimeReverse`/`SquareSymmetry`), one training-correctness bug (`BestModelCallback` scoring PyTorch Lightning's sanity-check pass as a real epoch), one non-square training resize bug, and one environment-dependent TFLite export failure.

Users exporting sparse-ID COCO checkpoints — including the official pretrained weights — or legacy background-first keypoint checkpoints, training keypoint models with the pydantic-default empty `keypoint_flip_pairs`, using custom Albumentations `TimeReverse`/`SquareSymmetry` configs, starting a new training run seeded from `pretrain_weights`, or training non-square models benefit most from this release. See the migration guide below — three behavior changes may need action on upgrade.

## ✨ Spotlights / highlights

### Export: configurable background logit slot ([#1397](https://github.com/roboflow/rf-detr/pull/1397))

The ONNX/TFLite reference inference helpers assumed the background class always sits at the final logit index. Sparse-ID COCO checkpoints and legacy background-first keypoint checkpoints decoded wrong. A new `background_class_id` argument on the private `_run_inference` helpers makes the assumption explicit — `-1` (default) preserves current behavior, `None` keeps every logit slot, `0` supports legacy background-first keypoint checkpoints. The `-1` default is kept for backward compatibility; it still mis-decodes the checkpoints named above, including the official pretrained COCO weights (a real foreground category occupies the final slot there) — pass `background_class_id=None` explicitly for those. The same commit also replaces the TFLite helper's old guess-any-lone-rank-4-output-is-a-mask behavior with a new `rank4_output` argument, defaulting to `None` — a keypoint export's `pred_keypoints` tensor could previously get silently upsampled into `Detections.mask`.

### Keypoint annotations no longer silently corrupted on flip ([#1358](https://github.com/roboflow/rf-detr/pull/1358))

`RandomHorizontalFlip` on the torchvision-native backend mirrored keypoint x-coordinates on every drawn flip, but only relabeled left/right joints `if self.keypoint_flip_pairs:`. With an empty list — the pydantic default — training samples got keypoints mirrored in position while keeping their original left/right label, with no warning. The flip is now dropped entirely for an empty-but-not-`None` `keypoint_flip_pairs`, matching the Albumentations backend's existing safety contract.

### Albumentations `TimeReverse`/`SquareSymmetry` box and keypoint handling ([#1386](https://github.com/roboflow/rf-detr/pull/1386))

Custom Albumentations configs using `TimeReverse` had it treated as pixel-only — it flipped images while leaving boxes and keypoints unchanged. It now shares the same geometric-transform and replay-based keypoint handling as `HorizontalFlip`, and the no-pairs safety filter now also covers `SquareSymmetry`.

### `BestModelCallback` no longer scores the PTL sanity check as a real epoch ([#1357](https://github.com/roboflow/rf-detr/pull/1357))

A positive validation score from PyTorch Lightning's pre-training sanity check — common when starting a new run initialized with `pretrain_weights` from a checkpoint pretrained on a different dataset — could get written out as the permanent "best" EMA checkpoint before a single real epoch ran, after which real training could never surpass it. EMA tracking now honors the same `trainer.sanity_checking` guard the regular checkpoint path already had. (This is distinct from PTL's own `resume`/`ckpt_path` restart, which PTL itself skips the sanity check for — resumed runs were never affected.)

## 🔄 Migration guide

No public API was removed or renamed. Three behavior changes may need action on upgrade:

- **TFLite segmentation inference.** The `_run_inference` reference helper no longer treats an anonymous rank-4 output as a mask. Pass `rank4_output="masks"` for a name-stripped segmentation export.
- **Keypoint training with `keypoint_flip_pairs=[]`** (the pydantic default). The default horizontal flip is now disabled instead of applied without relabeling. Provide left/right pairs to keep the augmentation.
- **Non-square training.** The crop branch no longer resamples through a fixed `384x384` intermediate, so the augmented pixel distribution differs from 1.9.3. Square training (the default for every shipped model config) is unchanged.

## 📝 Notable changes

### 🔧 Fixed

- ONNX and TFLite reference inference helpers now accept an explicit `background_class_id`; a new `rank4_output` argument replaces the old guess-any-lone-rank-4-output-is-a-mask behavior and defaults to `None`. ([#1397](https://github.com/roboflow/rf-detr/pull/1397))
- Non-square training resize no longer double-resamples crop-branch outputs through a fixed `384x384` intermediate. ([#1383](https://github.com/roboflow/rf-detr/pull/1383))
- Custom Albumentations `TimeReverse` no longer leaves boxes and keypoints unflipped while the image flips; the no-pairs keypoint safety filter now also covers `SquareSymmetry`. ([#1386](https://github.com/roboflow/rf-detr/pull/1386))
- TFLite export no longer fails when `onnx2tf` can't resolve `onnxsim` from a non-activated virtualenv; RF-DETR now temporarily adds the running interpreter's script directory to `PATH` during conversion. ([#1366](https://github.com/roboflow/rf-detr/pull/1366), fixes [#1365](https://github.com/roboflow/rf-detr/issues/1365))
- Torchvision-native training no longer silently mirrors keypoint positions without relabeling left/right joints when `keypoint_flip_pairs=[]`. ([#1358](https://github.com/roboflow/rf-detr/pull/1358))
- `BestModelCallback` no longer treats PyTorch Lightning's sanity-check pass as a real epoch's result. ([#1357](https://github.com/roboflow/rf-detr/pull/1357), fixes [#1348](https://github.com/roboflow/rf-detr/issues/1348))

## 🏆 Contributors

- **Jesús Royeth** (@JESUSROYETH) — export background-logit-slot fix, keypoint flip-pair safety fix, Albumentations `TimeReverse`/`SquareSymmetry` fix, `BestModelCallback` sanity-check fix.
- **Aman Harsh** (@amanharshx, [LinkedIn](https://www.linkedin.com/in/amanharshx/)) — TFLite export `onnxsim`-on-`PATH` fix.
- **jirka** (@Borda, [LinkedIn](https://linkedin.com/in/jirka-borovec)) — non-square training resize double-resample fix.

---

**Full changelog**: https://github.com/roboflow/rf-detr/compare/1.9.3...1.9.4