Skip to content

Migration Guide

Read each section between your current version and your target — every section covers only the delta between two adjacent releases.

1.4.x  →  1.5 →  1.6  →  1.7  →  1.8  →  1.9  →  1.10

You can apply all changes in one go; working through sections one release at a time and verifying between each step is optional but makes failures easier to isolate. Deprecated APIs emit a DeprecationWarning, while deprecated configuration fields emit a FutureWarning, until the version marked for removal. See the Changelog for the full list of changes in each release.


Upgrade 1.9 → 1.10

Breaking changes

Breaking: log_per_class_metrics now defaults to False

TrainConfig.log_per_class_metrics defaults to False (was True). Per-class AP keys (test/AP/<class>, val/AP/<class>) are no longer emitted by default — validation/test now skip that per-class computation. Set it explicitly to restore the old behavior:

train_config = TrainConfig(log_per_class_metrics=True)

Breaking: compute_val_loss now defaults to \"auto\"

TrainConfig.compute_val_loss defaults to "auto" (was True). In "auto" mode, validation loss is computed only when something actually consumes it — a ReduceLROnPlateau scheduler monitoring val/loss, or a callback (e.g. ModelCheckpoint(monitor="val/loss"), early stopping) that requires it — and is skipped otherwise. For a default run with no such consumer, val/loss no longer appears in metrics.csv, TensorBoard, or W&B. Set it explicitly to restore the old unconditional behavior:

train_config = TrainConfig(compute_val_loss=True)

Breaking: validation evaluates one model, and val/mAP_* follows it

Validation now runs one forward pass per batch instead of two: through the EMA weights when use_ema=True (the default), through the base weights otherwise. val/mAP_50_95, val/mAP_50, val/mAP_75, val/mAR, and per-class val/AP/<class> therefore report the EMA model on a default run — they used to report the base model — while the matching val/ema_* namespace remains available. Best-checkpoint selection is unaffected in substance (it already preferred EMA), but the "regular" track no longer writes checkpoint_best_regular.pth on such runs; checkpoint_best_total.pth is copied from the EMA checkpoint.

val/F1 and val/loss (when computed) follow the same single forward, so they now describe the EMA model too — consistent with the mAP under the primary key, but a change of meaning if you monitor val/loss with a ReduceLROnPlateau scheduler, ModelCheckpoint, or early stopping.

Restore the previous two-forward behavior, both metric namespaces and both checkpoint tracks:

train_config = TrainConfig(eval_base_model=True)

Breaking: grad_accum_steps now defaults to 1

TrainConfig.grad_accum_steps defaults to 1 (was 4), which changes the default effective batch size from 16 to 4 at the default batch_size=4. This is a training-semantics change, not just a throughput change — the optimization trajectory (and possibly convergence/final mAP) can differ from a run using the old default. batch_size="auto" runs are unaffected, since the auto-batch probe overwrites grad_accum_steps with its own recommendation. Restore the previous default:

train_config = TrainConfig(grad_accum_steps=4)

Breaking: optimizer parameter groups are now merged by hyperparameter

