All notable changes to RF-DETR are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
RFDETR.predict(..., return_embeddings=True)now attaches a per-detection embedding vector asdetections.data["embeddings"](orkey_points.data["embeddings"]for keypoint outputs), shape(K, H), gathered with the same indices used for boxes/masks/keypoints — useful for downstream similarity search, clustering, or re-identification. On the eager (unoptimized) model this can be toggled perpredict()call. On a model optimized viamodel.inference(...), the exported/traced forward pass has fixed control flow, soinference()now also acceptsreturn_embeddingsand the value must be decided at optimization time and match thereturn_embeddingspassed topredict(); a mismatch raisesRuntimeError. -
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)
- Training now skips PyTorch Lightning's pre-training sanity validation batches by default; set
TrainConfig(num_sanity_val_steps=N)to restore it. Training loss component metrics are emitted once per epoch, with decoder and encoder auxiliary terms compacted intotrain/<term>_aux— 17 to 9 tracked metric keys per microbatch on the defaultRFDETRSmallconfig;train/losspreserves itstrain_log_on_stepbehavior, but component-level metrics no longer honortrain_log_on_stepby default — setTrainConfig(compact_train_metrics=False)to restore per-layer keys andtrain_log_on_stephonoring for them. Learning-rate metrics now emit only for optimizer updates, including a final partial gradient-accumulation window, cutting LR log calls by about 75% at the default accumulation of four. These are call-count reductions in Lightning's metric bookkeeping, not a measured timing or memory improvement. Update dashboard queries that consume layer-specific auxiliary keys or assume one learning-rate point per microbatch.
-
The default (torchvision-native) training pipeline no longer silently corrupts keypoint annotations when
keypoint_flip_pairsis empty on a schema that has genuine left/right pairs.RandomHorizontalFlipon this backend always mirrored keypoint x-coordinates when a flip was drawn, but only relabeled left/right jointsif self.keypoint_flip_pairs:— with an empty list (the pydantic default, and one possible outcome when automatic flip-pair inference from dataset metadata doesn't match 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 same 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 already harmless there since nothing needed relabeling; this fix disables it there too, for consistency with the Albumentations backend's existing 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. -
BestModelCallbackno longer treats 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 that sit outsideModelCheckpoint's owntrainer.sanity_checkingguard (the guard the regular-checkpoint path already inherits), so a positive sanity-check score — common when starting a new training run initialized withpretrain_weightsfrom a checkpoint pretrained on a different dataset — could get written out as the permanent "best"checkpoint_best_ema.pthbefore a single real epoch ran, and real training could then never surpass it. Note this is distinct from PTL's ownresume/ckpt_pathrestart, which PTL itself skips the sanity check for (not val_loop.restarting). (#1348)
HungarianMatcher's compact-path safety gate now computes its target-side half (box/label finiteness checks) once per training step instead of 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 now 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 now O(N log N) instead of 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 now collected unsynced across all images and resolved to Python booleans once, after every image's conversion, range check, and transfer have already 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 now 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 only ever needs at mostnum_queriesrows that survive selection, not every one of thesum(H*W)encoder positions. (#1334)PostProcessbox/mask/keypoint selection is now 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 same 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)
evaluate(split="test")on YOLO-format datasets now evaluates the realtest/split, instead of silently evaluatingvalid/. When no resolvabletestsplit exists, evaluation now 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 now 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)metrics.csvtraining history now survives 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 — wiping 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()call 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)SegmentationHead'sskip_blocksbranch now applies the learnedspatial_features_proj1×1 convolution before computing mask logits, matching the non-skip branch — the projection was previously skipped entirely on this path. 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 before this change, and the main decoder path was already projected too, sopredict()outputs and exported models are unchanged. Custom deployment decoders that consumesparse_forward'sspatial_featuresdict entry must not re-apply the projection themselves, since it is now applied upstream. (#1331)- Non-finite keypoint predictions no longer poison 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 itself now 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) batch_size="auto"probing now accounts for AdamW's optimizer-state memory (exp_avg/exp_avg_sq) via a shadow optimizer, instead of ignoring it — 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 now logged when a non-AdamW optimizer is configured, since the estimate no longer directly applies. The search loop now starts fromcandidate=2/lower_ok=1, instead of1/0. (#1342)- The ONNX Runtime export benchmark now honors 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) - Training metric plots now draw a legend on every subplot, instead of only the one titled "Loss". (#1335)
- The ONNX and TFLite reference decoders now mirror
PostProcess's multi-label selection instead of taking a per-queryargmax, which silently dropped legitimate detections whenever a query scored above threshold on more than one class. Both paths now 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 now handled correctly during debug logging. (#1320) - EMA training no longer performs an extra averaged-model update at epoch boundaries after the final optimizer step, preventing one update per epoch from bypassing
ema_update_intervaland changing the EMA trajectory. (#1319) model.export(format="tflite")no longer hangs 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. Because the TFLite route runs a full ONNX export before reachingonnx2tf, 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)
- Exported artifact filenames now 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 remain unchanged.
HungarianMatcher's detection-only cost matrix is now built padded to each batch'smax(T_i)target count and diagonal-extracted, instead of padding 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 now 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 instead of one per image. (#1297, #1281, #1312)seed_all()now 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 instead of the device. (#1276)
- Keypoint decode skips redundant CUDA presence checks in postprocessing. (#1282)
- Loading a detection checkpoint published before keypoint support no longer warns 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 now recorded at debug level. (#1302) - 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) now restores per-callback state instead of silently restarting it cold. Those files intentionally omit optimizer/LR-scheduler state, and a warning now 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) - Training-time log calls no longer corrupt or duplicate 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) - An index-less
torch.device("cuda")is normalised to the current device index before the deferred-move guard compares it against a placed parameter's device — previously the comparison never matched an indexed device likecuda:0, so every call re-moved every parameter. (#1311) - The legacy query-embedding fallback now only warns when it actually truncates weights, instead of on every load. (#1301)
- Under
eval_ema_only, a run previously logged 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) ModelContext.reinitialize_detection_head()now raises a clearRuntimeErrorinstead of anAttributeError: 'NoneType'afterRFDETR.inference(inplace=True)has cleared the weights, and does so beforeargs.num_classesis mutated so a rejected call cannot leave the context half-updated. (#1283)evaluate()now builds its datamodule from the resolution-override config. (#1280)
- COCO datasets that contain 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 it 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 (the existing class-countUserWarningfires); retrain. Passingnum_classesexplicitly preserves the checkpoint's N+1-class head width so the weights still load, but it 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)
PostProcessnow selects boxes, masks, and keypoints withindex_select/expandinstead of materialising a repeatedint64gather index — an allocation that reached 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 scales with image area, and is 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)
keypoint_flip_pairsno longer silently disables 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)- Export inference and INT8 calibration now resize with
RFDETR.predict()'s exact convention (bilinear, half-pixel centers,antialias=False) across the ONNX inference, TFLite inference, INT8 TFLite calibration, and benchmark/traced-example paths. These paths previously resized through PIL's antialiased BILINEAR/BICUBIC filters, which diverge frompredict()on downscale and shift exported-model confidence scores and INT8 calibration ranges. 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) pip install 'rfdetr[onnx]'on Python 3.10 andpip install 'rfdetr[executorch]'on Python 3.14 no longer fail during install. Each extra previously resolved to a version (onnxruntime,executorch) that ships no wheel for that interpreter and has no source distribution to fall back on; the extras are now gated to interpreters that publish wheels. (#1267)- The Kornia augmentation builders (
GaussianBlur,GaussNoise) accept either a scalar or a(min, max)pair for range parameters, matching the Albumentations path. A customaug_configthat is valid under Albumentations no longer raises a bareTypeErrorwhenaugmentation_backend="cpu"/"auto"resolves to Kornia (Kornia installed and CUDA available). (#1255) uv syncnow resolves the development environment cleanly; anexecutorch/tfliteextra conflict previously blocked.venvcreation. (#1253)
- 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)
- Default dataset augmentations now 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)
- 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. Previously, disabling this branch 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 happen to be installed.AugmentationBackendnow only holds concrete, directly-usable backends (TV,ALBU,KORNIA);"cpu"/"auto"remain acceptedaugmentation_backendinput strings (resolved lazily at dataset-build time, keeping 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 (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.
TrainConfig.lr_dropandlr_min_factor— pass them throughlr_scheduler_kwargsinstead ({"lr_drop": ...}/{"min_factor": ...}). Deprecated since v1.9.0, will be removed in v1.11.0. The fields still work in the meantime 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.
- Keypoint L1-loss helper (
compute_l1_keypoint_loss) now returns graph-connected zeros on its out-of-schema class-index guard instead of detachednew_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. - Non-square Albumentations training resize (
aug_configset,augmentation_backendresolving to"albumentations") no longer silently inflates 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. - Explicit
augmentation_backend="albumentations"now raises a clearImportErrorimmediately if Albumentations is not installed, instead of resolving successfully and failing later, deep in dataset construction. RFDETR.from_checkpoint(..., trust_checkpoint=True)now actually works. 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, sotrust_checkpoint=Truehad no effect on checkpoints that genuinely needed it and raised the sameRuntimeErrorit was supposed to bypass. (#1239)- Segmentation evaluation resized 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)
pip install 'rfdetr[onnx]'(and[tflite]) no longer hangs 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)
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, will be removed in v1.11.0.
- Matched-pair IoU targets in the classification/matching losses now 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. It's only needed 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)
RFDETR.from_checkpoint()now 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 sametrust_checkpointflag. (#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)
[kornia]extra removed — GPU-side augmentation now 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.
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)
- Horizontal flip detection in
AlbumentationsWrappernow uses AlbumentationsReplayComposereplay metadata instead of heuristic bbox-center mirroring; eliminates false positives on non-flip transforms that shift box centers. Falls back toalb.Composewith aUserWarningwhenalbumentations <1.3is detected. (#1164) - Keypoint schema inference now 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 to prevent cross-format cache collisions when the same directory is used with different dataset formats. (#1164)
- Predicted bounding boxes are now clamped to image bounds
[0, width] × [0, height]inPostProcess._postprocess_boxes(); model regression is unbounded and could previously produce negative or out-of-frame coordinates.scale_fctis also cast toboxes.dtypebefore multiplication to prevent dtype mismatch when boxes arefloat16. (#1168) SegmentationTrainConfig.cls_loss_coefdefault corrected from5.0to1.0to restore the pre-v1.7 effective classification loss weight. The5.0value was present inSegmentationTrainConfigsince v1.6 but was 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)KeypointTrainConfig.keypoint_nll_loss_coefdefault 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)
- 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(and 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"(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)
- 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)
RFDETR.from_checkpoint()now correctly infersnum_classesandnum_keypoints_per_classfrom checkpoint weights (class_embed.weight.shape[0] - 1and_kp_active_maskrespectively). Previously,num_classeswas read asshape[0](i.e.num_classes + 1including the background class), causingload_state_dictshape mismatches or a silent extra output class on every load.BestModelCallback._serialize_model_configis also fixed to persist the correct foreground-onlynum_classes. (#1158)HungarianMatcher.forward()now uses the configuredfocal_alphain the focal classification matching cost. Previously the value was hardcoded to0.25, silently ignoring any non-defaultfocal_alphapassed to the constructor orbuild_matcher. This misaligned the bipartite matching cost with the focal classification loss incriterion.py, which correctly usedself.focal_alpha. (#1147)spatial_shapesinTransformer.forward()is now built from symbolicShapeops (torch.stackof per-leveltorch._shape_as_tensorslices) instead oftorch.empty+ in-place index assignment. The previous pattern emitted aScatterNDfeeding a shape tensor (level_start_index), which TensorRT rejected with "IScatterLayer cannot be used to compute a shape tensor". This fix is required to export any RF-DETR model to a TensorRT engine. (#1155)- Keypoint model inference now returns the correct
class_namefield in predictions. (#1151) predict()now re-asserts eval mode before each call for unoptimized models, preventing silent train-mode inference after the first prediction. (#1146)- TFLite inference preprocessing and mask decoder aligned with PyTorch
predict()behaviour. (#1131) - Python version mismatch in optional-dependency version overrides resolved. (#1137)
- Config path parameters (e.g.
dataset_dir,output_dir,pretrain_weights) now acceptpathlib.Pathobjects in addition to strings. Paths are coerced tostrautomatically via theexpand_pathsvalidator. No API changes required; existing string usage unaffected. (#1124) - Keypoint training now disables horizontal flip augmentation until keypoint flip-pair swapping is implemented. Previously, flipping was 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)
- Keypoint encoder in eval mode now routes all queries through head 0 instead of splitting across group heads. Previously,
group_detr = len(self.enc_out_keypoint_embed)caused the encoder keypoint path to splitnum_queriesqueries across all group heads in eval; now usesif self.training else 1guard. (#1135) config.use_return_dict(deprecated intransformers) replaced withconfig.return_dictin DINOv2 windowed attention backbone. (#1135)- Epoch metric tables now display correctly when a Rich progress bar callback is active. Tables are printed through the progress bar's owned Rich console, preventing cursor conflicts with active live displays. (#1128)
- Keypoint fine-tuning checkpoint selection stabilised with smoothed (EMA) best-metric comparison to avoid spurious checkpoint switches on noisy OKS metrics. Smoothing state is correctly restored on training resume. (#1122)
- Group DETR train-time metric evaluation now evaluates only the primary query group, preventing crashes on non-tensor mask outputs from auxiliary decoder layers. (#1122)
_detect_horizontal_flipin Albumentations transform pipeline now useslen(bboxes) == 0instead ofnot bboxesto correctly handle Albumentations 2.x where bboxes is a NumPy array (falsy even when non-empty). (#1126)- TensorBoard logger is now disabled gracefully when
tensorboardis installed alongside a NumPy-2.0-incompatibletensorflow. Training degrades to CSV-only logging with a clear warning instead of crashing inside_log_hyperparams. (#1123)
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)
- DDP strategy now enables
find_unused_parameters=Truefor all detection, keypoint, and segmentation models when running understrategy='ddp'orstrategy='auto'with a distributed launcher. Previously only enabled for segmentation. 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 torfdetr.datasets.aug_configs; the augmentation preset constants (AUG_AGGRESSIVE, etc.) are unchanged. (#1103)
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)
RFDETR.from_checkpoint()no longer treatsnum_classesloaded from the checkpoint as a user-supplied override. Previously, fine-tuning a checkpoint model on a dataset with a different class count was silently refused — 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)- Scale jitter restored in non-square training crop.
RandomCropin theoption_bbranch replaced withRandomSizedCrop, restoring the scale-augmentation behaviour lost during the Albumentations migration. (#1088) - Multi-GPU validation deadlock in COCO mAP synchronization prevented.
_merge_metric_state_across_ranksnow safe across zero-batch ranks. (#1085) import rfdetrno longer fails on NumPy 2.x when a transitive dependency references the removednp.complex_alias. (#1064)rfdetr_plusmodule availability check corrected; false-positive hit when the package was partially installed. (#1083)- Fixed 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) - Loss scaling corrected for keypoint training under gradient accumulation (
accumulate_grad_batches > 1). Keypoint models now 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) - Device auto-detection now verifies accelerator runtime availability before selecting a device (PyTorch ≥ 2.4:
torch.accelerator.current_accelerator; older builds:torch.cuda.is_available()). Previously, a machine with CUDA headers but no GPU driver could be assigned a CUDA device that fails at first use. (#1111) RFDETR.from_checkpoint()and related APIs now honor an explicitnum_classesargument even when its value equals the model default. Previously, passingnum_classes=NwhereNis the default (e.g. 80 for COCO) was silently treated as unset, causing fine-tuning on a different class count to be refused. (#1109)RFDETR.from_checkpoint()correctly infers the model variant from the checkpoint filename whenpretrain_weightsis absent or unset-like (empty string,None, whitespace). Previously, starter-like checkpoints without an explicitpretrain_weightsentry raised an error or silently loaded the wrong model class. (#1065)
augmentation_backendfield onTrainConfig("cpu"/"auto"/"gpu"): opt-in GPU-side augmentation via Kornia applied inRFDETRDataModule.on_after_batch_transferafter the batch is resident on the GPU. CPU path is unchanged and remains the default. Install withpip install 'rfdetr[augment]'. Supports detection and segmentation (see below). (#1003)- Kornia GPU augmentation now supports instance segmentation: images, boxes, and per-instance masks are augmented in sync on the GPU. New public helper
collate_maskspacks[N_i, H, W]boolean masks into a[B, N_max, H, W]float32 tensor for Kornia;build_kornia_pipelinegains awith_masks: bool = Falseparameter;unpack_boxesgains an optionalmasks_augtensor that re-binarises and filters masks in sync with boxes. Previouslyaugmentation_backend="gpu"/"auto"was silently ignored for segmentation models; now it works identically to detection. Note: the mask buffer is[B, N_max, H, W]float32 — approximately 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"]; set toFalseto reduce memory use when the image is not needed for annotation. (#912)model_nameis now stored in checkpoint files during training so thatRFDETR.from_checkpoint()can resolve the correct model class directly from the checkpoint, without requiring the caller to know or pass a class hint.strip_checkpoint()preserves this key. Backward-compatible: checkpoints withoutmodel_namecontinue to resolve viapretrain_weightsfilename matching. (#895)rfdetr_versionis now stored in checkpoint files during training for provenance tracking and compatibility hints.strip_checkpoint()preserves this key. The key is omitted gracefully when the package version cannot be resolved (e.g. editable install without metadata). Backward-compatible: checkpoints withoutrfdetr_versioncontinue to 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 model weights are cached (default:~/.roboflow/models). Bare filenames passed aspretrain_weights(e.g."rf-detr-base.pth") are now resolved relative to this directory; paths with a directory component are used as-is with parent directories created automatically. (#130)- Grayscale and multispectral imagery support: RF-DETR models now accept inputs with any number of channels (not just 3). The pretrained DINOv2 patch-embedding weights are automatically adapted to the specified channel count at model construction time — no additional dependencies required. (#180, closes #75)
- Training configuration is now saved to
training_config.jsonin the output directory after training completes. The file captures the fullTrainConfig,ModelConfig, effective training parameters, class names, and number of classes — useful for reproducibility and debugging predictions from older checkpoints. (#194) dinov2_registers_windowed_smallbackbone is now 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 requiring the caller to specify a class. Equivalent toRFDETR.from_checkpoint(path)but importable directly from therfdetrpackage. (#664)- ONNX export filenames now 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 (images without a matching label file) are now included in YOLO detection datasets as empty-detection samples instead of being silently dropped. Both detection and segmentation paths now use
_LazyYoloDetectionDatasetfor consistent behaviour. (#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 now accepted aspretrain_weights. Keys are automatically normalized from PTL format (state_dictwithmodel.-prefixed keys,hyper_parameters→args) so thatload_pretrain_weights, class-name extraction, and compatibility checks work without 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 now decodes segmentation mask outputs into
sv.Detections.mask. Mask logits are upsampled to the source image size using Pillow bilinear resampling and thresholded at zero, matching the behaviour ofPostProcess.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)
peftis no longer installed as part of the defaultrfdetrpackage. It has moved to the[lora]and[train]optional extras. If you use LoRA fine-tuning, install withpip install 'rfdetr[lora]'. (#838)- Native RLE annotation support in the COCO segmentation pipeline:
convert_coco_poly_to_masknow explicitly 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)
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. It will be removed in v1.9 and currently emits aDeprecationWarningon use. (#845)load_pretrain_weights(nn_model, model_config, train_config)— thetrain_configpositional argument is deprecated and will be removed in v1.9; it is no longer used internally. Omit it:load_pretrain_weights(nn_model, model_config). Passing a non-Nonevalue emits aDeprecationWarning. (#845)TrainConfig.group_detr(architecture decision →ModelConfig),TrainConfig.ia_bce_loss(loss type tied to architecture family →ModelConfig),TrainConfig.segmentation_head(architecture flag →ModelConfig),TrainConfig.num_select(postprocessor count →ModelConfig;SegmentationTrainConfigusers: remove thenum_selectoverride — the model config value is always used),ModelConfig.cls_loss_coef(training hyperparameter →TrainConfig) — each now emitsDeprecationWarningwhen set on the wrong config object and will be removed in v1.9. (#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 and will be removed in v1.9. A__getattr__hook on therfdetrpackage now emits a clearImportErrorwith migration guidance when these legacy paths are accessed. (#839)
-
Fixed TFLite export (
format="tflite") producing detection scores that collapse to ~0.02 (vs ~0.62 from ONNX) on real inputs. Root cause is a long-standing onnx2tf bug (PINTO0309/onnx2tf#274) where theGridSamplelowering diverges numerically from ONNX while onnx2tf's own validator silently passes. RF-DETR's deformable cross-attention usesF.grid_sampleonce per decoder layer; drift compounds and is amplified by the attention softmax. The converter now detects onnx2tf'sGridSample → pseudo-GridSamplereplacement kwarg at runtime (introspectingconvert()viainspect.signature) and passes it asTrue; a warning is logged when the kwarg is absent. (#1041) -
WindowedDinov2WithRegistersEmbeddings.forward()now raisesValueError(instead of silently failing under-O) when input spatial dimensions are not divisible bypatch_size * num_windows, with a clear message identifying the divisor and actual shape. (#167) -
Fixed
_namespace.py:num_selectin the builder namespace now always reads fromModelConfig, eliminating a regression whereTrainConfig.num_select(default 300) silently overrode model-specific values of 100–200 for segmentation variants (RFDETRSegNano,RFDETRSegSmall,RFDETRSegMedium,RFDETRSegLarge,RFDETRSegPreview). Post-processing now uses the correct top-k count for each model. (#841) -
Fixed
models/weights.py:load_pretrain_weightsnow correctly auto-aligns the model head when the checkpoint has fewer classes than the configured default, preventing a silent mismatch whennum_classeswas not explicitly set by the caller. (#845) -
Fixed
models/weights.py:load_pretrain_weightsnow slicesrefpoint_embed.weightandquery_feat.weightper-group when reshaping checkpoint queries, instead of taking a flattensor[: num_queries * group_detr]slice. The flat slice silently scrambled groups 1+ whennum_queriesdecreased andgroup_detr > 1; inference (which only reads group 0) was unaffected, but training-resume corrupted query embeddings for groups 1 onward. (#1019) -
Fixed YOLO segmentation training on large datasets hitting OS out-of-memory:
supervision.DetectionDataset.from_yolo(force_masks=True)was eager-rasterising H×W boolean masks for every image at dataset construction time (≈1 GB/1 000 images at 1024 px). A new_LazyYoloDetectionDatasetstores polygon coordinates only and defers dense mask rasterisation to__getitem__, keeping RAM proportional to annotation count rather than (N × H × W). (#851) -
Fixed ONNX/TRT dynamic batch inference:
gen_encoder_output_proposalsandTransformer.forwardextracted the batch size as a Python int and passed it totorch.full,.view(N_, ...),.expand(N_, ...), and.repeat(bs, ...), causing the ONNX tracer to bake the training batch size (e.g. 8) as a compile-time constant. TRT engines built with--minShapessmaller than the trace batch would fail at inference withReshape: reshaping failed. All six call sites are now replaced with ONNX-symbolic equivalents (zeros_like,-1reshapes,expand(memory.shape[0], ...)), keeping the batch dimension fully dynamic. (#950, closes #949) -
Fixed training failure when
square_resize_div_64=False: the non-square resize pipeline (SmallestMaxSize+LongestMaxSize) did not guarantee output dimensions divisible bypatch_size * num_windows, causingWindowedDinov2WithRegistersEmbeddings.forwardto raiseValueError. APadIfNeededstep (withpad_height_divisorandpad_width_divisorset topatch_size * num_windows) is now appended after the resize pair in both the train and val/test pipelines. (#991, closes #983) -
Fixed non-square batch padding correctness: batch-level
block_sizerounding is now applied in the DataLoader collator (nested_tensor_from_tensor_listviamake_collate_fn) in addition to the transform-levelPadIfNeeded, ensuring divisibility bypatch_size * num_windowssurvives anyComposereordering and applies uniformly to custom evaluation harnesses. (#992) -
Fixed
RFDETRModelModule.on_load_checkpointcrashing withRuntimeErrorwhen resuming training from a checkpoint saved at a different image resolution: DINOv2 positional embeddings in the checkpoint are now bicubic-interpolated to matchmodel_config.positional_encoding_sizebefore PyTorch Lightning applies the state dict. (#1002, closes #998) -
Fixed
RFDETRLargeinitialization showing two conflictingValueErrors (forpatch_size=14andpatch_size=16) when the deprecated-config fallback retry also fails. The fallback now re-raises the original error without chained context, so users see a single deterministic message. (#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).train(...)). The training entry path now delegates to the canonicalload_pretrain_weightshelper, which bicubic-interpolates the DINOv2 positional embeddings beforeload_state_dict. (#1040, closes #1038, #1023) -
Fixed TFLite detection scores collapsing for all queries (scores ~0.02 vs ~0.62 from ONNX) when
GridSamplewas used as an onnx2tf pseudo-operator. TheGridSampleONNX node is now rewritten toGather-based integer-index arithmetic before conversion, eliminating all numerical drift from attention position sampling. This supersedes the pseudo-GridSampleruntime-kwarg approach added in #1041. (#1054) -
Fixed
class_namelookup for pretrained COCO models: COCO category IDs are sparse (1–90 with gaps for 80 classes), so flat 0-based indexing returned the wrong name (e.g.class_id=18("dog") incorrectly returnedclass_names[18]instead ofclass_names[16]). Detection now uses acoco_id → class_namemapping built from the canonicalCOCO_CLASSESlist so every COCO category resolves to its correct label. Fine-tuned models continue to use direct 0-based indexing unchanged. (#1051)
predict()now stores the source image indetections.metadata["source_image"]instead ofdetections.data["source_image"]. supervision indexes every value indataby the detection mask;source_imageis per-image, not per-detection, so boolean/integer indexing raisedIndexError. Moving it tometadata(passed through unchanged) fixes the issue. Update any code that readsdetections.data["source_image"]. (#972, #968)
- Fixed segmentation training crash on T4 and P100 GPUs: cuDNN engine selection fails for depthwise convolution backward on some CUDA stacks (Kaggle, Colab). A custom
autograd.Functionnow disables cuDNN in both forward and backward passes. (#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 pretrained weight loading crash with custom resolution: DINOv2 positional embeddings are now bicubic-interpolated to match the target grid before
load_state_dict. (#964) - Fixed
validate_checkpoint_compatibilityproducing a crypticRuntimeErroronpatch_sizemismatch when checkpoint lacks explicitargs.patch_size. The function now inferspatch_sizefrom the DINOv2 projection weight shape and raises a descriptiveValueError. (#971) - Fixed
predict()storingdetections.data["source_shape"]as a Pythontuple, which causedTypeErrorwheneversv.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 now mapdata["class_name"]to"__background__"without any warning. (#970)
predict()now includesclass_nameindetections.data, mapping each detection's 0-indexed class ID to its human-readable name. (#914)
- Fixed segmentation multi-GPU DDP training crash:
build_trainer()now wrapsstrategy="ddp"withDDPStrategy(find_unused_parameters=True)whensegmentation_head=True. The segmentation head'ssparse_forward()leaves parameters unused on some forward steps; plain"ddp"raisedRuntimeError: It looks like your LightningModule has parameters that were not used in producing the loss. Non-segmentation DDP and other strategies are unchanged. (#942, #947) - Fixed fused AdamW crash under FP32 multi-GPU training:
configure_optimizers()andclip_gradients()now gate fused AdamW on the trainer's actual precision (requiring a BF16 variant) rather than GPU capability alone. On Ampere+ hardwaretorch.cuda.is_bf16_supported()is alwaysTrue, so the old code enabled fused AdamW even withprecision="32-true", causingRuntimeError: params, grads, exp_avgs, and exp_avg_sqs must have same dtype, device, and layoutfrom DDP gradient bucket view stride mismatches. (#942, #947) - Fixed multi-GPU DDP training crashing in Jupyter notebooks and Kaggle: replaced fork-based
ddp_notebookstrategy with a spawn-based DDP strategy that avoids OpenMP thread pool corruption afterfork(). (#928) - Fixed
RFDETR.train(resolution=...)being silently ignored — the kwarg is now 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 now 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 now padded to an exact multiple of
effective_batch_size * world_size, ensuring 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) download_pretrain_weights()no longer overwrites fine-tuned checkpoints that share a filename with a registry model (e.g.rf-detr-nano.pth). Previously, an MD5 mismatch would fall through to_download_file()and silently replace the user's weights with the original COCO checkpoint. The function now returns early whenever the file exists andredownload=False, regardless of MD5 status — a warning is emitted when the hash differs. Passredownload=Trueto force a fresh download. (#935)
predict()now 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)where each row is[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()now accepts dtype as a string name (e.g."float16") in addition to atorch.dtypeobject; invalid dtype inputs uniformly raiseTypeError. (#899)
- Fixed
models/lwdetr.py:reinitialize_detection_headnow replacesnn.Linearmodules instead of mutating.datatensors in-place, ensuringout_featuresmetadata stays consistent with the actual weight shape. This prevents ONNX export andtorch.jit.tracefrom emitting stale (pre-fine-tuning) 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 now 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 now 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 PyTorch Lightning migration:class_names.txtis now written to the upload directory andargs.class_namesis populated before saving the checkpoint. (#890)
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)
ModelConfig.deviceandRFDETR.train(device=...)now 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 ONNX export ignoring an explicit
patch_sizeargument:export()andpredict()now 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 — replaced
H_.expand(N_)withtorch.fullfor Python-int spatial dims to eliminate tracer failures. (#871)
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. They will be removed in v1.8. (#861)
- Fixed
RFDETR.train(): a missingrfdetr[train]install (e.g. plainpip install rfdetrin Colab) now raises anImportErrorwith an actionable message —pip install "rfdetr[train,loggers]"— instead of a rawModuleNotFoundErrorwith no install hint. (#858) - Fixed
AUG_AGGRESSIVEpreset:translate_percentwas(0.1, 0.1)— a degenerate range that forced AlbumentationsAffineto always translate right/down by exactly 10%. Corrected to(-0.1, 0.1)for symmetric bidirectional translation. (#863) - Fixed PTL training path:
latest.ckptand per-interval checkpoints (checkpoint_interval_N.ckpt) are now properly written and restored on resume. (#847) - Fixed
BestModelCallbackand checkpoint monitor raisingMisconfigurationExceptionon non-eval epochs wheneval_interval > 1— monitor key absence is now handled gracefully. (#848) - Fixed
protobufversion constraint in theloggersextra to guard against 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)
- PyTorch Lightning training building blocks:
RFDETRModelModule,RFDETRDataModule,build_trainer(), and individual callbacks (RFDETREMACallback,COCOEvalCallback,BestModelCallback,DropPathCallback,MetricsPlotCallback) — all standard PTL components, swap/subclass/extend any piece. Level 3:rfdetr fit --configCLI with 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.
- Breaking: Minimum
transformersversion bumped to>=5.1.0,<6.0.0. The DINOv2 windowed-attention backbone now 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_shapenow returnsTuple[np.ndarray, List[float]]instead ofnp.ndarray. The second element is a flat COCO-style polygon list[x1, y1, x2, y2, …]. Any caller that previously 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 automatically adapted to the 2.xsize=(height, width)API. (#786) - Current learning rate is now shown in the training progress bar alongside loss. (#809)
supervision,pytorch_lightning, and other heavy dependencies are now imported lazily (on first use) rather than at module load, reducing cold-import time in inference-only environments. (#801)
rfdetr.deploy.*— redirects torfdetr.export.*with aDeprecationWarning. Migrate before v1.7.rfdetr.util.*— redirects torfdetr.utilities.*with aDeprecationWarning. Migrate before v1.7.
- Raised a descriptive
ValueErrorinstead of a crypticRuntimeError/ tensor-size mismatch when a checkpoint is incompatible with the current model architecture — coverssegmentation_headmismatch andpatch_sizemismatch. (#810) - Fixed
class_namesnot reflecting dataset labels onmodel.predict()after training — class names are now 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 now fires only in the backbone-pretrain scenario. (#815, #509) - Fixed
grid_sampleand bicubic interpolation silently falling back to CPU on MPS (Apple Silicon) — both now run natively on the MPS device. (#821) - Fixed
early_stopping=FalseinTrainConfigbeing silently ignored — the setting now propagates correctly. (#835) - Fixed
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 now accepted. (#777) - Silently dropped degenerate bounding boxes (zero width or height) before Albumentations validation instead of raising
ValueError. (#825)
- Added peak GPU memory (
max_memin MB) to training and evaluation progress bars on CUDA; omitted on CPU and MPS. (#773)
- 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
AttributeErrorcrash inupdate_drop_pathwhen the DINOv2 backbone layer structure does not match any known pattern —_get_backbone_encoder_layersnow returnsNonefor unrecognised architectures. (#762) - Fixed
drop_path_ratenot being forwarded to the DINOv2 model configuration; 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)
- Added support for nested Albumentations containers (
OneOf,Sequential) insideaug_config. (#752)
- Migrated dataset transform pipeline to torchvision-native
Compose,ToImage, andToDtype;Normalizenow defaults to ImageNet mean/std. (#745)
- Fixed
RFDETRMediummissing from the public API —__all__contained a duplicateRFDETRSmallentry. (#748) - Fixed
AR50_90reporting an incorrect value inMetricsMLFlowSinkdue to a wrong COCO evaluation index. (#735) - Fixed supercategory filtering in
_load_classesfor COCO datasets with flat or mixed supercategory structures. (#744) - Fixed crash in geometric transforms when a sample contained zero-area or empty masks. (#727)
- Fixed segmentation training on Colab —
DepthwiseConvBlocknow disables cuDNN for depthwise separable convolutions. (#728) - Pinned
onnxsim<0.6.0to preventpip installfrom hanging indefinitely. (#749)
- 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) ModelConfignow raises an error on unknown parameters, preventing silent misconfiguration. (#196)
- Deprecated
OPEN_SOURCE_MODELSconstant in favour ofModelWeightsenum. (#696) - Added MD5 checksum validation for pretrained weight downloads. (#679)
- 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)
- Pretrained weight downloads now validate against an MD5 checksum to detect corrupted files. (#679)
- Fixed
deploy_to_roboflowfailing for segmentation model exports. (#578) - Fixed missing
infokey in COCO export format. (#681)
- 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)
model.predict()now accepts image URLs directly — no need to download images before inference. (#629)- Plus models (
RFDETRXLarge,RFDETR2XLarge) are now distributed as a separaterfdetr_pluspackage under the Roboflow Model License. (#645)
- Fixed segmentation ONNX export failure. (#626)
- Added native YOLO dataset format support alongside COCO. (#74)
- Added
--print-freqCLI argument to control training log frequency. (#603)
- Pinned
transformersto<5.0.0to prevent incompatibility with the transformers v5 API. (#599)
- 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)
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.