Files
wehub-resource-sync 16031aae96
CPU tests Workflow / Testing (ubuntu-latest, 3.12) (push) Failing after 1s
CPU tests Workflow / Testing (ubuntu-latest, 3.13) (push) Failing after 0s
Mypy Type Check / Type Check (push) Failing after 0s
Docs/Test WorkFlow / Test docs build (push) Failing after 1s
PR Conflict Labeler / labeling (push) Failing after 1s
Dependency resolution / Resolve [tflite] extra — Python 3.12 (push) Failing after 0s
Smoke Tests / try-all-models (ubuntu-latest, 3.10) (push) Failing after 0s
Smoke Tests / try-all-models (ubuntu-latest, 3.13) (push) Failing after 1s
CPU tests Workflow / build-pkg (push) Failing after 1s
CPU tests Workflow / Testing (ubuntu-latest, 3.10) (push) Failing after 0s
CPU tests Workflow / Testing (ubuntu-latest, 3.11) (push) Failing after 0s
Smoke Tests / try-all-models (macos-latest, 3.10) (push) Has been cancelled
Smoke Tests / try-all-models (macos-latest, 3.13) (push) Has been cancelled
Smoke Tests / try-all-models (windows-latest, 3.10) (push) Has been cancelled
Smoke Tests / try-all-models (windows-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / Testing (macos-latest, 3.10) (push) Has been cancelled
CPU tests Workflow / Testing (macos-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / Testing (windows-latest, 3.10) (push) Has been cancelled
CPU tests Workflow / Testing (windows-latest, 3.13) (push) Has been cancelled
CPU tests Workflow / testing-guardian (push) Has been cancelled
GPU tests Workflow / Testing (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:26:24 +08:00

385 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: Customize RF-DETR training with PyTorch Lightning primitives. Direct access to RFDETRModelModule, RFDETRDataModule, and build_trainer.
---
# Custom Training API
The high-level `RFDETR.train()` method is the quickest path to fine-tuning, but the underlying training primitives are fully public and are the **recommended path for any customisation**: custom callbacks, alternative loggers, mixed-precision overrides, multi-GPU strategies, or integration with external training frameworks.
!!! tip "Quickstart vs. customisation"
If you want to start training with minimal code, use `model.train()` — it sets up and runs the full PTL stack automatically. Come here when you need to take direct control over any part of that stack.
## How `RFDETR.train()` relates to PTL
When you call `model.train(...)`, three things happen internally:
```python
from rfdetr.training import RFDETRModelModule, RFDETRDataModule, build_trainer
module = RFDETRModelModule(model_config, train_config)
datamodule = RFDETRDataModule(model_config, train_config)
trainer = build_trainer(train_config, model_config)
trainer.fit(module, datamodule, ckpt_path=train_config.resume or None)
```
Each of these objects is a standard PTL class. You can construct them directly, modify them, swap out callbacks, or replace the trainer entirely.
---
## RFDETRModelModule
`RFDETRModelModule` is a `pytorch_lightning.LightningModule`. It owns the model weights, the criterion, the postprocessor, and the optimizer/scheduler configuration.
```python
from rfdetr.config import (
RFDETRMediumConfig,
TrainConfig,
) # config classes live in rfdetr.config, not the top-level rfdetr namespace
from rfdetr.training import RFDETRModelModule
model_config = RFDETRMediumConfig(num_classes=10)
train_config = TrainConfig(
dataset_dir="path/to/dataset",
epochs=50,
batch_size=4,
grad_accum_steps=4,
lr=1e-4,
output_dir="output",
)
module = RFDETRModelModule(model_config, train_config)
```
### Lifecycle hooks
| Hook | Behaviour |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `on_fit_start` | Seeds RNGs when `train_config.seed` is set. |
| `on_train_batch_start` | Applies multi-scale random resize when `train_config.multi_scale=True`. |
| `transfer_batch_to_device` | Moves `NestedTensor` batches to the target device. |
| `training_step` | Computes loss and logs `train/loss` plus per-term losses. Keypoint models use manual optimization with box-normalized accumulation across microbatches; detection and segmentation use Lightning's automatic optimization path. |
| `validation_step` | Runs forward pass and postprocessing; returns `{results, targets}` for `COCOEvalCallback`. |
| `test_step` | Same as `validation_step`, logs under `test/`. |
| `predict_step` | Runs inference-only forward pass and returns postprocessed detections. |
| `configure_optimizers` | Builds AdamW with layer-wise LR decay and a LambdaLR scheduler (cosine or step). |
| `on_load_checkpoint` | Auto-converts legacy `.pth` checkpoints to PTL format. |
### Accessing the underlying model
The raw `nn.Module` is `module.model`. After training completes, `RFDETR.train()` syncs it back onto `self.model.model` so `predict()` and `export()` continue to work.
---
## RFDETRDataModule
`RFDETRDataModule` is a `pytorch_lightning.LightningDataModule`. It builds train/val/test datasets and wraps them in `DataLoader` objects.
```python
from rfdetr.training import RFDETRDataModule
datamodule = RFDETRDataModule(model_config, train_config)
```
### Stages
| Stage | Datasets built |
| ------------ | ------------------------------------------ |
| `"fit"` | `train` + `val` |
| `"validate"` | `val` only |
| `"test"` | `test` (or `val` for COCO-format datasets) |
The `setup(stage)` method is lazy — each split is built at most once, even if called multiple times.
### class_names property
```python
datamodule.setup("fit")
print(datamodule.class_names) # e.g. ["cat", "dog", "person"]
```
Returns sorted category names from the COCO annotation file of the first available split, or `None` if the dataset has not been set up yet.
---
## build_trainer
`build_trainer` assembles a `pytorch_lightning.Trainer` with the full RF-DETR callback and logger stack. All `TrainConfig` fields are wired automatically.
```python
from rfdetr.training import build_trainer
trainer = build_trainer(train_config, model_config)
```
### What build_trainer configures
| Concern | Source |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Max epochs | `train_config.epochs` |
| Gradient accumulation | Detection/segmentation: `train_config.grad_accum_steps` forwarded to Trainer. Keypoint models: owned by `RFDETRModelModule` manual optimization (Trainer always sees `1`). |
| Gradient clipping | Detection/segmentation: `train_config.clip_max_norm` forwarded to Trainer. Keypoint models: owned by `RFDETRModelModule` manual optimization (Trainer always sees `None`). |
| Mixed precision | `model_config.amp` enables AMP; dtype resolved from `train_config.amp_dtype` (`"auto"` selects `bf16-mixed` on Ampere+, `"bf16"` / `"fp16"` force a specific dtype) |
| Accelerator | `train_config.accelerator` (default `"auto"`) |
| Strategy | Set via `train_config.strategy` (default `"auto"`) or pass `strategy=` as a `**trainer_kwarg` to `build_trainer`. Common values: `"auto"`, `"ddp"`, `"ddp_spawn"`. `TrainConfig` also exposes `devices` and `num_nodes` for multi-GPU and multi-node training. |
| Sync batch norm | `train_config.sync_bn` |
| Progress bar | `train_config.progress_bar` |
| Loggers | CSVLogger always; TensorBoard, WandB, MLflow when their `train_config` flags are `True` |
| Callbacks | `RFDETREMACallback`, `DropPathCallback`, `COCOEvalCallback`, `BestModelCallback`, `RFDETREarlyStopping` (conditional) |
### Overriding PTL Trainer kwargs
Pass keyword arguments accepted by `pytorch_lightning.Trainer` via `**trainer_kwargs`. Most keys override the built configuration.
**Detection and segmentation models** forward `accumulate_grad_batches` and `gradient_clip_val` to the Trainer normally — you can override them via `trainer_kwargs` or configure them on `TrainConfig` (`grad_accum_steps`, `clip_max_norm`).
**Keypoint models** use manual optimization, so `RFDETRModelModule` owns accumulation and clipping internally. `build_trainer()` forces `accumulate_grad_batches=1` and `gradient_clip_val=None` regardless of what is passed, and emits a `UserWarning` if those keys appear in `trainer_kwargs` so the override is visible:
```python
trainer = build_trainer(
train_config,
model_config,
fast_dev_run=2, # run 2 batches per epoch for a smoke test
log_every_n_steps=10,
)
```
---
## Running the training loop
### Full training run
```python
from rfdetr.config import (
RFDETRMediumConfig,
TrainConfig,
) # config classes live in rfdetr.config, not the top-level rfdetr namespace
from rfdetr.training import RFDETRModelModule, RFDETRDataModule, build_trainer
model_config = RFDETRMediumConfig(num_classes=10)
train_config = TrainConfig(
dataset_dir="path/to/dataset",
epochs=100,
batch_size=4,
grad_accum_steps=4,
lr=1e-4,
output_dir="output",
)
module = RFDETRModelModule(model_config, train_config)
datamodule = RFDETRDataModule(model_config, train_config)
trainer = build_trainer(train_config, model_config)
trainer.fit(module, datamodule)
```
### Resume from checkpoint
Pass the checkpoint path to `trainer.fit` via `ckpt_path`. The path can be a PTL `.ckpt` file or a legacy RF-DETR `.pth` file — `RFDETRModelModule.on_load_checkpoint` converts either format automatically.
```python
trainer.fit(module, datamodule, ckpt_path="output/last.ckpt")
# or a legacy checkpoint:
trainer.fit(module, datamodule, ckpt_path="output/checkpoint.pth")
```
> **Note:** When `checkpoint_interval=1`, no `last.ckpt` is written. Use `checkpoint_{epoch}.ckpt` (e.g. `output/checkpoint_epoch=4.ckpt`) to resume instead.
If you need to persist a converted checkpoint on disk (for example to inspect it, share it, or use it outside of PTL), convert it explicitly before passing it to `trainer.fit`:
```python
from rfdetr.training import convert_legacy_checkpoint
convert_legacy_checkpoint("old_checkpoint.pth", "new_checkpoint.ckpt")
trainer.fit(module, datamodule, ckpt_path="new_checkpoint.ckpt")
```
`convert_legacy_checkpoint` reads a pre-PTL `.pth` file produced by the legacy `engine.py` training loop and writes a PTL-compatible `.ckpt` file. Use it when migrating saved checkpoints to the PTL format rather than relying on on-the-fly conversion at load time.
### Validation only
```python
trainer.validate(module, datamodule)
```
Runs one full validation pass and logs `val/mAP_50_95`, `val/mAP_50`, `val/F1`, and per-class AP metrics to all active loggers.
### Inference with the data pipeline
```python
predictions = trainer.predict(module, dataloaders=datamodule.val_dataloader())
```
Calls `module.predict_step` on every batch and returns a list of postprocessed detection results. Pass any `DataLoader` instance — `datamodule.val_dataloader()`, `datamodule.test_dataloader()`, or a custom loader — as the `dataloaders` argument. This is useful for offline evaluation or generating submission files.
!!! note "predict_dataloader not implemented"
`RFDETRDataModule` does not define a `predict_dataloader()` method, so `trainer.predict(module, datamodule)` will raise an error. Always pass a dataloader explicitly via the `dataloaders=` argument.
---
## Multi-GPU training
`build_trainer` configures PyTorch Lightning's `Trainer` directly, so all PTL strategies work out of the box.
### Data Parallel (DDP) — recommended
Set `train_config.accelerator = "auto"` and pass `strategy="ddp"` to `build_trainer`, then launch with `torchrun`:
!!! note "`devices` must be overridden for multi-GPU runs"
`build_trainer` defaults to `devices=1`. To use all available GPUs, pass `devices="auto"` (or an explicit count) as a `**trainer_kwarg`:
```python
trainer = build_trainer(train_config, model_config, strategy="ddp", devices="auto")
```
Without this override, `torchrun` will spawn multiple processes but each process will only see one device, defeating the purpose of the multi-GPU launch.
```bash
torchrun --nproc_per_node=4 train.py
```
where `train.py` contains:
```python
from rfdetr.config import (
RFDETRMediumConfig,
TrainConfig,
) # config classes live in rfdetr.config, not the top-level rfdetr namespace
from rfdetr.training import RFDETRModelModule, RFDETRDataModule, build_trainer
model_config = RFDETRMediumConfig(num_classes=10)
train_config = TrainConfig(
dataset_dir="path/to/dataset",
epochs=100,
batch_size=4, # per-GPU batch size
grad_accum_steps=1, # reduce when using more GPUs
output_dir="output",
sync_bn=True, # sync batch norms across GPUs
)
module = RFDETRModelModule(model_config, train_config)
datamodule = RFDETRDataModule(model_config, train_config)
trainer = build_trainer(train_config, model_config, strategy="ddp", devices="auto")
trainer.fit(module, datamodule)
```
!!! warning "EMA is not compatible with FSDP or DeepSpeed"
`build_trainer` automatically disables `RFDETREMACallback` when `strategy` contains `"fsdp"` or `"deepspeed"`, and emits a `UserWarning`. Use `strategy="ddp"` or `strategy="auto"` to keep EMA active.
### Effective batch size
```
effective_batch_size = batch_size × grad_accum_steps × num_gpus
```
Maintain an effective batch size of 16 regardless of GPU count:
| GPUs | `batch_size` | `grad_accum_steps` | Effective |
| ---- | ------------ | ------------------ | --------- |
| 1 | 4 | 4 | 16 |
| 2 | 4 | 2 | 16 |
| 4 | 4 | 1 | 16 |
| 8 | 2 | 1 | 16 |
---
## Custom callbacks
`build_trainer` builds the default callback stack. To add your own callbacks alongside the built-in ones, pass them via `trainer_kwargs`:
```python
from pytorch_lightning.callbacks import LearningRateMonitor, ModelSummary
from rfdetr.training import build_trainer
extra_callbacks = [
LearningRateMonitor(logging_interval="step"),
ModelSummary(max_depth=3),
]
trainer = build_trainer(
train_config,
model_config,
callbacks=extra_callbacks, # replaces the default callback list entirely
)
```
!!! warning "Replacing vs. extending callbacks"
Passing `callbacks=` to `build_trainer` via `trainer_kwargs` **replaces** the entire default callback list built inside `build_trainer` (EMA, COCO eval, best-model checkpointing, etc.). To extend rather than replace, build the extra callbacks separately and merge them after calling `build_trainer`:
```python
trainer = build_trainer(train_config, model_config)
trainer.callbacks.extend(
[
LearningRateMonitor(logging_interval="step"),
]
)
trainer.fit(module, datamodule)
```
### Built-in callbacks
| Class | Purpose | Enabled when |
| --------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `RFDETREMACallback` | Maintains an EMA copy of model weights | `train_config.use_ema=True` and strategy is not sharded |
| `DropPathCallback` | Anneals drop-path rate over training | `train_config.drop_path > 0` |
| `COCOEvalCallback` | Computes task validation metrics after each validation epoch | Always |
| `BestModelCallback` | Saves `checkpoint_best_regular.pth`, `checkpoint_best_ema.pth`, `checkpoint_best_total.pth` | Always |
| `RFDETREarlyStopping` | Stops training when the validation task metric stops improving | `train_config.early_stopping=True` |
---
## Custom loggers
`build_trainer` adds loggers based on `TrainConfig` flags. To attach a logger not supported by `TrainConfig` (for example a custom Neptune or Comet logger), build it yourself and pass it alongside the defaults:
```python
from pytorch_lightning.loggers import NeptuneLogger # hypothetical
from rfdetr.training import build_trainer
trainer = build_trainer(train_config, model_config)
trainer.loggers.append(NeptuneLogger(project="my-workspace/rf-detr"))
trainer.fit(module, datamodule)
```
All logged keys (`train/loss`, `val/mAP_50_95`, `val/keypoint_map_50_95`, `val/F1`, `val/ema_mAP_50_95`, etc.) are written to every active logger in the list.
---
## Logged metrics reference
| Key | When logged | Description |
| ------------------------ | ---------------------- | --------------------------------------------------------- |
| `train/loss` | Every step / epoch | Total weighted training loss |
| `train/<term>` | Every step / epoch | Individual loss terms (e.g. `train/loss_bbox`) |
| `val/loss` | Each epoch | Validation loss (if `train_config.compute_val_loss=True`) |
| `val/mAP_50_95` | Each eval epoch | COCO box mAP@[.50:.05:.95] |
| `val/mAP_50` | Each eval epoch | COCO box mAP@.50 |
| `val/mAP_75` | Each eval epoch | COCO box mAP@.75 |
| `val/mAR` | Each eval epoch | COCO mean average recall |
| `val/ema_mAP_50_95` | Each eval epoch | EMA-model mAP@[.50:.05:.95] (if EMA active) |
| `val/F1` | Each eval epoch | Macro F1 at best confidence threshold |
| `val/precision` | Each eval epoch | Precision at best F1 threshold |
| `val/recall` | Each eval epoch | Recall at best F1 threshold |
| `val/AP/<class>` | Each eval epoch | Per-class AP (if `log_per_class_metrics=True`) |
| `val/segm_mAP_50_95` | Each eval epoch | Segmentation mAP (segmentation models only) |
| `val/segm_mAP_50` | Each eval epoch | Segmentation mAP@.50 (segmentation models only) |
| `val/keypoint_map_50_95` | Each eval epoch | COCO keypoint AP@[.50:.05:.95] (keypoint preview only) |
| `val/keypoint_map_50` | Each eval epoch | COCO keypoint AP@.50 (keypoint preview only) |
| `test/*` | After `trainer.test()` | Mirror of `val/*` keys |
---
## See also
- [RFDETR.train() — high-level API](index.md#quick-start) — the one-liner training path
- [Training parameters](training-parameters.md) — all `TrainConfig` fields
- [Training loggers](loggers.md) — TensorBoard, WandB, MLflow setup
- [Advanced training](advanced.md) — checkpointing, early stopping, memory optimisation
- [PTL primitives API reference](../../reference/training.md) — full docstring reference