get_param_dict now builds one parameter group per distinct learning-rate/weight-decay combination instead of one group per parameter (rfdetr-nano goes from 465 groups to 28). Layer-wise LR decay and per-parameter weight decay are preserved, and the resulting AdamW steps are bit-identical; checkpoints saved with the old per-parameter layout resume automatically. If you pass an explicit lr_scheduler whose lr_scheduler_kwargs include a list sized to a specific parameter-group count (e.g. LambdaLR's per-group lr_lambda), resize that list to match the new (smaller) group count.

Breaking: dataset builders require a complete pipeline-option namespace

build_roboflow_from_coco, build_roboflow_from_yolo, and build_o365_raw now raise instead of silently substituting a default when the config namespace passed to them is missing square_resize_div_64, segmentation_head, multi_scale, expanded_scales, do_random_resize_via_padding, patch_size, or num_windows (build_o365_raw doesn't take segmentation_head — detection-only). Calling these with a complete TrainConfig/ModelConfig (the normal .train()/RFDETRDataModule path) is unaffected — this only affects callers who assemble a partial config namespace by hand and pass it to these builders directly. Supply every field on that namespace to fix it:

# Before — missing fields silently fell back to (sometimes wrong) defaults
build_roboflow_from_coco(args=partial_namespace)

# After — supply every pipeline option the builder needs, matching your
# model variant's ModelConfig (patch_size varies by variant — 12, 14, or
# 16 — read it from your ModelConfig rather than hardcoding it)
partial_namespace.square_resize_div_64 = True
partial_namespace.segmentation_head = False
partial_namespace.multi_scale = True
partial_namespace.expanded_scales = True
partial_namespace.do_random_resize_via_padding = False
partial_namespace.patch_size = model_config.patch_size
partial_namespace.num_windows = model_config.num_windows
build_roboflow_from_coco(args=partial_namespace)

Deprecated in v1.10 → Remove in v1.13

eval_ema_only is deprecated

Evaluating only the selected model is the default. Explicit legacy TrainConfig(eval_ema_only=True) preserves EMA-only evaluation and emits a FutureWarning; explicit eval_ema_only=False is migrated to the old base-plus-EMA behavior and also warns. Drop the field from new configurations. Use eval_base_model=True if you want the base model evaluated as well; eval_ema_only=True still requires use_ema=True and conflicts with that opt-in.

One improvement for existing eval_ema_only users: val/mAP_50_95 is now populated (with the EMA score) instead of staying absent, so monitors pointed at it start receiving values again.


Upgrade 1.8 → 1.9

Breaking changes

Breaking: albumentations and kornia extras merged into augment

PyPI extras renamed. Default training/validation/prediction/export augmentations now use torchvision-native transforms, so [train] no longer installs Albumentations. Custom CPU (Albumentations) and GPU (Kornia) augmentation both live behind a single new augment extra.

Old extra New extra
rfdetr[train] (implied albumentations) rfdetr[train,augment]
rfdetr[kornia] rfdetr[augment]
# Before
pip install 'rfdetr[train]'    # bundled albumentations
pip install 'rfdetr[kornia]'

# After
pip install 'rfdetr[train,augment]'   # custom aug_config or GPU backend
pip install 'rfdetr[augment]'

augmentation_backend values renamed

augmentation_backend="tv" and "albu" are renamed to "torchvision" and "albumentations". The old strings (and "gpu") still work as aliases, so no code changes are required — see Augmentation Backend Values for the full accepted set.

Breaking: default resize interpolation changed — pixel values and mAP may shift

The default resize backend changed from Albumentations (cv2 INTER_LINEAR, no antialias) to torchvision (BILINEAR + antialias=True). Resized pixel values differ slightly from previous versions, and mAP may drift on existing benchmarks. This affects training as well as validation and test preprocessing — not just the training split.

To restore the previous pixel-exact behaviour:

pip install 'rfdetr[augment]'
from rfdetr.datasets.aug_configs import AUG_CONFIG

train_config = TrainConfig(aug_config=AUG_CONFIG)

Installing rfdetr[augment] alone is not sufficient to pin this behaviour — with Albumentations installed, augmentation_backend="auto"/"cpu" (the default) auto-selects Albumentations for you, but identical code on a machine without [augment] installed silently falls back to torchvision instead. The only setting that pins resize behaviour regardless of what is installed is:

train_config = TrainConfig(augmentation_backend="torchvision")

Removed

The following APIs were deprecated in earlier releases and are removed as of v1.9. Update your code before upgrading.

Removed: rfdetr.util.* and rfdetr.deploy.* import paths

Deprecated since v1.6, removed in v1.9. Use the canonical replacements listed in the Upgrade 1.5 → 1.6 section.

# These imports now raise ImportError; update to the canonical paths
from rfdetr.util.coco_classes import COCO_CLASSES  # → rfdetr.assets.coco_classes
from rfdetr.util.misc import get_rank  # → rfdetr.utilities
from rfdetr.deploy import export_onnx  # → rfdetr.export.main

Removed: build_namespace(model_config, train_config)

Deprecated since v1.7, removed in v1.9. Use build_model_from_config and build_criterion_from_config instead.

Removed: load_pretrain_weights(nn_model, model_config, train_config) with train_config

Deprecated since v1.7, removed in v1.9. Drop the train_config positional argument.

Removed: start_epoch kwarg in train()

Deprecated since v1.7, removed in v1.9. PyTorch Lightning resumes automatically via resume=.

Removed: do_benchmark kwarg in train()

Deprecated since v1.7, removed in v1.9. Use the rfdetr.export.benchmark module instead.

Removed: callbacks dict kwarg in train()

Deprecated since v1.7, removed in v1.9. Pass PTL Callback objects directly via the Lightning API instead.

Removed: misplaced config fields

The following TrainConfig and ModelConfig fields moved to their correct config class in v1.7; the deprecated compatibility shims are removed in v1.9. Passing one of these fields on its old config class now raises a pydantic validation error:

Field Removed from Use in
group_detr TrainConfig ModelConfig
ia_bce_loss TrainConfig ModelConfig
segmentation_head TrainConfig ModelConfig
num_select TrainConfig ModelConfig
cls_loss_coef ModelConfig TrainConfig

Removed: RFDETRLarge silent fallback to deprecated Large config

RFDETRLarge() no longer catches checkpoint/config incompatibility errors and silently retries with RFDETRLargeDeprecatedConfig. Loading legacy deprecated-Large weights through RFDETRLarge now raises the original ValueError/RuntimeError instead of falling back. RFDETRLargeDeprecated itself is unaffected — use it directly to load those checkpoints.

# Before (silently retried with the deprecated config and logged a warning)
model = RFDETRLarge(pretrain_weights="old_large_checkpoint.pth")

# After
from rfdetr import RFDETRLargeDeprecated

model = RFDETRLargeDeprecated(pretrain_weights="old_large_checkpoint.pth")

Deprecated in v1.9 → Remove in v1.11

Deprecated: RFDETR.optimize_for_inference() renamed to RFDETR.inference()

optimize_for_inference(compile=..., batch_size=..., dtype=..., inplace=...) — renamed to inference() with the same signature.

# Before (deprecated)
model.optimize_for_inference(dtype=torch.float16)

# After
model.inference(dtype=torch.float16)

Deprecated: TrainConfig.lr_drop and TrainConfig.lr_min_factor

lr_drop / lr_min_factor — pass them through lr_scheduler_kwargs instead. For the managed "step" / "cosine" presets the fields are still folded into lr_scheduler_kwargs (with a FutureWarning); set with an explicit scheduler they are inert and warn.

# Before (deprecated)
TrainConfig(lr_scheduler="step", lr_drop=80, lr_min_factor=0.1)

# After
TrainConfig(lr_scheduler="step", lr_scheduler_kwargs={"lr_drop": 80, "min_factor": 0.1})

Deprecated in v1.9 → Remove in v1.12

rfdetr.datasets.aug_config is deprecated

The module was renamed to rfdetr.datasets.aug_configs (plural) in v1.8.0 — see the "Upgrade 1.7 → 1.8" section below, where it is listed as a breaking change because that rename shipped with no compatibility shim. A shim was added in v1.9.0, so the singular path imports again and emits a FutureWarning. It is scheduled for removal in v1.12.0; migrate before then.

The preset constants are unchanged — only the module path moves.

# Before (deprecated, warns since v1.9.0)
from rfdetr.datasets.aug_config import AUG_AGGRESSIVE

# After
from rfdetr.datasets.aug_configs import AUG_AGGRESSIVE

Upgrade 1.7 → 1.8

Breaking changes

Breaking in v1.8.2: default keypoint schema changed to active-first [17]

New checkpoints created from v1.8.2 onwards use class_id=0 for person. Legacy [0, 17] checkpoints are still supported — RF-DETR auto-detects the schema from the checkpoint at load time.

If your post-processing code offsets class IDs by 1 (common for background-first models), update it:

# Before (background-first [0, 17]: person was at class_id=1)
class_name = "person" if detection.class_id == 1 else "other"

# After (active-first [17]: person is at class_id=0)
class_name = "person" if detection.class_id == 0 else "other"

Use detection.data["class_name"] for schema-agnostic name resolution.

Breaking: rfdetr.datasets.aug_config renamed to rfdetr.datasets.aug_configs

The augmentation config module was renamed (singular → plural). If you import from it directly:

# Before
from rfdetr.datasets.aug_config import AUG_AGGRESSIVE

# After
from rfdetr.datasets.aug_configs import AUG_AGGRESSIVE

All preset constants (AUG_AGGRESSIVE, AUG_CONSERVATIVE, etc.) are unchanged.

Breaking: supervision>=0.29.0 now required

Required for sv.KeyPoints support. pip install rfdetr==1.8.0 pulls this automatically. If another dependency pins supervision<0.29.0, resolve the conflict manually.

Breaking: pyDeprecate constraint narrowed to >=0.9,<0.10

Was >=0.6,<0.8. If another package pins an older version, resolve with:

pip install "rfdetr==1.8.0" "pyDeprecate>=0.9,<0.10"

Upgrade 1.6 → 1.7

Breaking changes

Breaking: peft removed from the default install

LoRA fine-tuning now requires the lora extra. If you use LoRA adapters during training, update your install command.

# Before
pip install rfdetr

# After
pip install 'rfdetr[lora]'

Breaking: predict() stores source image in detections.metadata

predict() stores the source image in detections.metadata, not detections.data.

# Before (1.6.4 and earlier)
source = detections.data["source_image"]

# After
source = detections.metadata["source_image"]

Breaking: pyDeprecate constraint changed to >=0.6,<0.8

Was >=0.3,<0.6. If another package pins an older version, resolve with:

pip install "rfdetr==1.7.0" "pyDeprecate>=0.6,<0.8"

Deprecated in v1.7 → Remove in v1.9

Deprecated: build_namespace() split into two functions

build_namespace(model_config, train_config) — use build_model_from_config or build_criterion_from_config instead.

# Before (deprecated)
from rfdetr.models import build_namespace

ns = build_namespace(model_config, train_config)

# After
from rfdetr.models import build_model_from_config, build_criterion_from_config

model = build_model_from_config(model_config)
criterion = build_criterion_from_config(model_config, train_config)

Deprecated: load_pretrain_weights() no longer takes train_config

load_pretrain_weights(nn_model, model_config, train_config) — drop the train_config positional argument.

# Before (deprecated)
from rfdetr.models import load_pretrain_weights

load_pretrain_weights(nn_model, model_config, train_config)

# After
from rfdetr.models import load_pretrain_weights

load_pretrain_weights(nn_model, model_config)

Deprecated: config fields moved between ModelConfig and TrainConfig

Config fields placed in the wrong config object. Move them as shown:

Field Was in Move to
group_detr TrainConfig ModelConfig
ia_bce_loss TrainConfig ModelConfig
segmentation_head TrainConfig ModelConfig
num_select TrainConfig ModelConfig
cls_loss_coef ModelConfig TrainConfig
# Before (deprecated)
train_config = TrainConfig(group_detr=13, cls_loss_coef=2.0)

# After
model_config = ModelConfig(group_detr=13)
train_config = TrainConfig(cls_loss_coef=2.0)

Deprecated in v1.7 → Remove in v2.0

Deprecated: RFDETRBase replaced by size-specific classes

RFDETRBase defaulted to the small variant and is replaced by size-specific classes. Choose the variant that matches your previous model size. If you used RFDETRBase() without arguments, switch to RFDETRSmall().

# Before (deprecated)
from rfdetr import RFDETRBase

model = RFDETRBase()

# After — pick one
from rfdetr import RFDETRNano, RFDETRSmall, RFDETRMedium, RFDETRLarge

model = RFDETRSmall()

Deprecated: RFDETRSegPreview replaced by size-specific segmentation classes

RFDETRSegPreview defaulted to the small variant and is replaced by size-specific segmentation classes. If you used RFDETRSegPreview() without arguments, switch to RFDETRSegSmall().

# Before (deprecated)
from rfdetr import RFDETRSegPreview

model = RFDETRSegPreview()

# After — pick one
from rfdetr import RFDETRSegNano, RFDETRSegSmall, RFDETRSegMedium, RFDETRSegLarge

model = RFDETRSegSmall()

Upgrade 1.5 → 1.6

Breaking changes

Breaking: transformers minimum version raised to >=5.1.0

transformers minimum version raised to >=5.1.0,<6.0.0.

Projects pinned to transformers<5.0.0 must upgrade. If upgrading is not possible, pin rfdetr<1.6.0.

pip install 'transformers>=5.1.0,<6.0.0'

Breaking: PyPI extras renamed

PyPI extras renamed.

Update your pip install commands and requirements*.txt files.

Old extra New extra
rfdetr[metrics] rfdetr[loggers]
rfdetr[onnxexport] rfdetr[onnx]
# Before
pip install 'rfdetr[metrics]'
pip install 'rfdetr[onnxexport]'

# After
pip install 'rfdetr[loggers]'
pip install 'rfdetr[onnx]'

Breaking: draw_synthetic_shape() now returns a tuple

draw_synthetic_shape() now returns (image, polygon) instead of image.

Update every call site that unpacks only the image.

# Before
img = draw_synthetic_shape(...)

# After
img, polygon = draw_synthetic_shape(...)

Deprecated in v1.6 → Removed in v1.8

Deprecated: simplify and force arguments in RFDETR.export()

RFDETR.export(..., simplify=..., force=...) — both arguments are no-ops. Remove them from your calls.

# Before (deprecated)
model.export("model.onnx", simplify=True, force=True)

# After
model.export("model.onnx")

Deprecated in v1.6 → Remove in v1.9

Deprecated: rfdetr.util.* and rfdetr.deploy.* import paths

Backward-compatibility shims are still active but emit DeprecationWarning on import. Replace with the canonical paths listed in the table below.

Deprecated module Canonical replacement
rfdetr.util.coco_classes rfdetr.assets.coco_classes
rfdetr.util.misc rfdetr.utilities
rfdetr.util.logger rfdetr.utilities.logger
rfdetr.util.box_ops rfdetr.utilities.box_ops
rfdetr.util.files rfdetr.utilities.files
rfdetr.util.package rfdetr.utilities.package
rfdetr.util.get_param_dicts rfdetr.training.param_groups
rfdetr.util.drop_scheduler rfdetr.training.drop_schedule
rfdetr.util.visualize rfdetr.visualize.data
rfdetr.deploy rfdetr.export
rfdetr.models.segmentation_head rfdetr.models.heads.segmentation

Examples:

# Before (deprecated)
from rfdetr.util.coco_classes import COCO_CLASSES
from rfdetr.util.misc import get_rank, get_world_size, is_main_process, save_on_master
from rfdetr.util.logger import get_logger
from rfdetr.util.box_ops import box_cxcywh_to_xyxy, generalized_box_iou
from rfdetr.util.get_param_dicts import get_param_dict
from rfdetr.util.drop_scheduler import drop_scheduler
from rfdetr.util.visualize import save_gt_predictions_visualization
from rfdetr.deploy import export_onnx
from rfdetr.models.segmentation_head import SegmentationHead

# After
from rfdetr.assets.coco_classes import COCO_CLASSES
from rfdetr.utilities.distributed import get_rank, get_world_size, is_main_process, save_on_master
from rfdetr.utilities.logger import get_logger
from rfdetr.utilities.box_ops import box_cxcywh_to_xyxy, generalized_box_iou
from rfdetr.training.param_groups import get_param_dict
from rfdetr.training.drop_schedule import drop_scheduler
from rfdetr.visualize.data import save_gt_predictions_visualization
from rfdetr.export.main import export_onnx
from rfdetr.models.heads.segmentation import SegmentationHead

Upgrade 1.4 → 1.5

Breaking changes

Breaking: ModelConfig rejects unknown keyword arguments

ModelConfig now raises ValidationError on unknown keyword arguments.

Previously, unrecognised fields were silently ignored. Remove or rename any unrecognised keys you pass to ModelConfig(...).

# Before — silently accepted
config = ModelConfig(unknown_field=True)

# Now raises ValidationError — remove the unknown key
config = ModelConfig()

Deprecated in v1.5 → Removed in v1.7

Deprecated: OPEN_SOURCE_MODELS replaced by ModelWeights enum

OPEN_SOURCE_MODELS constant — use the ModelWeights enum instead. A DeprecationWarning is emitted on access. See the API reference for available enum values.

# Before (deprecated)
from rfdetr import OPEN_SOURCE_MODELS

# After
from rfdetr.assets.model_weights import ModelWeights