Changelog¶
RF-DETR release notes are maintained on GitHub Releases. Use the release feed to review versioned package changes, migration notes, and model updates.
- Install the latest PyPI package
- Migration guide — upgrade steps between major versions
- Cookbooks — runnable notebooks for training, fine-tuning, export, and deployment
Changelog¶
All notable changes to RF-DETR are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]¶
Added¶
-
Added
TrainConfig.eval_backend, selecting the COCO evaluator used for validation and test mAP. Both options now ship withrfdetr[train];"faster_coco_eval"restores the previous evaluator. Keypoint OKS evaluation is unaffected, and the ONNX/TensorRT benchmark evaluator inrfdetr.evaluation.coco_evalcontinues to usefaster-coco-evaldirectly. -
Added
python -m rfdetr.cli.webdatasetas the dedicated packing entry point. -
RFDETR.inference()now acceptscompile_backend="inductor"as an opt-in backend for long-running inference at a fixed batch size and resolution; the default remains the existing TorchScript path. On CUDA, Inductor completes its two setup invocations and synchronizes insideinference()before the first publicpredict()call. Runtime benefit and compatibility depend on the workload, CUDA device, operators, and installed PyTorch version. -
Added
dataset_file="webdataset", an opt-in training input path that streams a split from pre-packed.tarshards instead of opening one file per image, together withpython -m rfdetr.cli.webdatasetto pack a COCO split into ~100 MB shards and a small JSON index. Shards are written with the standard library, so packing needs no extra dependency; reading them installs withpip install "rfdetr[data]". Image bytes are copied verbatim, and a decoded sample goes through the sameConvertCococonversion, the samemake_coco_transformsCPU pipeline (Albumentations included), the same collate function and the samepin_memoryhand-off to the Kornia GPU stage as the loose-file loaders — verified by comparing a packed split against the directory it came from, tensor by tensor, on 500 real COCO images: identical pixels, boxes, labels and label space, including when a shard decodes through PIL's draft mode, which now rescales annotations by the actual draft-vs-full-resolution ratio to match.coco,roboflowandyoloare unaffected. Because a streaming dataset has no index to sample from, the training loader gives every worker a fixed sample count floored to a whole number of accumulation windows (batch_size × grad_accum_steps) — the streaming counterpart of the paddingGradAccumAlignedDatasetgives the map-style loader — while validation, test and predict instead let every worker drain its shards once, so a split is scored exactly once and those loaders report no length; a packedtestsplit is used when present, falling back tovalwith a log line otherwise. Training refuses to start whenworld_size × num_workersexceeds the shard count, warns when an uneven shard split leaves the worst-served worker more than 5% short of the samples its epoch asks for, and now raises instead of continuing silently past 30% — a config that trained yesterday at that skew fails fast today — all measured from each shard's real sample count when the packer recorded them; the resolved plan (samples per worker × slots vs. total) is logged at INFO on every run, not only when a threshold is crossed. Each rank gets a fixed shard split assigned once at loader-build time rather than one that re-resolvesRANK/WORLD_SIZEper process, so eval assignment stays deterministic even when those env vars are absent or inconsistent across workers, and shard order plus an in-stream reservoir buffer are both reshuffled each epoch — reseeded from a per-worker epoch counter so apersistent_workers=Trueloader (the DataModule's own default whenevernum_workers > 0) reshuffles too instead of replaying its first epoch's order, a local shuffle rather than the global permutationshuffle=Truegives a map-style loader. Measured on a 32-vCPU instance with an NVMe-attached persistent disk, streaming COCO 2017 shards gave the same loader throughput as the loose files across six configurations (0.92x–1.03x; page cache cold and warm, 8 and 32 workers, default and Albumentations augmentation) and is not I/O-bound there, though construction is faster (median 19.9 s down to 0.012 s per DDP rank) because the annotation file is never parsed — packing should pay off where per-file access is genuinely the constraint (network filesystems, object-store mounts, millions of small files), which that disk was not. Accuracy is not established either way: over five seeds of a 3-epoch, 2,000-image fine-tune, the streaming median landed about 0.011mAP@50:95below the map-style loader at 39 shards and matched it at 290 (the shard-count skew above), with 2–3x the seed-to-seed spread in both cases; parity on a full-length run over a real dataset was not measured. Supports detection and segmentation splits — keypoint training rejects this format explicitly, since its label space is inferred from a whole parsed COCO annotation file that a shard index does not carry.num_classesauto-detects straight from the train shard index —max(category_id) + 1undercategory_ids="raw"(matchingdataset_file="coco"'s convention), the filteredcat2labelcount under"remap"— same asclass_names; shard paths resolve against the localdataset_dir, so streaming straight from object storage is not wired up here. (#1392) -
Added
TrainConfig.pad_targets_to, which pads every training image's targets to a fixed row count so the loss keeps one tensor shape across batches. XLA compiles per shape and the detection loss is shaped by the ground-truth box count, so a TPU run recompiles whenever a batch presents a new per-image count; as reported in issue #1433 on a v5litepod-4, a new count costs roughly 47 s and four fresh compilations while a repeated one runs in 0.18 s, and on data with a realistic spread the run never reaches steady state at all. Measured for this fix on a Cloud TPU v6e-1 (RFDETRNano, resolution 256, batch size 4, 15 steps): 78 uncached compiles and 1453.9 s unpadded versus 9 uncached compiles and a median 159.0 s padded. With padding the same data pays a bounded warm-up and then holds steady. The defaultNonekeeps the existing variable-length path, which is what CUDA wants. Settingpad_targets_toalso requiresaugmentation_backendto stay off Kornia/GPU (setup("fit")raisesValueErrorotherwise), and an image whose real box count exceedspad_targets_tohas its extra boxes dropped, logged as a warning. Padding is applied to the training dataloader only: the evaluation loaders keep their real targets, since padded rows would otherwise be counted as ground truth by COCO matching. It composes withpack_targets(#1399): padding runs first, so every sample the packer sees already shares one row count, and the packed batch it produces is bit-identical to packing the same padded targets directly. It is semantically transparent — the padded columns carry a query-independent cost so the Hungarian assignment on real targets is unchanged in both ofHungarianMatcher's paths (the batched compact path, and the full cartesian path a batch of one image or a mask/keypoint target always takes), the box losses are masked, a query matched to a filler target keeps its background weighting in the IoU-aware BCE branch, andclass_erroris reduced with the mask. The three classification branches whose padded pairs are not masked yet (position-supervised, varifocal, plain focal), the mask loss for segmentation models, and the keypoint loss all raise rather than reporting a quietly wrong loss. (#1058, #1433) -
Added
TrainConfig.eval_batch_size, decoupling the validation, test and predict dataloaders from the training micro-batch size. The three eval loaders previously always reused the resolvedbatch_size, so lowering it to fit an optimizer step also shrank evaluation batches. Evaluation runs underno_grad, which avoids autograd activation storage, but in-fit validation still shares device memory with the model and optimizer state and needs memory for its own forward outputs. The defaultNoneinheritsbatch_sizeexactly as before. Unlikebatch_sizeit accepts no"auto": an expliciteval_batch_sizeis never probed and stays usable on thebatch_size="auto"path, while leaving it unset keeps the existing "auto was never resolved" error for eval loaders too. The training dataloader, including itsgrad_accum_stepsalignment padding, is unaffected. -
deploy_to_roboflow()'sversionargument is now optional: when omitted, the highest existing dataset version of the target project is resolved automatically via the Roboflow API (falling back to version1for a project with no generated versions, where the Roboflow SDK then raises its usual "Version number 1 is not found."). Passing an explicitversionbehaves exactly as before, with no extra API call. (#1116) -
Added a live opt-in end-to-end CI job (
roboflow-deploy-e2e,-m e2e_roboflow) that generates a fresh dataset version in a dedicated Roboflow test project, deploys a real model withversionomitted, and independently polls the server-side trained-model status — catching silent server-side upload failures thatdeploy_to_roboflow()'s return value cannot surface. (#1116) -
Added live free/total GPU memory (
free_mem,torch.cuda.mem_get_info()in MB) next tomax_memin the training progress bar. Unlikemax_mem,free_memis not process-local and not a peak — it reflects the whole device, including other workloads sharing the GPU, at the instant it is read. It typically does not rise when this process frees a tensor while the caching allocator retains that block; explicit cache release or allocator reclamation can return it to the driver. It is closer to "room left for a new allocation beyond what every process already claimed" than to the full headroom this run has for a biggerbatch_size. Sametrainer.fit()-only scope asmax_mem. (#1314) -
Restored peak GPU memory (
max_memin MB) in the training progress bar, dropped during the PyTorch Lightning migration (PR #794) along withrfdetr.engine. Only coverstrainer.fit()(training and its periodic in-training validation) — PTL's own progress-bar classes never callget_metrics()outsidetrainer.state.fn == "fit", so a standaloneRFDETR.evaluate()progress bar shows no metrics at all, not justmax_mem, same as before this change. (#974) -
RFDETR.export(backbone_only=True)now exports the encoder and feature projector instead of calling the full detector and failing with anAttributeError. ONNX exports retain every configured feature-pyramid level and support dynamic batches. -
pack_targetscorrectness for segmentation targets (themasksfield) is now covered by a dedicated regression test through the realRFDETRDataModulecollate path, closing a parity gap #1399 shipped without. (#1399)
Changed¶
-
XLA validation, test, and the optional train-split (
compute_train_metrics=True) evaluation callbacks now materialize each model forward once before COCO metric code reads individual tensors on the host, avoiding repeated compilation of overlapping lazy-graph fragments. On a Cloud TPU v5e-1 (RFDETRNano, resolution 384, batch size 2, five training batches with train-split metrics disabled and two validation batches), median end-to-end fit time across five fresh-process pairs fell from 310.2 s to 232.0 s (-25.2%); validation time fell from 105.8 s to 28.1 s (-73.4%), while metrics, model tensors, and checkpoint tensors remained identical. The train-split callback shares the same barrier but was not separately benchmarked. (#1058) -
Multi-GPU keypoint training with
grad_accum_steps > 1now synchronizes gradients once per optimizer step instead of once per microbatch, avoiding redundant DDP reductions. -
The ONNX Runtime CPU inference session built by
RFDETR.export(format="onnx")'s inference helper no longer lets its intra-op thread pool busy-spin between calls. Spinning previously contended for CPU with any other work sharing the process — including this same helper's own torchvision-based preprocessing step — for as long as the session was alive.
Deprecated¶
Fixed¶
-
TPU/XLA training with EMA now keeps its control-flow counter on the host and queues parameter averaging inside the optimizer step, before Lightning's existing XLA step marker. This prevents the deleted-buffer failure seen after a few optimizer steps without adding another per-step synchronization; CPU and CUDA EMA updates are unchanged. (#1058)
-
Segmentation validation/test mAP no longer risks CUDA OOM in
_compute_mask_iou's boolean-to-float32 mask conversion, which previously materialized every matched prediction of a class at once (N x H x W, full image resolution by default) and every ground truth at once (M x H x W) — a densely annotated class can makeMcomparable toN, since GT count is bounded only by the image's own annotations, not byeval_max_dets. Both sides are now converted 32 rows at a time. For any nonzero prediction and ground-truth count, output is unchanged — bit-identical to the previous implementation; for a zero count on either side, the previous implementation raised an ambiguous-reshapeRuntimeErrorinstead of returning a value, and now returns an empty result. (#1460) -
WebDataset validation/test-only runs retain the training index's class names even when evaluation categories are a subset, for both raw and remapped labels.
-
WebDataset training keeps shard permutations consistent across ranks with real DataLoader workers, aligns accumulation at rank level, and sizes raw-label heads from all declared categories. Repacking is documented as offline-only; path and shard-helper doctests are portable and executable.
-
Distributed (DDP) training now preserves the minimum five optimizer steps per epoch for short datasets instead of losing the replacement sample count when Lightning injects its distributed sampler.
-
Installing the
[onnx]extra from a source checkout withuvon Python 3.10, 3.11 or 3.13 now brings inml-dtypesagain; theml-dtypes==0.5.1override, scoped to Python 3.12 for the TFLite stack, was dropping the requirement on every other interpreter and leftimport onnxfailing withModuleNotFoundError. -
Kornia
Affinenow applies scalartranslate_percentto both axes and reads scalarscaleas a fixed range, avoiding silent horizontal-translation loss and construction failures. Scalar translation emits a warning because Kornia samples signed offsets while Albumentations applies the scalar as a fixed positive offset. -
TFLite INT8 documentation and warnings now reflect that dynamic-range quantization needs no calibration data. (#1363)
-
RFDETR.export(format="tensorrt", fp16=True)now actually builds an FP16 engine on strongly typed TensorRT (11+) instead of silently falling back to FP32, by casting the ONNX graph to FP16 first (rfdetr[tensorrt]now also pullsonnxandonnxconverter-common). This graph cast raisesImportErrorif those two packages are missing — previously such a setup silently produced an FP32 engine reported as FP16. (#1453)
Breaking Changes¶
-
Removed
rfdetr.datasets.synthetic(generate_coco_dataset,generate_synthetic_sample,draw_synthetic_shape,calculate_boundary_overlap,DatasetSplitRatios,SYNTHETIC_SHAPES,SYNTHETIC_COLORS). The module only ever fed RF-DETR's own test fixtures and is replaced by thefuse-augmentationspackage, whosefuse_augmentations.datamodule generates the same shape datasets in COCO or YOLO layout for detection, segmentation, and OBB. Callers migrate topip install fuse-augmentationsplusfrom fuse_augmentations.data import generate_dataset; note that it writes dense COCO category ids where the removed generator wrote sparse ones, and its shape set addsrectangle. -
Renamed the optional installation extra from
webdatasettodata, without a compatibility alias. Usepip install "rfdetr[data]";dataset_file="webdataset"is unchanged. -
Restructured the export internals into one
Exporterclass per format, each built from its own configuration dataclass and reached through a registry that maps a format name to the module defining it.RFDETR.export()is unchanged — same signature, same accepted formats, same return value — but the modules behind it moved:rfdetr.export.main(includingmain()andmake_infer_image, nowrfdetr.export.prepare.make_infer_image) andrfdetr.export.protocols.ExporterProtocol(nowrfdetr.export.base.Exporter) are removed, the per-formatexport_onnx/export_openvino/export_coreml/export_executorch/export_tflitefunctions are replaced byOnnxExporter/OpenVINOExporter/CoreMLExporter/ExecuTorchExporter/TFLiteExporter,rfdetr.export._tensorrt.build_enginebecomesTensorRTExporter.build_engineinrfdetr.export._tensorrt.exporter, andrfdetr.export.benchmark.TRTInferencemoves torfdetr.export._tensorrt.inference. Every removed path exceptrfdetr.export.mainandrfdetr.export.protocolsalready carried a leading underscore and no stability guarantee. The format-independent graph preparation every format shared now runs once inrfdetr.export.prepare, and requesting a capability a format lacks —dynamic_batchon CoreML, ExecuTorch or OpenVINO — is refused from the registry's own data before that format's optional dependency is imported, rather than after paying for it. The contract each format implements, and the steps a new one takes, are documented in the new Exporter Blueprint page under Export Model in the docs. -
RFDETR.export(format="tensorrt", backbone_only=True, output_name=...)now writes{output_name}-backbone.trtinstead of{output_name}.trt, matching every other format and whatexport()'s own documentation already described. Without the marker a backbone engine silently overwrote a full-detector engine exported under the same name; scripts that rebuilt the engine path fromoutput_nameneed the suffix added.
[1.10.1] — 2026-09-07¶
Fixed¶
- Reduced peak CUDA memory in segmentation loss: matched boolean ground-truth masks are now sampled one image at a time on CUDA instead of concatenating a batch-wide float mask tensor. (#1437)
point_sample(mode="nearest")no longer falls back to a host op on MPS/XLA — routed through a backend-agnostic gather path instead ofF.grid_sample. CUDA/CPU are unaffected. Measured on a Cloud TPU v6e-1 withRFDETRSegNano:aten::grid_sampler_2dhost fallbacks went from 50 to 0 per 5-step fit. (#1432, issue #1058)SetCriterion.loss_masksno longer reads its normalizing denominator back to the host on every call —dice_loss/sigmoid_ce_lossnow acceptUnion[Tensor, float, int]andloss_maskspasses the Tensor straight through. Side effect:dice_loss_jit/sigmoid_ce_loss_jit— reachable only throughlwdetr.py's backward-compat re-exports, not part of the public API — now reject most NumPy scalar denominators (np.float64still works,np.float32/np.int64and similar now raiseRuntimeError); the eagerdice_loss/sigmoid_ce_lossfunctions are unaffected. (#1428, issue #1058)build_trainernow selectsXLAStrategyfor multi-device XLA/TPU training whenstrategy="auto"— previously this crashed atTrainerconstruction (DDPStrategybuilt before Lightning's XLA-first auto selection could apply). Also routes single-deviceaccelerator="auto"runs on an XLA-available host through Lightning'sXLAPrecisionplugin instead of a plainprecision=kwarg. Keypoint models are excluded from the strategy promotion. (#1427, issue #1058)- XLA-marked tests now pass on real TPU hardware. (#1426, issue #1058)
compile=Truenow takes effect on CUDA with the defaultmulti_scale=True, instead of logging a notice and training eagerly. (#1436; #1411 made compilation reachable in the first place)
[1.10.0] — 2026-09-04¶
Added¶
TrainConfig.pack_targets(defaultTrue) concatenates each batch's per-sample target dicts into one tensor per field before the DataLoader worker-to-main boundary, rebuilding them losslessly on the other side: a batch of 16 crosses as 9 objects, not 114, with bit-identical values. Loaders yieldPackedTargetswhen packing is lossless, else the original tuple of dicts. (#1399)TrainConfig.eval_batch_sizedecouples the validation/test/predict dataloaders from the trainingbatch_size. DefaultNoneinheritsbatch_size; unlikebatch_sizeit accepts no"auto". (#1378)TrainConfig.best_model_metric("map"or"mar", default"map") ranks checkpoints and early-stopping by mAR instead of mAP. (#1305)- Training progress bar restored/extended:
deploy_to_roboflow():- Experimental, undocumented XLA/TPU training path, not announced in the release notes and not exercised by any 1.10.0 benchmark:
build_trainer()routesaccelerator="xla"/"tpu"through anXLAPrecision("bf16-true")plugin, with a newxlaoptional extra (torch_xla==2.9.*, Linux only, py3.10-3.13). (#1257, #1256, #1254) - Kornia GPU augmentation backend gains seven ops:
ToGray,Blur,Sharpen,Equalize,CLAHE,Perspective,ShiftScaleRotate. Params Kornia cannot express are warned about, not silently dropped;HueSaturationValueremains unsupported. (#1249, #1277, #1330, #1370) - GPU batched linear-assignment solver (
rfdetr.models._assignment) wrapstorch_linear_assignment(Triton-backed), folding every decoder layer's assignment problem into one solve. SciPy'slinear_sum_assignmentremains the CPU/fallback path, and wherever the Triton backend cannot run (non-Linux, compute capability < 8.0, old torch) it falls back internally to that same SciPy solve. New[train]-extra dependencytorch-hungarian, pinned to the0.1.0rc0pre-release on PyPI pending a stable0.1.0, imported lazily so inference-only installs are unaffected. (#1368)
Changed¶
-
Detection and segmentation COCO evaluation now runs on hotcoco by default — a Rust COCO evaluator under MIT with
numpyas its only runtime dependency, added to thetrainextra. Reported metrics do not change: the parity tests compare every aggregate, per-class and class-ID output of both backends for box-only and box-plus-mask evaluation and require exact equality, which they reach. SetTrainConfig.eval_backend="faster_coco_eval"to restore the previous evaluator, which remains installed and is still required — torchmetrics resolves its COCO helpers from a closed backend-name enum with no hotcoco member, so the adapter constructs it with the supported name and replaces the resolved modules. What changes is the cost ofcompute(), not the validation forward pass that usually dominates a validation epoch: on synthetic COCO-val-shaped state (5,000 images, 36.6k ground-truth boxes, 300 detections per image, 80 classes,eval_max_dets=500) one macOS-CPUcompute()took 6.2 s before and 1.1 s after, measured againsthotcoco1.0.0. Most of that is not the evaluator: for box-only evaluation the prediction dataset is now handed to the backend as one detection array instead of the million-plus annotation dictionaries TorchMetrics materializes, which on that state builds in 0.4 s where the dictionary path the other backend still takes costs 1.8 s. Segmentation, thefaster_coco_evalbackend, and states without stored boxes keep the dictionary path. This is a single-machine CPU measurement on generated detections, not a trained-model or multi-hardware figure. One hotcoco behavior is a silent wrong answer rather than an error and is handled in the adapter, with a test that fails if the handling is dropped: itsdatasetgetter returns a copy, so field-level mutation is discarded — which would leak one IoU type's annotation areas into the other's COCO size buckets, doublingbbox_map_smallin the shipped regression fixture. Installing hotcoco also puts a generically-namedcococonsole script onPATH. -
RFDETR.predict()performance work, none of it changing detections: every entry measured byte-identical or checksum-identical against the previous path.- Skips the recursive
eval()reassignment when the module tree is already in eval mode, saving ~0.4-0.5 ms/call on RTX 4060/L4 in the common repeated-inference case. (#1419) - Transfers PIL/uint8 NumPy inputs to device in their original byte storage and widens to float on-device, not on host, cutting host-to-device transfer size 4x. (#1415)
- Converts PIL/uint8 NumPy inputs to contiguous CHW float storage in one fused allocation, not a separate dtype/layout pass. (#1390)
include_source_image=Trueconverts CUDA float images touint8source bytes on-device before the host transfer, not on CPU. CPU tensors and unsupported CUDA dtypes (e.g.bfloat16) keep the previous path. (#1388)- Skips the deferred
[0, 1]pixel-range scan (from #1341) for PIL/uint8 NumPy inputs, sinceto_tensoralready guarantees that range for them; tensor and non-uint8 NumPy inputs are unaffected. (#1387)
- Skips the recursive
-
Single-feature-level fast paths reuse tensors instead of re-materializing them (current Nano/Small/Medium/Large models; legacy
RFDETRLargeDeprecatedConfigunaffected where noted); outputs bit-identical:- Eager forward pass skips rebuilding the sine position embedding, padding masks, and padded batch tensor when a batch carries no padding, tracked via
NestedTensor.no_padding; position embeddings are served from a small cache in eval mode. Batches with real padding are unaffected. (#1416) - Deformable attention reuses its sampled tensor directly for single-level inputs instead of stack+flatten over a one-element list, mainly benefiting keypoint cross-attention. (#1385)
Transformer.forwardreuses flattened tensors instead oftorch.catover a one-element list. (#1377)- Decoder's grouped self-attention reuses the regrouped query tensor as the key, not materializing the same grouping twice. (#1371)
- Eager forward pass skips rebuilding the sine position embedding, padding masks, and padded batch tensor when a batch carries no padding, tracked via
-
Evaluation:
- New
TrainConfig.eval_base_model(defaultFalse) restores base+EMA validation comparison when only one model is evaluated (see Breaking Changes).TrainConfig.eval_ema_onlyis deprecated, removal in v1.13. (#1380) - COCO mAP computation consolidated into a new
rfdetr.training.coco_map.OnePassCocoMeanAveragePrecisionadapter: base and EMA share one evaluation pass, and each image's detection scores convert once, not once per detection. Narrows thetorchmetrics[detection]pin to>=1.8.2,<1.9.0, which validates a TorchMetrics-internal contract this adapter relies on. (#1375, #1379) - Shares bbox IoU per image with a unified tie-break contract, plus C=1/no-crowd fast paths. (#1373)
- mAP metric state kept on CPU, restricted to consumed metrics only; the train hot path is gated on eval epochs. (#1356)
- Detection validation converts each batch's ground-truth targets once and shares the result between base and EMA mAP accumulators. Segmentation still converts twice, because per-head mask grids can differ. (#1381)
- New
-
Segmentation postprocessing, both bit-identical to the previous output:
- Reads each image's mask resize target once per batch, not per image, cutting CUDA syncs; same fix applied to
COCOEvalCallback._convert_targets. (#1369) - Writes thresholded interpolation chunks directly into a preallocated buffer instead of
torch.cat-ing a list. Small CUDA selections keep the prior path, for lower peak memory at shippednum_select=100defaults. (#1374)
- Reads each image's mask resize target once per batch, not per image, cutting CUDA syncs; same fix applied to
-
SetCriterion.loss_maskssamples matched ground-truth mask labels via direct tensor indexing instead ofpoint_sample, under size/contiguity/dtype guards; CUDA keeps the previous path. Measured 6.7-7.1x faster on a single-thread CPU microbenchmark of the fullloss_maskscall, labels bit-identical either way. (#1367) -
HungarianMatcherbatches host transfers instead of issuing them per problem. (#1361) -
Oversized JPEGs, including 1080p sources, are draft-decoded while preserving draft geometry. (#1389)
-
Torch-free NumPy export kernels: bilinear resize made separable, top-k selection partitioned. (#1394, #1393)
-
Kornia
GaussianBlur.sigmadefault changed(0.1, 2.0)→(0.5, 3.0)andGaussNoise.std_rangedefault changed(0.01, 0.05)→(0.2, 0.44), 4-9x stronger, matching Albumentations' defaults. Silently changes augmentation strength for any config that omits these params on the Kornia/GPU backend (e.g.AUG_INDUSTRIALreaches the blur default); pin explicit values if you rely on the old strength. (#1395) -
Training skips PyTorch Lightning's pre-training sanity validation batches by default;
num_sanity_val_stepsrestores it. Per-microbatch training-loss metrics are compacted, 17 → 9 keys on defaultRFDETRSmall, andcompact_train_metrics=Falserestores per-layer keys. LR metrics emit only on optimizer updates, not every microbatch: a no-op at the newgrad_accum_steps=1default, but ~75% fewer log calls atgrad_accum_steps=4, the 1.9.x default. (#1360)
Deprecated¶
rfdetr.datasets.aug_configcompatibility shim now has a concrete removal target: deprecated since 1.9.0, removal in v1.12.0. Userfdetr.datasets.aug_configs(plural) instead; constants unchanged. (#1103, #1037)TrainConfig.eval_ema_onlyis deprecated, removal in v1.13, superseded byeval_base_model. LegacyTrue/Falsestill migrate to the equivalenteval_base_modelvalue with aFutureWarning; it still requiresuse_ema=Trueand conflicts witheval_base_model=True. (#1380)
Fixed¶
- Packed targets materialize directly into per-sample device tensors instead of clone-after-move, removing a transient CUDA allocation equal to the mask field's size. (#1405)
- Empty COCO targets keep
iscrowd/areadtypes matching populated targets, enabling lossless packed-target transport for mixed empty/populated batches. (#1404) - Fixed
compile=Trueaborting training on supported PyTorch versions, including 2.2.spatial_shapesis now built from Python ints under compilation instead oftorch._shape_as_tensor, which Dynamo could not trace. Eager,torch.jit.trace, and the ONNX/TensorRT export path (#1155) are unaffected. (#1411) - Kornia
CLAHEreads a scalarclip_limitas a range, matching Albumentations, and rejects the same sequences Albumentations rejects. (#1350) - Corrupt COCO zip downloads are retried, size validated against
Content-Length, up to 3 attempts with linear backoff, instead of failing the dataset build outright. (#1306)
Breaking Changes¶
TrainConfig.grad_accum_stepsnow defaults to1(was4), changing the default effective batch size from 16 to 4 — a training-semantics change, not just throughput. Setgrad_accum_steps=4explicitly to restore prior behavior.batch_size="auto"runs are unaffected, since the auto-batch probe overwritesgrad_accum_steps. Measured 27% faster/epoch on one L4 (batch_size=16, grad_accum_steps=1vs. the old4/4), mAP equal within noise. (#1378)- Validation now evaluates one model per epoch, EMA when
use_ema=True(the default) and base otherwise, instead of both, removing a full validation pass worth ~5% epoch time in one measured L4 run. Metric keys move:val/mAP_*,val/mAR, per-classval/AP/<class>, andval/lossreport whichever model was evaluated, the EMA model by default, instead of always the base model — changing what aReduceLROnPlateauscheduler,ModelCheckpoint(monitor=...), or early stopping watching those keys tracks.val/ema_*remains available for explicit EMA consumers.checkpoint_best_regular.pthis no longer written when the base model is not evaluated. SetTrainConfig.eval_base_model=Trueto restore the previous base+EMA comparison;use_ema=Falseruns are unaffected. (#1380) - Optimizer parameter groups are now one per distinct learning-rate/weight-decay combination instead of one per parameter (
rfdetr-nano: 465 → 28 groups), letting fused/foreach AdamW batch properly. AdamW steps are bit-identical and old checkpoints auto-regroup on load, but an explicitlr_scheduler_kwargslist sized to the old per-parameter group count, e.g.LambdaLR's per-grouplr_lambda, must be resized to the new group count. (#1409) - Dataset builders (
build_roboflow_from_coco,build_roboflow_from_yolo,build_o365_raw) now require seven image-pipeline options (square_resize_div_64,segmentation_head,multi_scale,expanded_scales,do_random_resize_via_padding,patch_size,num_windows;build_o365_rawtakes nosegmentation_head) instead of silently substituting contradictory defaults when called with an incomplete config namespace, which could previously train with multi-scale off and the wrong crop scales without warning. Callers passing a completeTrainConfig/ModelConfigare unaffected; callers assembling a partial namespace by hand must supply every field. (#1413) TrainConfig.log_per_class_metricsnow defaultsFalse(wasTrue), so per-class AP keys are no longer emitted by default.TrainConfig.compute_val_lossnow defaults"auto"(wasTrue), soval/lossis computed only when a scheduler/callback consumes it. Set either explicitly to restore the prior unconditional behavior. (#1372)
[1.9.4] — 2026-08-24¶
Fixed¶
- ONNX and TFLite reference inference helpers accept an explicit
background_class_id:-1preserves the existing final-background default,Noneretains every exported logit slot for sparse-ID COCO checkpoints, and0supports legacy background-first keypoint checkpoints. (#1397) - Fixed the TFLite reference inference helper assuming a lone rank-4 output is a segmentation mask. ONNX output names rarely survive the conversion — RF-DETR's own TFLite files arrive as
StatefulPartitionedCall:N— so a keypoint export'spred_keypointstensor was indistinguishable from a mask by name and was silently upsampled intoDetections.mask.rank4_outputnow defaults toNone, decoding only named masks; pass"masks"explicitly for a name-stripped segmentation export. (#1397) - Fixed the torchvision-native non-square training pipeline resampling crop-branch outputs twice.
_build_train_resize_transforms(square=False)resizes each crop directly to a randomly selected target scale, matching the square and Albumentations paths. This changes the augmented pixel distribution for non-square training by avoiding the fixed384x384intermediate and its extra resampling step. Square training, the released default for every shipped model config, is untouched, as are validation, prediction, and export preprocessing. (#1383) - Fixed custom Albumentations configs treating
TimeReverseas a pixel-only transform, which flipped images while leaving boxes and keypoints unchanged.TimeReversenow shares the geometric-transform and replay-based keypoint handling used byHorizontalFlip. The keypoint safety filter disables bothTimeReverseandSquareSymmetrywhenkeypoint_flip_pairs=[]; detection-only pipelines (keypoint_flip_pairs=None) retain them, and configured pairs enable their keypoint-slot swapping.SquareSymmetryalready had geometric and replay handling as the alias ofD4; this fix extends the no-pairs safety filter to it. The default torchvision pipeline is unchanged, as are configs already using the canonicalHorizontalFlip/D4names. - Fixed TFLite export failing when
onnx2tfcould not resolve the installedonnxsimconsole script from a non-activated virtual environment.onnx2tfinvokes the bareonnxsimname; when that lookup raisesFileNotFoundErrorit logsFailed to optimize the onnx file, a warning that also appears in working runs, and a stockRFDETRSmall()export then failed withRuntimeError: onnx2tf conversion failed: Output tensors of a Functional model must be the output of a TensorFlow Layer. RF-DETR now temporarily adds the running interpreter's script directory toPATHduring conversion. (#1365) - Fixed the default torchvision-native training pipeline silently corrupting keypoint annotations when
keypoint_flip_pairsis empty on a schema with genuine left/right pairs.RandomHorizontalFlipon this backend always mirrored keypoint x-coordinates when a flip was drawn, but relabeled left/right joints onlyif self.keypoint_flip_pairs:— with an empty list, the pydantic default and one possible outcome when automatic flip-pair inference from dataset metadata misses an asymmetric schema, affected training samples got their keypoints mirrored in position while keeping their original left/right label, with no warning._build_torchvision_pipelinenow drops the flip entirely for an empty-but-not-Nonekeypoint_flip_pairs, logging the warning the Albumentations backend already emits viafilter_keypoint_hflip_augmentations, worded for this backend's lack of an editableaug_config, matching the annotation-safety behavior that backend has had since #1122. An empty list can also legitimately mean the schema has no left/right pairs at all, e.g. a single midline keypoint; the unpatched flip was harmless there since nothing needed relabeling, but this fix disables it there too, for consistency with the Albumentations backend's contract, at the cost of a now-unavailable-by-default augmentation for that narrower case. Detection-only pipelines (keypoint_flip_pairs=None) and keypoint pipelines with real pairs are unaffected. - Fixed
BestModelCallbacktreating PyTorch Lightning's pre-training sanity-check validation pass as a real epoch's result. Its EMA-checkpoint tracking and thesmooth_alphasmoothing accumulator are custom bookkeeping sitting outsideModelCheckpoint's owntrainer.sanity_checkingguard, which the regular-checkpoint path already inherits, so a positive sanity-check score — common when starting a new run initialized withpretrain_weightsfrom a checkpoint pretrained on a different dataset — could be written out as the permanent "best"checkpoint_best_ema.pthbefore a single real epoch ran, and real training could then never surpass it. This is distinct from PTL's ownresume/ckpt_pathrestart, which PTL itself skips the sanity check for (not val_loop.restarting). (#1357, fixes #1348)
[1.9.3] — 2026-08-17¶
Changed¶
HungarianMatcher's compact-path safety gate computes its target-side half, the box/label finiteness checks, once per training step rather than once permatcher()call.SetCriterion.forwardinvokesmatcher()separately for the final layer, each auxiliary decoder layer, and the encoder layer with the sametargets, so the target-side precheck is precomputed once and reused across all of them, keyed ontargetsobject identity pluspred_boxesdtype/device andnum_classes; a mismatch triggers a fresh computation. Matching results are unchanged. Callers must not mutatetargetsin place between precompute and reuse — the identity check cannot detect that. (#1340)- Per-class confidence-threshold sweeps in evaluation are O(N log N), not O(T·N): one stable ascending sort per class plus
np.searchsortedinto precomputed suffix sums replaces a full rescan per threshold. NaN scores are explicitly masked so they never count as "above threshold". Results are unchanged. (#1339) RFDETR.predict()no longer blocks the host on a per-image CUDA sync for its[0, 1]pixel-range validation. The range-check tensors are collected unsynced across all images and resolved to Python booleans once, after every image's conversion, range check, and transfer have been queued, so later images' GPU work can overlap the sync. Error-message precedence per image is unchanged. A malformed-rank input combined withinclude_source_image=Truenow raises a publicValueErrorwith a shape message, where it previously surfaced an internalRuntimeErrorfrompermute(). (#1341)Transformer.forward's two-stage query selection gathers thetorch.topk-selected rows before running the bbox-delta MLP (enc_out_bbox_embed), not after: the MLP is pointwise with no cross-token mixing, so it needs at most thenum_queriesrows that survive selection, not every one of thesum(H*W)encoder positions. (#1334)PostProcessbox/mask/keypoint selection is deterministically tie-broken:torch.argsort(..., stable=True)plus a slice replacestorch.topk, so ties resolve by descending score then ascending flattened query/class index — the rule now shared with the torch-free export decoders, both sides changed together in this PR. Output ordering may differ from 1.9.2 when scores tie (same detections, different order;detections[0]may change), but ordering among equal scores was never contractual.PostProcess(num_select=<negative>)now raisesValueErrorat construction instead of being silently accepted. (#1320)
Fixed¶
- Fixed
evaluate(split="test")on YOLO-format datasets silently evaluatingvalid/instead of the realtest/split. When no resolvabletestsplit exists, evaluation falls back tovalid/with a logged warning rather than failing; a newYoloSplitUnavailableError, aFileNotFoundErrorsubclass, drives that fallback and is catchable by callers. If atestpath is declared indata.yamlbut unresolvable, or the images directory exists but is empty, or the labels directory is missing, evaluation raises instead of silently relabeling the split as validation. COCO-format Roboflow exports have no such fallback and still raiseFileNotFoundError; COCO and Objects365 datasets never attempt atestsplit. (#1329, #1343) - Fixed
metrics.csvtraining history being wiped by a resumed run.build_trainer()reconstructs a freshCSVLogger(version="")on every start, and PyTorch Lightning's_ExperimentWriterdeletes any pre-existingmetrics.csvthe first time.experimentis accessed, removing every pre-resume row. The file is now snapshotted before that access and restored after, with the writer's column cache seeded so the nextsave()appends instead of overwriting. This is gated onresumebeing set, so reusing anoutput_dirfor a fresh, non-resumed run still resets the file instead of appending onto an unrelated run's history. (#1325, closes #1321) - Fixed
SegmentationHead'sskip_blocksbranch skipping the learnedspatial_features_proj1×1 convolution; it is now applied before computing mask logits, matching the non-skip branch. This affects the encoder-branch aux mask supervision during training only (sparse_forward,skip_blocks=True); the export path (forward_export) already applied the projection unconditionally, and the main decoder path was already projected, sopredict()outputs and exported models are unchanged. Custom deployment decoders consumingsparse_forward'sspatial_featuresdict entry must not re-apply the projection themselves, since it is now applied upstream. (#1331) - Fixed non-finite keypoint predictions poisoning the shared box head's gradients, in both the decoder and encoder branches.
compute_l1_keypoint_lossalready guarded its own inputs, but could not zero the local backward pass of a multiply feedingref_wh, shared with the box head, letting a NaN delta propagate through0.0 * nan == nan; deltas are now sanitized at the source withtorch.nan_to_num(..., 0.0)before the reference is composed. The keypoint loss also masks out non-finite predicted keypoints and non-finite target areas rather than letting them poison the loss. Not yet covered: the matcher's own keypoint cost (compute_keypoint_matching_cost) still lacks the equivalent guard. (#1336) - Fixed
batch_size="auto"probing ignoring AdamW's optimizer-state memory (exp_avg/exp_avg_sq); it now accounts for it via a shadow optimizer, where previously the probed batch size overshot what real training could fit, causing an out-of-memory error on the first optimizer step. A warning is logged when a non-AdamW optimizer is configured, since the estimate no longer directly applies. The search loop starts fromcandidate=2/lower_ok=1, not1/0. (#1342) - Fixed the ONNX Runtime export benchmark ignoring the requested
device: the inference session is built withproviders=[("CUDAExecutionProvider", {"device_id": device})]instead of the bare provider name, which previously always bound to GPU 0 regardless of--device N. (#1346) - Fixed training metric plots drawing a legend only on the subplot titled "Loss"; every subplot now gets one. (#1335)
- Fixed the ONNX and TFLite reference decoders taking a per-query
argmax, which silently dropped legitimate detections whenever a query scored above threshold on more than one class; both now mirrorPostProcess's multi-label selection. Both paths flatten(Q, C)scores intoQ·Cquery/class pairs and take the top-scoring pairs before thresholding, via a shared_select_topk_multiclasshelper using the same deterministic tie rule asPostProcess. The selection cap defaults to the exported model's query count; custom exports can pass an explicit value. Empty, zero, negative, and NaN inputs are handled correctly during debug logging. (#1320) - Fixed EMA training performing an extra averaged-model update at epoch boundaries after the final optimizer step, which let one update per epoch bypass
ema_update_intervaland change the EMA trajectory. (#1319) - Fixed
model.export(format="tflite")hanging forever at the ONNX → TFLite conversion step.onnx's C extension and TensorFlow both statically link Abseil and export its symbols as weak definitions, which the dynamic loader coalesces onto whichever library loads first. The TFLite route runs a full ONNX export before reachingonnx2tf, so ONNX won that race and supplied Abseil's synchronization primitives to TensorFlow, whose executor then blocked forever inabsl::Notification::WaitForNotification()while restoring the SavedModel bundle: no traceback, no error, 0% CPU, no.tflite. TensorFlow is now imported before the ONNX export (rfdetr.export._backend.preload_tensorflow_before_onnx), and a warning is logged when the calling process had already importedonnxbefore TensorFlow, e.g. a directexport_tflite()call, since that order cannot be repaired in-process. Importingonnxafter TensorFlow is safe and does not warn. (#1322, #1323)
Breaking Changes¶
- Exported artifact filenames encode precision or backend for variant-derived/default names: TFLite
{stem}_float32.tflite/{stem}_float16.tflite→{stem}_fp32.tflite/{stem}_fp16.tflite; ExecuTorch{variant}.pte→{variant}_{backend}.pte(or{variant}_qnn_{soc}.pte); CoreML{variant}.mlpackage→{variant}_fp32.mlpackage/{variant}_fp16.mlpackage; TensorRT{stem}.trt→{stem}_fp16.trt/{stem}_fp32.trt. ONNX filenames are unchanged. Update scripts that hardcode or glob these artifact filenames; explicitoutput_nameoverrides are unchanged.
[1.9.2] — 2026-08-11¶
Changed¶
HungarianMatcher's detection-only cost matrix is built padded to each batch'smax(T_i)target count and diagonal-extracted, not padded to the cross-imagesum(T_i), whenever the batch's targets and predictions pass a fast eligibility check; ineligible batches fall back to the previous full-cartesian computation with identical results. The matcher runs inside the training-step criterion undertorch.no_grad(), so this is a training-time, not inference-time, saving: on real COCO batches matcher time drops ~51% and peak CUDA memory ~73-76%, and the measured end-to-end training step goes from 288.364 ms to 232.457 ms on an A100. The saving scales with target-count evennessr = sum(T_i) / max(T_i), capped at the batch size, with a1 - 1/rceiling, so a batch where one image holds nearly all the targets (rclose to 1) sees little to no improvement. The compact path also copies only the diagonal cost blocks to CPU before assignment instead of the full-size matrix, and its safety gate batches its box/label finiteness sweeps into one synchronization, not one per image. (#1297, #1281, #1312)seed_all()escalates totorch.use_deterministic_algorithms(True, warn_only=True)after setting the cuDNN flags, so every op with a deterministic kernel uses it; ops without one, some scatter /grid_sampleCUDA kernels, warn at execution time instead of raising, and a failure to enable determinism is caught and logged rather than propagating out ofseed_all. This is user-visible as new runtime warnings and a possible slight performance cost. (#1307)RFDETR.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 the host, not the device. (#1276)
- Keypoint decode skips redundant CUDA presence checks in postprocessing. (#1282)
Fixed¶
- Fixed loading a detection checkpoint published before keypoint support warning that
_kp_active_maskis a "model parameter not in checkpoint (left at random init)". The key is a deterministic schema buffer the model always rebuilds from the configured keypoint schema, empty for detection-only variants, not a learned parameter, so its absence never affected the loaded weights. AffectsNano,Small,Large(2026) andSegSmall. The filter matches the exact terminal key, so a similarly-named real parameter still warns, and an unexpected_kp_active_maskin a checkpoint still warns; the filtered key is recorded at debug level. (#1302) - Fixed resuming training from one of
BestModelCallback's four lightweight checkpoints (checkpoint_best_regular.pth,checkpoint_best_ema.pth,checkpoint_best_total.pth,last_ema.pth) silently restarting per-callback state cold; it now restores. Those files intentionally omit optimizer/LR-scheduler state, and a warning says so explicitly, distinguishing them from checkpoints that predate callback-state persistence entirely, where best-score tracking, EMA, and early-stopping all restart cold too. Best-score restore additionally requires the originaloutput_dirto match. (#1318) - Fixed training-time log calls corrupting or duplicating the completed Rich epoch progress bar when
RichProgressBar(leave=True)is active. A new stream handler tracks the log target by name and re-resolvesstdout/stderron every emit, following Rich's redirect proxies instead of capturing the pre-redirect stream once at import time. (#1316) - Fixed an index-less
torch.device("cuda")never matching an indexed device likecuda:0in the deferred-move guard, which re-moved every parameter on every call; it is now normalised to the current device index before the comparison. (#1311) - Fixed the legacy query-embedding fallback warning on every load; it now warns only when it actually truncates weights. (#1301)
- Fixed
eval_ema_onlyruns logging no validation output at all when the base metric was empty. EMA metrics are now computed and logged in that case (val/ema_mAP_50_95,val/ema_mAP_50,val/ema_mAR, per-class AP, and aval (ema)summary table), andval/F1is no longer silently dropped. Theeval_ema_onlycontract is now:val/mAP_50_95stays unpopulated, so pointmonitor_emaatval/ema_mAP_50_95— a prior comment claiming otherwise has been corrected. (#1289) - Fixed
ModelContext.reinitialize_detection_head()raisingAttributeError: 'NoneType'afterRFDETR.inference(inplace=True)cleared the weights; it now raises a clearRuntimeError, and does so beforeargs.num_classesis mutated so a rejected call cannot leave the context half-updated. (#1283) - Fixed
evaluate()not building its datamodule from the resolution-override config. (#1280)
Breaking Changes¶
- COCO datasets containing an unannotated grouping category no longer spend a model output slot on it. Roboflow COCO exports prepend a synthetic root category (id
0,supercategory: "none", named after the project) that every real class then lists as its ownsupercategory; it carries no annotations, but previously took label index0and an extra class channel.CocoDetection.cat2label, the auto-detectednum_classesandRFDETR._load_classes()now share one filter (rfdetr.datasets.coco.filter_parent_categories), so training such a dataset builds an N-class head instead of N+1 and every real class shifts down one label index. A parent category that owns annotations keeps its slot, and flat datasets are unaffected. Checkpoints trained before this change keep their N+1-class head — evaluating one against the same dataset now misaligns per-class metrics, firing the existing class-countUserWarning; retrain. Passingnum_classesexplicitly preserves the checkpoint's N+1-class head width so the weights still load, but does not restore the old label indices:CocoDetectiondrops the grouping category wheneverremap_category_ids=True, so every real class still shifts down one slot and the pretrained head is misaligned against the new labels. The keypoint remapping path (_build_keypoint_cat2label) is unchanged, so keypoint datasets still include the grouping category. For hierarchical datasets, thetrain/valid/testsplits now share one label mapping, always derived from thetrainsplit, so a grouping category annotated in only some splits no longer shifts that split's label indices out from under the others. (#1303)
[1.9.1] — 2026-08-03¶
Changed¶
PostProcessselects boxes, masks, and keypoints withindex_select/expandinstead of materialising a repeatedint64gather index, an allocation reaching 21–84 MiB per image for the segmentation mask head. Mask post-processing at head resolution is 2.6–3.0× faster; the output is bit-for-bit identical. (#1268)RFDETR.predict()no longer upsamples segmentation masks whose scores fall below the caller's threshold before discarding them; on typical COCO images only a few of thenum_selectmasks survivethreshold=0.5. End-to-endpredict()is ~20% faster at 1080p, the saving scaling with image area and neutral at 640 px; the output is unchanged. (#1265)- ExecuTorch export lowers the
addmmoperations the XNNPACK partitioner leaves undelegated back intoaten.linearviaAddmmToLinearTransform, which runs ~100× faster for those shapes. RFDETRNano on XNNPACK / Apple silicon is ~2.5× faster (119.9 → 48.3 ms median); outputs match the previous lowering to ~1e-4. (#1262)
Fixed¶
- Fixed
keypoint_flip_pairssilently disabling horizontal-flip augmentations (HorizontalFlip,Flip,D4) on detection-only datasets when a customaug_configis supplied.AlbumentationsWrapper.from_configtreats an emptykeypoint_flip_pairsas "keypoint pipeline with no flip pairs defined" and drops flip transforms for annotation safety; detection pipelines must passNoneinstead of[]to keep flips enabled. (#1248) - Fixed export inference and INT8 calibration resizing through PIL's antialiased BILINEAR/BICUBIC filters, which diverge from
predict()on downscale and shift exported-model confidence scores and INT8 calibration ranges. The ONNX inference, TFLite inference, INT8 TFLite calibration, and benchmark/traced-example paths now resize withRFDETR.predict()'s exact convention: bilinear, half-pixel centers,antialias=False. A shared torch-free_bilinear_resize_half_pixelNumPy kernel (rfdetr/export/_resize.py) mirrors the convention wherever torchvision is unavailable. Re-export any INT8 TFLite model to recalibrate against the corrected pixel distribution. (#1269) - Fixed
pip install 'rfdetr[onnx]'on Python 3.10 andpip install 'rfdetr[executorch]'on Python 3.14 failing during install. Each extra previously resolved to a version (onnxruntime,executorch) shipping no wheel for that interpreter and with no source distribution to fall back on; the extras are now gated to interpreters that publish wheels. (#1267) - Fixed the Kornia augmentation builders (
GaussianBlur,GaussNoise) rejecting scalars for range parameters; they now accept either a scalar or a(min, max)pair, matching the Albumentations path. A customaug_configvalid under Albumentations no longer raises a bareTypeErrorwhenaugmentation_backend="cpu"/"auto"resolves to Kornia, i.e. Kornia installed and CUDA available. (#1255) - Fixed
uv syncfailing to create.venv; anexecutorch/tfliteextra conflict previously blocked resolution of the development environment. (#1253)
Documentation¶
- Corrected RF-DETR Keypoint Preview's parameter count (126.4 M → 40.7 M), added deployment parameter-count columns to the keypoint benchmark tables, and clarified that the new SAM 3 RF100-VL result is author-reported rather than measured in SAB. (#1258, #1261)
- Documented ONNX Runtime raw-output decoding and expanded the LLM keypoint task/model/benchmark/API reference. (#1251, #1260)
[1.9.0] — 2026-07-27¶
- Default dataset augmentations use torchvision-native transforms unless Albumentations is installed, in which case
augmentation_backend="auto"/"cpu", the default, auto-selects Albumentations instead — identical user code can therefore resolve to a different resize backend, and slightly different pixel values / mAP, purely based on whetherrfdetr[augment]is installed. Passaugmentation_backend="torchvision"to pin torchvision regardless of what is installed. Non-empty customaug_configdictionaries use the optional Albumentations integration and Kornia GPU backend, both viapip install 'rfdetr[augment]'. The[train]extra no longer installs Albumentations or Kornia. See the migration guide's "Upgrade 1.8 → 1.9" section for remediation steps. (#1112)
Added¶
- Native CoreML export:
format="coreml"onRFDETR.export()produces a.mlpackage(mlprogram, iOS 16+) directly fromtorch.export, with no ONNX intermediary — distinct from ExecuTorch'sformat="executorch", backend="coreml".ptepath. Install withpip install 'rfdetr[coreml]'(macOS only;coremltools>=8.0,<10.0). (#1235) - Multi-GPU / multi-node keypoint (pose) training under
DistributedDataParallel. Keypoint models (RFDETRKeypointPreview) previously raisedNotImplementedErrorfor any distributed strategy,num_nodes > 1, ordevices > 1; they now train withstrategy="ddp"/strategy="auto"on multiple GPUs and nodes, launched withtorchrunexactly like detection models. Because keypoint models use manual optimization, gradients synchronize on every microbatch — keepgrad_accum_steps=1on multi-GPU for best throughput (grad_accum_steps > 1is correct but performs redundant all-reduces). Sharded strategies (FSDP / DeepSpeed) remain unsupported for keypoint models and raise a clear error. See the "Keypoint / Pose models" note indocs/learn/train/advanced.md. (#1232) scale_jitter: bool = TrueonTrainConfig— independent control for the resize → crop → resize branch (Option B) in the training resize pipeline. Disabling this branch previously required passingaug_config={}, which also disabled the entire Albumentations augmentation stack;aug_confignow controls only that stack. Setscale_jitter=Falseto use direct resize only, with annotations near image borders never clipped.AugmentationBackend.TV(augmentation_backend="torchvision") — forces the torchvision-native default pipeline. Unlike"cpu"/"auto", which auto-select the best installed backend (Albumentations > Kornia > torchvision) and can therefore resolve differently across environments,"torchvision"always resolves to torchvision regardless of what optional packages are installed.AugmentationBackendnow holds only concrete, directly-usable backends (TV,ALBU,KORNIA);"cpu"/"auto"remain acceptedaugmentation_backendinput strings, resolved lazily at dataset-build time to keep saved configs portable across environments, but are no longer enum members.AugmentationBackend.TV/.ALBUvalues changed from"tv"/"albu"to"torchvision"/"albumentations"; the old"tv"/"albu"/"gpu"strings are still accepted as legacy input aliases.TrainConfig.optimizer(str | Callable) andoptimizer_kwargs— configurable training optimizer.optimizer="adamw", the default, keeps RF-DETR's built-in fusedtorch.optim.AdamWpath unchanged. A bare short name selects a nativetorch.optimoptimizer only (e.g."sgd","adam"); any other optimizer, including third-party ones such aspytorch-optimizer(install separately), is selected by a full dotted import path ("pytorch_optimizer.Lion") or a callable /functools.partialcalled with the RF-DETR parameter groups.optimizer_kwargsforwards constructor arguments, ignored for callables, which bake their own arguments in. (#1006)TrainConfig.lr_scheduler(str | Callable) pluslr_scheduler_kwargs,lr_scheduler_interval, andlr_scheduler_monitor— configurable LR scheduler, mirroringoptimizer.lr_scheduler="step"/"cosine", the managed presets, keep RF-DETR's built-in warmup-aware schedules unchanged; any other scheduler is selected by a full dotted import path ("torch.optim.lr_scheduler.OneCycleLR") or a callable /functools.partialcalled with the optimizer. Explicit schedulers are built fromlr_scheduler_kwargsonly, with nototal_steps/T_maxinjected, are auto-wrapped in aSequentialLRlinear warmup whenwarmup_epochs>0, and step atlr_scheduler_interval("step"/"epoch").ReduceLROnPlateauis supported end-to-end: it steps once per epoch on the metric named bylr_scheduler_monitor(default"val/loss"), in both the automatic and manual (keypoint) optimization paths.
Deprecated¶
TrainConfig.lr_dropandlr_min_factor— pass them throughlr_scheduler_kwargsinstead ({"lr_drop": ...}/{"min_factor": ...}). Deprecated since v1.9.0, removal in v1.11.0. The fields still work meanwhile and are folded intolr_scheduler_kwargsfor the managed presets with aFutureWarning; default values, e.g. on config reload, do not warn. Set with an explicit, non-managed scheduler they are inert and emit aFutureWarning.
Fixed¶
- Fixed the keypoint L1-loss helper (
compute_l1_keypoint_loss) returning detachednew_zeroson its out-of-schema class-index guard; it now returns graph-connected zeros. A detached zero left the keypoint-head parameters without a gradient path on that batch, which desyncsDistributedDataParallel's gradient reducer across ranks (hang or "parameter did not receive grad") when the guard fires on some ranks but not others. This is a prerequisite for the multi-GPU keypoint training above. - Fixed non-square Albumentations training resize (
aug_configset,augmentation_backendresolving to"albumentations") silently inflating every image's longest side tomax_size, 1333 by default.SmallestMaxSize→LongestMaxSizealways forces an exact resize in Albumentations, not a conditional cap; a newCappedLongestMaxSizeinternal transform only shrinks, never upscales, matching torchvision'sRandomResizesemantics. - Fixed explicit
augmentation_backend="albumentations"resolving successfully without Albumentations installed and failing later, deep in dataset construction; it now raises a clearImportErrorimmediately. - Fixed
RFDETR.from_checkpoint(..., trust_checkpoint=True)having no effect. It previously bypassed the safe-load check only for the checkpoint's own metadata read; model construction then silently reloaded the same file throughload_pretrain_weights()with the unsafe-load default, so the flag did nothing for checkpoints that genuinely needed it and raised the sameRuntimeErrorit was supposed to bypass. (#1239) - Fixed segmentation evaluation resizing ground-truth masks to each image's original resolution before comparison, a lossy round trip vs. the mask head's native grid; GT masks now resize directly to each prediction's own pixel grid, so segm mAP is computed on consistent pixel grids. (#1241)
- Fixed
pip install 'rfdetr[onnx]'(and[tflite]) hanging while buildingonnxsimfrom source on CPython 3.11/3.13 and Linux aarch64. The previousonnxsim<0.6.0pin resolved to 0.5.0, which ships no wheels for those targets, so pip compiled onnxsim's bundled onnxruntime/onnx from source. The constraint is nowonnxsim>=0.7.0, which publishes prebuilt wheels across CPython 3.10–3.13 on Linux x86_64/aarch64, Windows x86_64, and macOS arm64. (#1242)
Deprecated¶
RFDETR.optimize_for_inference()renamed toRFDETR.inference(), same signature. The old name is kept as a deprecated alias that forwards toinference()and emits aFutureWarning. Deprecated since v1.9.0, removal in v1.11.0.
Changed¶
- Matched-pair IoU targets in the classification/matching losses compute via
elementwise_box_iou/elementwise_generalized_box_iou, new public helpers inrfdetr.utilities.box_ops, instead oftorch.diag(box_iou(...)). The old path built the full NxN pairwise IoU matrix just to read its diagonal; the new one computes only the N matched pairs directly, reducing peak GPU memory during loss calculation. Both new helpers raiseValueErroron mismatched-length inputs instead of silently broadcasting. (#1245) - The
[tensorrt]extra no longer installspycuda, needed only forTRTInference's async benchmarking mode, which now requires the separate[tensorrt-bench]extra (pip install 'rfdetr[tensorrt-bench]'); the standard export→engine path (polygraphy, nopycuda) is unaffected. (#1246)
Security¶
RFDETR.from_checkpoint()uses safe deserialization by default (weights_only=True) instead of always running full pickle deserialization. Checkpoints containing custom Python objects beyondargparse.Namespaceortypes.SimpleNamespaceneed the new keyword-onlytrust_checkpoint: bool = Falseparameter set toTrueto opt into the old, unsafe behavior; resume-from-checkpoint during training honors the same flag. (#1179)- TensorRT export no longer shells out to the
trtexecCLI — engines are built in-process through thepolygraphyPython API, removing the subprocess/shell-injection surface entirely. (#853)
Removed¶
[kornia]extra removed — GPU-side augmentation installs via[augment](pip install 'rfdetr[augment]') instead. There is no[kornia]alias extra;pip install 'rfdetr[kornia]'will fail.rfdetr.util.*andrfdetr.deployimport paths, deprecated since v1.6.0 withremove_in="1.9.0". Userfdetr.utilities.*,rfdetr.assets.coco_classes,rfdetr.training.drop_schedule,rfdetr.training.param_groups,rfdetr.visualize.data,rfdetr.models.heads.segmentation, andrfdetr.exportinstead.rfdetr._namespace.build_namespace(model_config, train_config), deprecated since v1.7.0 withremove_in="1.9.0". Userfdetr.models.build_model_from_configandbuild_criterion_from_configinstead.- The
train_configargument toload_pretrain_weights(nn_model, model_config, train_config), deprecated since v1.7.0 withremove_in="1.9.0". Call it with just(nn_model, model_config). - The
start_epoch,do_benchmark, andcallbackskeyword arguments to.train()/.evaluate(), deprecated since v1.7.0 withremove_in="1.9.0". PTL resumes automatically viaresume=; use therfdetr.export.benchmarkmodule for benchmarking; pass PTLCallbackobjects directly instead of acallbacksdict. TrainConfig.group_detr,TrainConfig.ia_bce_loss,TrainConfig.segmentation_head,TrainConfig.num_select, andModelConfig.cls_loss_coef, deprecated since v1.7.0 withremove_in="1.9.0".group_detr,ia_bce_loss,segmentation_head, andnum_selectnow live only onModelConfig;cls_loss_coefnow lives only onTrainConfig.RFDETRLarge's automatic silent fallback toRFDETRLargeDeprecatedConfigon checkpoint/config incompatibility errors. Loading legacy deprecated-Large weights throughRFDETRLargenow raises the original error instead of retrying; useRFDETRLargeDeprecateddirectly to load those checkpoints.
[1.8.3] — 2026-06-27¶
Added¶
optimize_for_inference(inplace=True)— new keyword-only argument onRFDETR.optimize_for_inference(); skips the deep-copy of the base model for memory-constrained inference-only deployments, ~0.5× model-weight peak memory reduction. Requirescompile=False. After inplace optimization,export()raisesRuntimeErrorandremove_optimized_model()issues aUserWarningand returns cleanly instead of silently clearing state. NewRFDETR.is_optimized_inplaceproperty returnsTrueafter a successful inplace optimization. (#1089)CocoKeypointSchema.keypoint_flip_pairsandYoloKeypointSchema.keypoint_flip_pairsfields — horizontal-flip swap pairs inferred automatically from keypoint names (left/right naming convention) for COCO schemas, and fromflip_idxpermutation for YOLO schemas. Auto-populated byinfer_coco_keypoint_schemaandinfer_yolo_keypoint_schemarespectively. (#1164)infer_coco_keypoint_schemaandinfer_yolo_keypoint_schemare-exported fromrfdetr.datasets, previously only accessible fromrfdetr.datasets._keypoint_schema. (#1164)
Changed¶
- Horizontal flip detection in
AlbumentationsWrapperuses AlbumentationsReplayComposereplay metadata instead of heuristic bbox-center mirroring, eliminating false positives on non-flip transforms that shift box centers. Falls back toalb.Composewith aUserWarningwhenalbumentations <1.3is detected. (#1164) - Keypoint schema inference supports native COCO format (
dataset_file="coco") in addition to"roboflow"and"yolo". (#1164) _keypoint_schema_cachekey changed fromdataset_dir(string) to(dataset_file, dataset_dir)tuple, preventing cross-format cache collisions when the same directory is used with different dataset formats. (#1164)
Fixed¶
- Fixed unbounded box regression producing negative or out-of-frame coordinates: predicted bounding boxes are clamped to image bounds
[0, width] × [0, height]inPostProcess._postprocess_boxes().scale_fctis also cast toboxes.dtypebefore multiplication, preventing dtype mismatch when boxes arefloat16. (#1168) - Fixed
SegmentationTrainConfig.cls_loss_coefdefault of5.0, corrected to1.0to restore the pre-v1.7 effective classification loss weight. The5.0value was present since v1.6 but dead code until the v1.7 TrainConfig ownership migration activated it, silently over-penalising classification relative to mask losses during segmentation fine-tuning. To reproduce pre-fix behaviour, passcls_loss_coef=5.0explicitly. (#1165) - Fixed
KeypointTrainConfig.keypoint_nll_loss_coef, restored to1.0to align with the other keypoint loss terms (keypoint_l1_loss_coef,keypoint_findable_loss_coef,keypoint_visible_loss_coef). The previous default of0.5was set to dampen OKS@75 oscillation but under-weighted the NLL loss relative to other terms in practice. (#1165)
[1.8.2] — 2026-06-25¶
Added¶
- YOLO pose keypoint dataset support: load Ultralytics YOLO pose datasets (
.yamlwithkpt_shape) directly for keypoint fine-tuning. Schema is inferred automatically viainfer_yolo_keypoint_schema. (#1156) is_bg_first_schema,to_active_first,to_bg_first,schemas_semantically_equalutilities inrfdetr.utilities.keypoints, re-exported fromrfdetr.utilities, for schema-aware keypoint processing. (#1160)amp_dtypefield onTrainConfig("auto"/"bf16"/"fp16"): pin the mixed-precision autocast dtype instead of relying on device-capability auto-detection."auto", the default, preserves the historical behaviour —bf16-mixedon Ampere+ CUDA,16-mixedotherwise. Invalid values degrade gracefully to"auto"with aUserWarning. (#1143)- Instance segmentation fine-tuning cookbook (
docs/cookbooks/fine-tune_segmentation.ipynb) — end-to-end walkthrough usingRFDETRSegSmallacross seven diverse segmentation datasets. (#1159) - Inference latency benchmark cookbook (
docs/cookbooks/inference-latency-benchmark.ipynb) — benchmarks CPU/GPU throughput across model sizes with reproducible measurement methodology. (#1152)
Changed¶
- Default
num_keypoints_per_classinRFDETRKeypointPreviewConfigchanged from[0, 17](background-first) to[17](active-first). Legacy bg-first checkpoints auto-align on load via_kp_active_mask. (#1160)
Fixed¶
- Fixed
RFDETR.from_checkpoint()misreadingnum_classesasshape[0], i.e.num_classes + 1including the background class, causingload_state_dictshape mismatches or a silent extra output class on every load. It now infersnum_classesandnum_keypoints_per_classfrom checkpoint weights,class_embed.weight.shape[0] - 1and_kp_active_maskrespectively.BestModelCallback._serialize_model_configis also fixed to persist the correct foreground-onlynum_classes. (#1158) - Fixed
HungarianMatcher.forward()hardcoding0.25in the focal classification matching cost, silently ignoring any non-defaultfocal_alphapassed to the constructor orbuild_matcher; it now uses the configured value. This had misaligned the bipartite matching cost with the focal classification loss incriterion.py, which correctly usedself.focal_alpha. (#1147) - Fixed
spatial_shapesinTransformer.forward()being built bytorch.empty+ in-place index assignment, which emitted aScatterNDfeeding a shape tensor (level_start_index) that TensorRT rejected with "IScatterLayer cannot be used to compute a shape tensor". It now uses symbolicShapeops,torch.stackof per-leveltorch._shape_as_tensorslices. Required to export any RF-DETR model to a TensorRT engine. (#1155) - Fixed keypoint model inference returning the wrong
class_namefield in predictions. (#1151) - Fixed silent train-mode inference after the first prediction:
predict()re-asserts eval mode before each call for unoptimized models. (#1146) - Fixed TFLite inference preprocessing and mask decoder diverging from PyTorch
predict()behaviour. (#1131) - Fixed a Python version mismatch in optional-dependency version overrides. (#1137)
[1.8.1] — 2026-06-19¶
Changed¶
- Config path parameters, e.g.
dataset_dir,output_dir,pretrain_weights, acceptpathlib.Pathobjects in addition to strings. Paths are coerced tostrautomatically via theexpand_pathsvalidator. No API changes required; existing string usage unaffected. (#1124) - Keypoint training disables horizontal flip augmentation until keypoint flip-pair swapping is implemented. Flipping was previously applied without reordering keypoint pairs, producing incorrect labels. (#1122)
- Training metric plots improved with optional seaborn error bands, AP@0.75 metric grouping, and custom AP metric group configuration. (#1122)
Fixed¶
- Fixed the keypoint encoder in eval mode splitting
num_queriesqueries across all group heads, becausegroup_detr = len(self.enc_out_keypoint_embed); anif self.training else 1guard now routes all queries through head 0. (#1135) - Fixed
config.use_return_dict, deprecated intransformers, replaced withconfig.return_dictin the DINOv2 windowed attention backbone. (#1135) - Fixed epoch metric tables rendering incorrectly when a Rich progress bar callback is active. Tables print through the progress bar's owned Rich console, preventing cursor conflicts with active live displays. (#1128)
- Fixed spurious keypoint fine-tuning checkpoint switches on noisy OKS metrics: selection is stabilised with smoothed (EMA) best-metric comparison, and smoothing state is correctly restored on training resume. (#1122)
- Fixed Group DETR train-time metric evaluation crashing on non-tensor mask outputs from auxiliary decoder layers; it now evaluates only the primary query group. (#1122)
- Fixed
_detect_horizontal_flipin the Albumentations transform pipeline usingnot bboxes, which mishandles Albumentations 2.x where bboxes is a NumPy array, falsy even when non-empty; it now useslen(bboxes) == 0. (#1126) - Fixed a crash inside
_log_hyperparamswhentensorboardis installed alongside a NumPy-2.0-incompatibletensorflow; the TensorBoard logger is now disabled gracefully and training degrades to CSV-only logging with a clear warning. (#1123)
[1.8.0] — 2026-06-13¶
Added¶
RFDETRKeypointPreview— keypoint detection model variant with GroupPose-style head, covariance-based uncertainty (precision-Cholesky parameterization), and COCO keypoint AP evaluation. Public config classes:KeypointTrainConfig,RFDETRKeypointPreviewConfig(fromrfdetr.config). Utility:precision_cholesky_to_pixel_covariance(fromrfdetr.utilities). Schema helpersinfer_coco_keypoint_schema,CocoKeypointSchema,active_keypoint_countsaccessible viarfdetr.datasets._keypoint_schema. (#1099)RFDETR.export_for_roboflow(output_dir)— writes a Roboflow upload bundle (weights.pt+class_names.txt) without a network call; extracted fromdeploy_to_roboflow, which now delegates to it. (#1086)- Keypoint fine-tuning cookbook (
docs/cookbooks/fine-tune_keypoints.ipynb) — end-to-end walkthrough: dataset download, schema inference,KeypointTrainConfig, training metrics, and inference with covariance uncertainty. (#1104) MetricKeypointOKS— reusable OKS metric facade overCocoEvaluator, exported fromrfdetr.evaluation. Supports arbitrary keypoint counts, per-category OKS sigma values, DDP-safe evaluation with first-rank-wins deduplication, and anOKSKeyenum (mAP,mAP@50,mAP@75,mAR) for standardised metric keys. (#1107)
Changed¶
- DDP strategy enables
find_unused_parameters=Truefor all detection, keypoint, and segmentation models understrategy='ddp'orstrategy='auto'with a distributed launcher, previously segmentation only. Opt out viatrainer_kwargs={"strategy": DDPStrategy(find_unused_parameters=False)}. (#1094) rfdetr.datasets.aug_configmodule renamed torfdetr.datasets.aug_configs(plural). Direct imports fromrfdetr.datasets.aug_configmust be updated; the augmentation preset constants (AUG_AGGRESSIVE, etc.) are unchanged. (#1103)
Removed¶
RFDETR.export(simplify=..., force=...)— both kwargs removed from the signature. Deprecated since v1.6.0 withremove_in="1.8.0"; both were no-ops during the deprecation window. Callers passing these args must remove them before upgrading. (#1102)
Fixed¶
- Fixed
RFDETR.from_checkpoint()treatingnum_classesloaded from the checkpoint as a user-supplied override, which silently refused fine-tuning on a dataset with a different class count — the head refused to re-initialise and trained against the stale class count. An explicitnum_classeskwarg from the caller still wins over both the checkpoint value and the dataset. (#1106) - Fixed scale jitter missing from the non-square training crop:
RandomCropin theoption_bbranch replaced withRandomSizedCrop, restoring the scale-augmentation behaviour lost during the Albumentations migration. (#1088) - Fixed a multi-GPU validation deadlock in COCO mAP synchronization;
_merge_metric_state_across_ranksis now safe across zero-batch ranks. (#1085) - Fixed
import rfdetrfailing on NumPy 2.x when a transitive dependency references the removednp.complex_alias. (#1064) - Fixed the
rfdetr_plusmodule availability check giving a false-positive hit when the package was partially installed. (#1083) - Fixed a spurious "Keypoint class-logit boost has N classes but detection head has M" warning on custom, non-Roboflow keypoint datasets:
_align_num_classes_from_datasetnow zero-padsnum_keypoints_per_classwhen auto-adjustingnum_classesbeyond the schema length. (#1113) - Fixed loss scaling for keypoint training under gradient accumulation (
accumulate_grad_batches > 1). Keypoint models use manual optimization to normalize losses by the accumulated box count across the effective batch; detection and segmentation remain on Lightning's automatic-optimization path. Optimizer-step scheduling, LR warmup/decay, and epoch-boundary flushing are correctly handled in both paths. (#1117) - Fixed device auto-detection assigning a CUDA device on a machine with CUDA headers but no GPU driver, which then failed at first use; it now verifies accelerator runtime availability first (PyTorch ≥ 2.4:
torch.accelerator.current_accelerator; older builds:torch.cuda.is_available()). (#1111) - Fixed
RFDETR.from_checkpoint()and related APIs silently treating an explicitnum_classesas unset when its value equals the model default, e.g. 80 for COCO, which refused fine-tuning on a different class count. (#1109) - Fixed
RFDETR.from_checkpoint()raising an error or silently loading the wrong model class for starter-like checkpoints without an explicitpretrain_weightsentry; it now infers the model variant from the checkpoint filename whenpretrain_weightsis absent or unset-like — empty string,None, whitespace. (#1065)
[1.7.0] — 2026-04-29¶
Added¶
augmentation_backendfield onTrainConfig("cpu"/"auto"/"gpu"): opt-in GPU-side augmentation via Kornia, applied inRFDETRDataModule.on_after_batch_transferonce the batch is on the GPU. The CPU path is unchanged and remains the default. Install withpip install 'rfdetr[augment]'. (#1003)- Kornia GPU augmentation supports instance segmentation: images, boxes, and per-instance masks augmented in sync on the GPU, where
augmentation_backend="gpu"/"auto"was previously ignored silently. New public helpercollate_masks;build_kornia_pipelinegainswith_masks: bool = False;unpack_boxesgains an optionalmasks_augtensor. Note: the mask buffer is[B, N_max, H, W]float32, roughly 500 MB atB=8, N_max=50, H=W=560; useaugmentation_backend="cpu"on cards with limited VRAM. (#1003, closes #997) BuilderArgs— a@runtime_checkabletyping.Protocoldocumenting the minimum attribute set consumed bybuild_model(),build_backbone(),build_transformer(), andbuild_criterion_and_postprocessors(). Enables static type-checker support for custom builder integrations. Exported fromrfdetr.models. (#841)build_model_from_config(model_config, train_config=None, defaults=MODEL_DEFAULTS)— config-native alternative tobuild_model(build_namespace(mc, tc)); accepts Pydantic config objects directly and constructs the internal namespace automatically. Exported fromrfdetr.models. (#845)build_criterion_from_config(model_config, train_config, defaults=MODEL_DEFAULTS)— config-native alternative tobuild_criterion_and_postprocessors(build_namespace(mc, tc)); returns a(SetCriterion, PostProcess)tuple. Exported fromrfdetr.models. (#845)ModelDefaultsdataclass — exposes the 35 hardcoded architectural constants previously buried insidebuild_namespace(). Pass adataclasses.replace(MODEL_DEFAULTS, ...)override to the new config-native builders to customise individual constants. Note: fields may be promoted toModelConfig/TrainConfigin future phases. Exported fromrfdetr.models. (#845)MODEL_DEFAULTS— the canonicalModelDefaultssingleton with production defaults. Exported fromrfdetr.models. (#845)RFDETR.predict(include_source_image=...)— opt-out flag, defaultTrue, to skip storing the source image indetections.metadata["source_image"]; setFalseto reduce memory use when the image is not needed for annotation. (#912)model_nameis stored in checkpoint files during training, soRFDETR.from_checkpoint()resolves the model class from the checkpoint without a caller-supplied hint.strip_checkpoint()preserves it; checkpoints without it still resolve viapretrain_weightsfilename matching. (#895)rfdetr_versionis stored in checkpoint files during training for provenance and compatibility hints.strip_checkpoint()preserves it; the key is omitted gracefully when the package version cannot be resolved, and checkpoints without it load normally. (#918)notesparameter onRFDETR.train()andRFDETR.export()— embed arbitrary JSON-serialisable provenance metadata (labeller, date, class names, etc.) into best-model.pthcheckpoints, undercheckpoint["args"]["notes"], and ONNX files, under the"rfdetr_notes"metadata property. String values are stored verbatim; all other types are JSON-encoded. (#1025, closes #1021)RF_HOMEenvironment variable controls where pretrained weights are cached, default~/.roboflow/models. Bare filenames passed aspretrain_weights, e.g."rf-detr-base.pth", resolve relative to it; paths with a directory component are used as-is, parent directories created automatically. (#130)- Grayscale and multispectral imagery support: models accept any channel count, not just 3, with pretrained DINOv2 patch-embedding weights adapted to it at construction time and no extra dependencies. (#180, closes #75)
- Training configuration is saved to
training_config.jsonin the output directory after training, capturing the fullTrainConfig,ModelConfig, effective training parameters, class names, and class count. (#194) dinov2_registers_windowed_smallbackbone is available as a config option inModelConfig.encoder. (#236)rfdetr.from_checkpoint(path)— new top-level convenience function that loads a checkpoint and infers the correct model subclass automatically, without the caller specifying a class. Equivalent toRFDETR.from_checkpoint(path)but importable directly from therfdetrpackage. (#664)- ONNX export filenames include the model variant name, e.g.
rfdetr-medium.onnx, instead of the genericinference_model.onnx. Exporting multiple variants to the same directory no longer overwrites previous exports. (#910) - Background images, those without a matching label file, are included in YOLO detection datasets as empty-detection samples instead of being dropped; detection and segmentation both use
_LazyYoloDetectionDataset. (#915) - TFLite export via
model.export(format="tflite"). Converts through ONNX usingonnx2tf; FP32 and FP16 outputs are always produced, INT8 quantization is available with a calibration image directory:model.export(format="tflite", quantization="int8", calibration_data="path/to/images/"). Requirespip install 'rfdetr[onnx,tflite]'. (#920) - PyTorch Lightning
.ckptfiles are accepted aspretrain_weights; keys are normalized from PTL format automatically (state_dictwithmodel.-prefixed keys,hyper_parameters→args), so weight loading, class-name extraction, and compatibility checks need no manual conversion. (#951) skip_best_epochsparameter forRFDETR.train()andTrainConfig: the first N epochs are excluded from best-checkpoint selection and early-stopping comparison, preventing strong pretrained weights or resumed checkpoints from locking in a suboptimal early score. (#1000, closes #789)- TFLite inference decodes segmentation mask outputs into
sv.Detections.mask, upsampled to source size with Pillow bilinear resampling and thresholded at zero, matchingPostProcess.forward. The mask tensor is detected by output name,"masks"substring, with a rank-4 shape fallback. (#1053) PretrainWeightsCompatibilityWarning— new warning class emitted when aModelConfigoverride, e.g. customencoder,num_queries, ornum_feature_levels, risks breaking pretrained weight loading. Importable asfrom rfdetr.config import PretrainWeightsCompatibilityWarningfor targeted filtering. (#1017)
Changed¶
peftis no longer installed as part of the defaultrfdetrpackage; it moved to the[lora]and[train]optional extras. For LoRA fine-tuning, install withpip install 'rfdetr[lora]'. (#838)- Native RLE annotation support in the COCO segmentation pipeline:
convert_coco_poly_to_maskexplicitly detects and decodes both compressed (string counts) and uncompressed (int-list counts) RLE formats alongside existing polygon support. Malformed annotations now raise instead of being silently swallowed. (#897) - Pinned PyTorch Lightning to exclude known-compromised versions. (#1020)
Deprecated¶
build_namespace(model_config, train_config)— no longer used internally and deprecated in this release; usebuild_model_from_config,build_criterion_from_config, or_namespace_from_configsdirectly. Removal in v1.9; emits aDeprecationWarningon use. (#845)load_pretrain_weights(nn_model, model_config, train_config)— thetrain_configpositional argument is deprecated, removal in v1.9, and is no longer used internally. Omit it:load_pretrain_weights(nn_model, model_config). Passing a non-Nonevalue emits aDeprecationWarning. (#845)TrainConfig.group_detr,TrainConfig.ia_bce_loss,TrainConfig.segmentation_head,TrainConfig.num_select→ModelConfig;ModelConfig.cls_loss_coef→TrainConfig. Each emitsDeprecationWarningwhen set on the wrong config object and will be removed in v1.9.SegmentationTrainConfigusers: remove thenum_selectoverride, the model config value is always used. (#841)RFDETRBase— useRFDETRNano,RFDETRSmall,RFDETRMedium, orRFDETRLargeinstead. EmitsFutureWarningon instantiation; scheduled for removal in v2.0. (#900)RFDETRSegPreview— useRFDETRSegNano,RFDETRSegSmall,RFDETRSegMedium, orRFDETRSegLargeinstead. EmitsFutureWarningon instantiation; scheduled for removal in v2.0. (#900)rfdetr.utilandrfdetr.deploysub-modules are deprecated, removal in v1.9. A__getattr__hook on therfdetrpackage emits a clearImportErrorwith migration guidance when these legacy paths are accessed. (#839)
Fixed¶
- Fixed TFLite export (
format="tflite") producing detection scores that collapse to ~0.02, vs ~0.62 from ONNX; cause was an onnx2tfGridSamplelowering bug (PINTO0309/onnx2tf#274) compounding through RF-DETR's per-decoder-layerF.grid_sample. The converter now passes onnx2tf's pseudo-GridSamplereplacement kwarg, logging a warning when it is absent. (#1041) - Fixed
WindowedDinov2WithRegistersEmbeddings.forward()failing silently under-Owhen input spatial dimensions are not divisible bypatch_size * num_windows; it now raisesValueErrorwith a clear message identifying the divisor and actual shape. (#167) - Fixed
_namespace.py:num_selectin the builder namespace always reads fromModelConfig, whereTrainConfig.num_select(default 300) silently overrode model-specific values of 100–200 for segmentation variants. (#841) - Fixed
models/weights.py:load_pretrain_weightsauto-aligns the model head when the checkpoint has fewer classes than the configured default, preventing a silent mismatch when the caller did not setnum_classes. (#845) - Fixed
models/weights.py:load_pretrain_weightsslicesrefpoint_embed.weightandquery_feat.weightper-group when reshaping checkpoint queries; the previous flat slice scrambled groups 1+ whennum_queriesdecreased withgroup_detr > 1, corrupting training-resume. Inference, which reads group 0 only, was unaffected. (#1019) - Fixed YOLO segmentation training on large datasets hitting OS out-of-memory, caused by
supervision.DetectionDataset.from_yolo(force_masks=True)eager-rasterising every image's masks at construction time. A new_LazyYoloDetectionDatasetstores polygons and defers rasterisation to__getitem__, keeping RAM proportional to annotation count. (#851) - Fixed ONNX/TRT dynamic batch inference: the tracer baked the training batch size as a compile-time constant, so TRT engines built with smaller
--minShapesfailed withReshape: reshaping failed. Six call sites ingen_encoder_output_proposalsandTransformer.forwardnow use ONNX-symbolic equivalents, keeping the batch dimension dynamic. (#950, closes #949) - Fixed training failure when
square_resize_div_64=False: the non-square resize pipeline did not guarantee dimensions divisible bypatch_size * num_windows, raisingValueError. APadIfNeededstep is appended after the resize pair in the train and val/test pipelines. (#991, closes #983) - Fixed non-square batch padding:
block_sizerounding is applied in the DataLoader collator as well as the transform-levelPadIfNeeded, so divisibility bypatch_size * num_windowssurvivesComposereordering and applies to custom evaluation harnesses. (#992) - Fixed
RFDETRModelModule.on_load_checkpointcrashing withRuntimeErrorwhen resuming from a checkpoint saved at a different image resolution; DINOv2 positional embeddings are bicubic-interpolated tomodel_config.positional_encoding_sizefirst. (#1002, closes #998) - Fixed
RFDETRLargeinitialization showing two conflictingValueErrors, forpatch_size=14andpatch_size=16, when the deprecated-config fallback retry also fails; the fallback re-raises the original error without chained context. (#975) - Fixed
RFDETRModelModule.__init__crashing withRuntimeError: size mismatch for backbone.0.encoder.encoder.embeddings.position_embeddingswhen training segmentation models at a custom resolution, e.g.RFDETRSegLarge(resolution=1008); the training entry path delegates toload_pretrain_weights, which interpolates the positional embeddings. (#1040, closes #1038, #1023) - Fixed TFLite detection scores collapsing for all queries when
GridSamplewas used as an onnx2tf pseudo-operator; the node is rewritten toGather-based integer-index arithmetic before conversion. Supersedes the runtime-kwarg approach in #1041. (#1054) - Fixed
class_namelookup for pretrained COCO models: sparse COCO category IDs, 1–90 for 80 classes, made flat 0-based indexing return the wrong name. Detection uses acoco_id → class_namemapping built fromCOCO_CLASSES; fine-tuned models keep direct 0-based indexing. (#1051)
[1.6.5] — 2026-04-22¶
Breaking Changes¶
predict()stores the source image indetections.metadata["source_image"], notdetections.data["source_image"], which supervision indexed per-detection and raisedIndexErroron. Update any code that readsdetections.data["source_image"]. (#972, #968)
Fixed¶
- Fixed segmentation training crash on T4 and P100 GPUs, caused by cuDNN engine selection for depthwise convolution backward on some CUDA stacks. A custom
autograd.Functiondisables cuDNN in forward and backward. (#967) - Fixed
ema_segm_mAP_50_95andema_segm_mAP_50being computed from the base, non-EMA, metric accumulator instead of the EMA accumulator, producing misleading validation scores for segmentation models. (#980) - Fixed
BestModelCallbacklosing the best EMA score on training resume, because_best_emawas not persisted instate_dict(). (#973) - Fixed
positional_encoding_sizenot updating whenresolutionis set at construction time, e.g.RFDETRLarge(resolution=640), causing shape mismatches during forward. A model validator now auto-syncs PE size. (#956) - Fixed a pretrained weight loading crash with custom resolution: DINOv2 positional embeddings are bicubic-interpolated to match the target grid before
load_state_dict. (#964) - Fixed
validate_checkpoint_compatibilityproducing a crypticRuntimeErroronpatch_sizemismatch when the checkpoint lacks explicitargs.patch_size; it now inferspatch_sizefrom the DINOv2 projection weight shape and raises a descriptiveValueError. (#971) - Fixed
predict()storingdetections.data["source_shape"]as a Pythontuple, which raisedTypeErrorwheneversv.Detectionswas iterated. The value is now annp.ndarrayof shape(N, 2)and dtypeint64. (#966, #963) - Fixed
predict()emitting a misleading "class_id out of range" warning for the background/no-object class, class indexnum_classes. Background-class detections mapdata["class_name"]to"__background__"without any warning. (#970)
[1.6.4] — 2026-04-10¶
Changed¶
predict()includesclass_nameindetections.data, mapping each detection's 0-indexed class ID to its human-readable name. (#914)
Fixed¶
- Fixed segmentation multi-GPU DDP training crashing with
RuntimeError: It looks like your LightningModule has parameters that were not used in producing the loss, because the segmentation head'ssparse_forward()leaves parameters unused on some steps:build_trainer()wrapsstrategy="ddp"withDDPStrategy(find_unused_parameters=True)whensegmentation_head=True. Non-segmentation DDP and other strategies are unchanged. (#942, #947) - Fixed fused AdamW crashing under FP32 multi-GPU training with
RuntimeError: params, grads, exp_avgs, and exp_avg_sqs must have same dtype, device, and layout:configure_optimizers()andclip_gradients()gate fused AdamW on the trainer's actual precision, not GPU capability, which reports BF16 support on Ampere+ even atprecision="32-true". (#942, #947) - Fixed multi-GPU DDP training crashing in Jupyter notebooks and Kaggle: the fork-based
ddp_notebookstrategy is replaced with a spawn-based one, avoiding OpenMP thread pool corruption afterfork(). (#928) - Fixed
RFDETR.train(resolution=...)being silently ignored; the kwarg is applied tomodel_configbefore training begins, with validation that the value is divisible bypatch_size * num_windows. (#933) - Fixed
save_dataset_gridsbeing silently a no-op;DatasetGridSaveris wired into the training loop, saving sample grids to{output_dir}/dataset_grids/when enabled. Grid save failures are caught without interrupting training. (#946) - Fixed partial gradient-accumulation windows at the tail of training epochs: the training dataset is padded to an exact multiple of
effective_batch_size * world_size, so every optimizer step uses a full gradient window. Workaround for pytorch-lightning#19987. (#937) - Fixed
torch.export.exportfailing on the transformer decoder, by threadingspatial_shapes_hwthrough all decoder layers. (#936) - Fixed
download_pretrain_weights()overwriting fine-tuned checkpoints that share a filename with a registry model, e.g.rf-detr-nano.pth, where an MD5 mismatch silently restored the original COCO checkpoint. It now returns early whenever the file exists andredownload=False, warning when the hash differs; passredownload=Trueto force a fresh download. (#935)
[1.6.3] — 2026-04-02¶
Changed¶
predict()stores the original image and its shape on returnedsv.Detectionsobjects —detections.data["source_image"](NumPy array) anddetections.data["source_shape"](NumPy array of shape(N, 2), each row[height, width]) let you annotate results without loading the image separately. (#892)RFDETR.train()auto-detectsnum_classesfrom the dataset directory when not explicitly set, reinitializing the detection head to the correct class count automatically. A warning is emitted when the configured value differs from the dataset count. (#893)optimize_for_inference()accepts dtype as a string name, e.g."float16", in addition to atorch.dtypeobject; invalid dtype inputs uniformly raiseTypeError. (#899)
Fixed¶
- Fixed
models/lwdetr.py:reinitialize_detection_headreplacesnn.Linearmodules instead of mutating.datain place, keepingout_featuresconsistent with the weight shape, so ONNX export andtorch.jit.traceno longer emit stale class counts for fine-tuned models. (#904) - Fixed
RFDETR.optimize_for_inference()leaking a CUDA context on multi-GPU setups: the deep-copy, export, and JIT-trace steps run insidetorch.cuda.device(device)to pin the context to the correct device. (#899) - Fixed
optimize_for_inference()leaving inconsistent state on failure: prior optimized state is reset and flags are committed only after a successful build/trace; temp download files use unique per-process paths to avoid parallel worker collisions. - Fixed
deploy_to_roboflowfailing withFileNotFoundErrorafter the PyTorch Lightning migration:class_names.txtis written to the upload directory andargs.class_namesis populated before saving the checkpoint. (#890)
[1.6.2] — 2026-03-27¶
Added¶
RFDETR.predict(shape=...)— optional(height, width)tuple overrides the default square inference resolution; useful when matching a non-square ONNX export. Both dimensions must be positive integers divisible bypatch_size × num_windowsas determined by the model configuration. (#866)
Changed¶
ModelConfig.deviceandRFDETR.train(device=...)accepttorch.deviceobjects and indexed device strings such as"cuda:0". Values are normalized to canonical torch-style strings.RFDETR.train()warns when an unmapped device type is passed to PyTorch Lightning auto-detection. (#872)
Fixed¶
- Fixed ONNX export ignoring an explicit
patch_sizeargument:export()andpredict()resolvepatch_sizefrommodel_configby default, validate it strictly (positive integer, not bool), and enforce that(H, W)dimensions are divisible bypatch_size × num_windows. (#876) - Fixed ONNX export for models with dynamic batch dimensions:
H_.expand(N_)replaced withtorch.fullfor Python-int spatial dims, eliminating tracer failures. (#871)
[1.6.1] — 2026-03-25¶
Deprecated¶
RFDETR.export(..., simplify=..., force=...)— both arguments are now no-ops and emit aDeprecationWarning. RF-DETR no longer runs ONNX simplification automatically; remove these arguments from your calls. Removal in v1.8. (#861)
Fixed¶
- Fixed
RFDETR.train()raising a bareModuleNotFoundErroron a missingrfdetr[train]install; it now raises anImportErrornaming the fix,pip install "rfdetr[train,loggers]". (#858) - Fixed
AUG_AGGRESSIVEpreset:translate_percent(0.1, 0.1)was a degenerate range forcingAffineto always translate right/down by exactly 10%, corrected to(-0.1, 0.1). (#863) - Fixed the PTL training path:
latest.ckptand per-interval checkpoints (checkpoint_interval_N.ckpt) are written and restored on resume. (#847) - Fixed
BestModelCallbackand checkpoint monitor raisingMisconfigurationExceptionon non-eval epochs wheneval_interval > 1; monitor key absence is handled gracefully. (#848) - Fixed the
protobufversion constraint in theloggersextra, guarding against the TensorBoard descriptor crash (TypeError: Descriptors cannot be created directly) with protobuf ≥ 4. (#846) - Fixed duplicate
ModelCheckpointstate keys whencheckpoint_interval=1;last.ckptis omitted in that configuration to avoid collision. (#859)
[1.6.0] — 2026-03-20¶
Added¶
- PyTorch Lightning training building blocks:
RFDETRModelModule,RFDETRDataModule,build_trainer(), and callbacks (RFDETREMACallback,COCOEvalCallback,BestModelCallback,DropPathCallback,MetricsPlotCallback) — standard PTL components, swap/subclass/extend any piece. Level 3:rfdetr fit --configCLI, zero Python required. (#757, #794) - Multi-GPU DDP via
model.train():strategy,devices, andnum_nodesadded toTrainConfig; single-GPU behaviour unchanged when omitted. (#808) batch_size='auto': CUDA memory probe finds the largest safe micro-batch size, then recommendsgrad_accum_stepsto reach a configurable effective batch target, default 16 viaauto_batch_target_effective. (#814)ModelContextpromoted from_ModelContextto a public, exported API — inspectclass_names,num_classes, and related metadata viamodel.contextafter training. (#835)backbone_loraandfreeze_encoderadded as first-class fields inModelConfig. (#829)generate_coco_dataset(with_segmentation=True)produces COCO polygon annotations alongside bounding boxes for segmentation fine-tuning with synthetic data. (#781)set_attn_implementation("eager" | "sdpa")on the DINOv2 backbone — switch attention implementation at runtime. (#760)eval_max_dets,eval_interval, andlog_per_class_metricsadded toTrainConfig.python -m rfdetrentry point alongside therfdetrconsole script.py.typedmarker — RF-DETR is now PEP 561–compliant.
Changed¶
- Breaking: Minimum
transformersversion bumped to>=5.1.0,<6.0.0. The DINOv2 windowed-attention backbone uses the transformers v5 API (BackboneMixin._init_transformers_backbone(), removedhead_maskplumbing). Projects still on transformers v4 must pinrfdetr<1.6.0. (#760) - Breaking: PyPI install extras renamed —
rfdetr[metrics]→rfdetr[loggers],rfdetr[onnxexport]→rfdetr[onnx]. draw_synthetic_shapereturnsTuple[np.ndarray, List[float]], notnp.ndarray. The second element is a flat COCO-style polygon list[x1, y1, x2, y2, …]. Any caller that didimg = draw_synthetic_shape(...)must be updated toimg, polygon = draw_synthetic_shape(...). (#781)- Albumentations version constraint broadened to
>=1.4.24,<3.0.0;RandomSizedCropconfigs usingheight/widthkwargs are adapted automatically to the 2.xsize=(height, width)API. (#786) - Current learning rate is shown in the training progress bar alongside loss. (#809)
supervision,pytorch_lightning, and other heavy dependencies are imported lazily, on first use, rather than at module load, reducing cold-import time in inference-only environments. (#801)
Deprecated¶
rfdetr.deploy.*— redirects torfdetr.export.*with aDeprecationWarning. Migrate before v1.7.rfdetr.util.*— redirects torfdetr.utilities.*with aDeprecationWarning. Migrate before v1.7.
Fixed¶
- Fixed a cryptic
RuntimeError/ tensor-size mismatch when a checkpoint is incompatible with the current model architecture; a descriptiveValueErroris raised instead, coveringsegmentation_headmismatch andpatch_sizemismatch. (#810) - Fixed
class_namesnot reflecting dataset labels onmodel.predict()after training; class names are synced from the dataset so inference always uses the correct label list. (#816) - Fixed detection head reinitialization overwriting fine-tuned weights when loading a checkpoint with fewer classes than the model default. The second
reinitialize_detection_headcall fires only in the backbone-pretrain scenario. (#815, #509) - Fixed
grid_sampleand bicubic interpolation silently falling back to CPU on MPS (Apple Silicon); both run natively on the MPS device. (#821) - Fixed
early_stopping=FalseinTrainConfigbeing silently ignored; the setting propagates correctly. (#835) - Fixed an
AttributeErrorcrash inupdate_drop_pathwhen the DINOv2 backbone layer structure does not match any known pattern. - Added warning when
drop_path_rate > 0.0is configured with a non-windowed DINOv2 backbone, where drop-path is silently ignored. - Fixed
ValueError: matrix entries are not finiteinHungarianMatcherwhen the cost matrix contains NaN or Inf; non-finite entries are replaced with a finite sentinel beforelinear_sum_assignment, warning emitted at most once per matcher instance. (#787) - Fixed YOLO dataset validation rejecting
data.yml; both.yamland.ymlare accepted. (#777) - Silently dropped degenerate bounding boxes, zero width or height, before Albumentations validation instead of raising
ValueError. (#825)
[1.5.2] — 2026-03-04¶
Added¶
- Added peak GPU memory (
max_memin MB) to training and evaluation progress bars on CUDA; omitted on CPU and MPS. (#773)
Fixed¶
- Fixed
aug_configbeing silently ignored when training on YOLO-format datasets;build_roboflow_from_yolonever forwarded the value, so transforms always fell back to the default. (#774) - Fixed segmentation evaluation metrics not being written to
results_mask.jsonduring validation and test runs. (#772) - Fixed an
AttributeErrorcrash inupdate_drop_pathwhen the DINOv2 backbone layer structure does not match any known pattern;_get_backbone_encoder_layersreturnsNonefor unrecognised architectures. (#762) - Fixed
drop_path_ratenot being forwarded to the DINOv2 model configuration, so stochastic depth was never applied even when explicitly set. Added a warning whendrop_path_rate > 0.0is used with a non-windowed backbone. (#762) - Fixed incorrect COCO hierarchy filtering that excluded parent categories from the class list. (#759)
- Fixed evaluation metric corruption on 1-indexed Roboflow datasets, caused by a flawed contiguity check in
_should_use_raw_category_ids. (#755)
[1.5.1] — 2026-02-27¶
Added¶
- Added support for nested Albumentations containers (
OneOf,Sequential) insideaug_config. (#752)
Changed¶
- Migrated dataset transform pipeline to torchvision-native
Compose,ToImage, andToDtype;Normalizedefaults to ImageNet mean/std. (#745)
Fixed¶
- Fixed
RFDETRMediummissing from the public API;__all__contained a duplicateRFDETRSmallentry. (#748) - Fixed
AR50_90reporting an incorrect value inMetricsMLFlowSink, due to a wrong COCO evaluation index. (#735) - Fixed supercategory filtering in
_load_classesfor COCO datasets with flat or mixed supercategory structures. (#744) - Fixed a crash in geometric transforms when a sample contained zero-area or empty masks. (#727)
- Fixed segmentation training on Colab;
DepthwiseConvBlockdisables cuDNN for depthwise separable convolutions. (#728) - Pinned
onnxsim<0.6.0to preventpip installfrom hanging indefinitely. (#749)
[1.5.0] — 2026-02-23¶
Added¶
- Added custom training augmentations via
aug_configinmodel.train()— accepts a dict of Albumentations transforms, a built-in preset (AUG_CONSERVATIVE,AUG_AGGRESSIVE,AUG_AERIAL,AUG_INDUSTRIAL), or{}to disable. Bounding boxes and segmentation masks are transformed automatically. (#263, #702) - Added
save_dataset_grids=TrueinTrainConfigto write 3×3 JPEG grids of augmented samples tooutput_dirbefore training begins. (#153) - Added ClearML logger: set
clearml=TrueinTrainConfigto stream per-epoch metrics to ClearML. (#520) - Added MLflow logger: set
mlflow=TrueinTrainConfigto log runs and metrics to MLflow with custom tracking URI support. (#109) - Added live progress bar for training and validation with structured per-epoch logs. (#204)
- Added
devicefield toTrainConfigfor explicit device selection. (#687) ModelConfigraises an error on unknown parameters, preventing silent misconfiguration. (#196)
Changed¶
- Deprecated
OPEN_SOURCE_MODELSconstant in favour ofModelWeightsenum. (#696) - Added MD5 checksum validation for pretrained weight downloads. (#679)
Fixed¶
- Fixed Albumentations bool-mask crash during segmentation training. (#706)
- Fixed
UnboundLocalErrorwhen resuming training from a completed checkpoint. (#707) - Prevented corruption of
checkpoint_best_total.pthvia atomic checkpoint stripping. (#708) - Fixed PyTorch 2.9+ compatibility issue with CUDA capability detection. (#686)
- Fixed dtype mismatch error when
use_position_supervised_loss=True. (#447) - Fixed inconsistent return values from
build_model. (#519) - Fixed
positional_encoding_sizetype annotation (bool→int). (#524) - Fixed ONNX export
output_namesto include masks when exporting segmentation models. (#402) - Fixed
num_selectnot being updated correctly during segmentation model fine-tuning. (#399) - Fixed
np.argwhere→np.argmaxmisuse. (#536) - Fixed COCO sparse category ID remapping for non-contiguous or offset category IDs. (#712)
- Fixed segmentation mask filtering when using aggressive augmentations. (#717)
[1.4.3] — 2026-02-16¶
Changed¶
- Pretrained weight downloads validate against an MD5 checksum to detect corrupted files. (#679)
Fixed¶
- Fixed
deploy_to_roboflowfailing for segmentation model exports. (#578) - Fixed missing
infokey in COCO export format. (#681)
[1.4.2] — 2026-02-12¶
Added¶
- Added
generate_coco_dataset()utility for generating synthetic COCO-format datasets with configurable class counts, split ratios, and bounding box annotations. (#617) - Added
run_test=FalsetoTrainConfig— skip test-split evaluation when your dataset has no test set. (#628)
Changed¶
model.predict()accepts image URLs directly, with no need to download images before inference. (#629)- Plus models (
RFDETRXLarge,RFDETR2XLarge) are distributed as a separaterfdetr_pluspackage under the Roboflow Model License. (#645)
Fixed¶
- Fixed segmentation ONNX export failure. (#626)
[1.4.1] — 2026-01-30¶
Added¶
- Added native YOLO dataset format support alongside COCO. (#74)
- Added
--print-freqCLI argument to control training log frequency. (#603)
Changed¶
- Pinned
transformersto<5.0.0to prevent incompatibility with the transformers v5 API. (#599)
Fixed¶
- Fixed class count mismatch in
train_from_configfor Roboflow-uploaded datasets. (#588) - Improved
num_classesmismatch warning messages to be actionable rather than misleading. (#261) - Fixed CLI crash when specifying the
deviceargument. (#246)
[1.4.0] — 2026-01-22¶
Headline release introducing new pre-trained model sizes — L, XL, and 2XL for object detection, and the full N/S/M/L/XL/2XL range for instance segmentation. Also added YOLO format training support, simplified the dependency footprint by removing several heavy packages (cython, fairscale, timm, einops, and others), and fixed per-class precision/recall/F1 computation. Drops Python 3.9 support.