Hyperparameters
Every training argument is a field on a TrainConfig dataclass. The base class defines the field and its default; each model family subclasses it and overrides the defaults that its published recipe changes.
Setting arguments
train() takes keyword arguments and the CLI takes the same names in
key=value form.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")results = model.train( data="my-dataset.yaml", epochs=100, batch=16, imgsz=640, lr0=0.01,) print(results["best_mAP50_95"])libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \ epochs=100 batch=16 imgsz=640 lr0=0.01Both paths end at the same place. The kwargs are handed to
TrainConfig.from_kwargs(), which builds the family's config dataclass.
A typo does not raise
from_kwargs() drops any key that is not a field on the config and emits a
UserWarning naming it. Training then starts with the default in place:
# UserWarning: Unknown training config keys (ignored): ['learning_rate']model.train(data="my-dataset.yaml", learning_rate=0.001)Nothing fails, the run completes, and the learning rate was never what the caller asked for. Read the warnings on the first epoch of a new recipe. The CLI is stricter, because it validates flag names before the config is built, so a misspelled CLI flag is rejected outright.
Defaults are per family
TrainConfig defines the field and a base default. Each family subclasses it and
overrides what its published recipe changes, so there is no single correct answer
to "what is the default learning rate".
The base defaults are optimizer="sgd", lr0=0.01, momentum=0.937,
weight_decay=5e-4, scheduler="yoloxwarmcos", epochs=300, batch=16,
imgsz=640 and amp=True. Three examples of how far a family moves from that:
| Field | Base | YOLOv9 | D-FINE | YOLO-NAS |
|---|---|---|---|---|
optimizer | sgd | sgd | adamw | adamw |
lr0 | 0.01 | 0.01 | 2e-4 | 5e-4 |
weight_decay | 5e-4 | 5e-4 | 1e-4 | 1e-5 |
scheduler | yoloxwarmcos | linear | flat_cosine | cos |
epochs | 300 | 300 | 132 | 300 |
amp | True | True | True | True |
D-FINE, DEIM, RT-DETRv4 and YOLO-NAS detection default to amp=True with amp_dtype="float16". Dome-DETR, PP-YOLOE and YOLO-NAS OBB retain FP32 defaults. Pass amp=False when FP32 is required.
To read a family's real defaults rather than guessing:
from dataclasses import fields from libreyolo import LibreYOLO9from libreyolo.training.config import TrainConfig family_cfg = LibreYOLO9.TRAIN_CONFIG()base_cfg = TrainConfig() for f in fields(family_cfg): family_value = getattr(family_cfg, f.name) base_value = getattr(base_cfg, f.name, None) if not hasattr(base_cfg, f.name) or family_value != base_value: print(f"{f.name}: {family_value}")# Prints the train, val and predict defaults, including family overrides.libreyolo cfgBatch size
batch is the global batch. Under multi-GPU training each rank loads
batch // world_size, so the number you pass is the number of images per
optimizer step regardless of how many GPUs are involved. See
Multi-GPU training.
batch=-1 turns on autobatch. The trainer probes the model in training mode with
a real backward pass at powers of two, fits a line to the memory curve, and picks
the largest power of two strictly below the extrapolated value that fits within
60 percent of total VRAM.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # batch=-1 probes GPU memory and resolves to a concrete power of two.model.train(data="my-dataset.yaml", batch=-1, imgsz=640)libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml batch=-1Probing in training mode with a backward pass is the point: an inference-mode probe misses the retained activations and gradient tensors, which for a deep CNN are several times the inference footprint. RF-DETR lowers the target fraction to 45 percent, because the probe's synthetic backward still underestimates what its criterion and auxiliary decoder layers cost.
Autobatch is a CUDA feature. On CPU or MPS it logs one line and keeps the default batch.
min_samples=0 leaves epoch length unchanged. A positive floor samples shorter detection datasets with replacement. class_balanced=False enables per-image repeat-factor sampling when set to true; it combines with min_samples and DDP. Specialized loaders that bypass the shared sampler reject enabled balancing.
Gradient accumulation
nbs sets the nominal, or effective, batch size. The trainer accumulates
round(nbs / batch) micro-batches per optimizer step.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # 4 micro-batches of 16 per optimizer step, effective batch 64.model.train(data="my-dataset.yaml", batch=16, nbs=64)Left as None, the default, accumulation is off and training is unchanged.
Learning rate and schedule
lr0 is the initial learning rate and optimizer accepts sgd, adam and
adamw. momentum is SGD momentum or Adam's beta1, weight_decay is the L2
term, and nesterov applies to SGD.
The schedule is shaped by scheduler, warmup_epochs, warmup_lr_start and
min_lr_ratio. no_aug_epochs sets how many final epochs run without strong
augmentation, and several schedules use it to shape their tail as well, so it is
not purely an augmentation knob. What each family does with the augmentation half
of it is on Augmentations.
Some families add their own learning-rate knobs. backbone_lr_mult scales the
backbone group against the head, clip_max_norm sets gradient clipping, and
SegFormer uses head_lr_mult to run its decode head at ten times the backbone
rate. These live on the family's config subclass, not the base one.
clip_max_norm clips the gradient L2 norm to that value before each optimizer
step, and 0 turns clipping off. YOLOv9, YOLOv9-E2E and YOLOv9-P2 default it to
10. D-FINE, Dome-DETR, DEIM, DEIMv2, TinyFormer, RT-DETR, RT-DETRv2,
RT-DETRv4, RF-DETR, DINOv2, GTR and EC default it to 0.1. On the CLI it is
clip_max_norm= or --clip-max-norm; see
libreyolo train for the families that accept it there.
EMA
ema=True keeps an exponential moving average of the weights alongside the
trained ones. It is on by default everywhere except FOMO.
ema_decay is the target decay. The decay ramps in rather than starting at its
target: the effective value at update n is ema_decay * (1 - exp(-n / tau))
with tau defaulting to 2000, so early updates track the model more closely and
late updates smooth it. Family defaults range from 0.997 on YOLO-NAS pose
through 0.9998 on YOLOX to 0.9999 on YOLOv9 and the DETR line.
The EMA weights are what gets validated and what best.pt and last.pt carry.
The raw trained weights are also stored, under the train_model key, so a resume
continues from the trained trajectory rather than from the average.
Precision
amp=True runs the forward pass under CUDA autocast. amp_dtype selects
float16 (the default) or bfloat16; fp16 and bf16 are accepted spellings.
Float16 needs dynamic loss scaling and gets a live GradScaler. Bfloat16's wider
exponent range does not, so its scaler is constructed but disabled, which keeps
the optimizer path identical. Asking for bfloat16 on a CUDA device without
bfloat16 support raises at setup rather than degrading silently.
Output, checkpoints and stopping
Runs are written to project/name. project defaults to runs/train
everywhere, but name is one of the per-family overrides: the base default is
exp, while YOLOv9 uses yolo9_exp and D-FINE uses dfine_exp. With
exist_ok=False, the default, an existing directory gets an incremented suffix
instead of being overwritten.
save_period writes an extra weights/epoch_<N>.pt every N epochs, on top of
weights/last.pt after each epoch and weights/best.pt whenever the tracked
metric improves. eval_interval sets how often validation runs, and the final
epoch always validates; val=False turns validation off, and such a run writes
no best.pt. patience stops the run after that many epochs without
improvement, with 0 disabling early stopping.
cache speeds up repeated epochs by holding decoded images in RAM (True or
"ram") or as .npy files beside the sources ("disk"). Cached reads are
byte-identical to fresh ones. With dataloader workers, "disk" is the safer of
the two.
average_best=0 disables checkpoint averaging; a positive N writes weights/average.pt from up to N best snapshots. Floating tensors are averaged uniformly and integer buffers come from the best snapshot. export_check=False can be enabled to fail before epoch one if ONNX export fails. Matching raw outputs are compared at rtol=1e-3, atol=1e-4; incompatible layouts log a skipped comparison.
precise_bn=0 disables final BatchNorm recalibration. A positive value bounds training-loader images before final validation; under DDP the budget applies per participating rank. Frozen BatchNorm stays frozen. Custom fitness callbacks can choose best checkpoints and patience.
Resume
resume=True continues an interrupted run from the loaded checkpoint;
resume="path/to/last.pt" continues from that file instead.
from libreyolo import LibreYOLO # Load the interrupted run's checkpoint, then ask to resume.model = LibreYOLO("runs/train/yolo9_exp/weights/last.pt")model.train(data="my-dataset.yaml", resume=True)libreyolo train model=runs/train/yolo9_exp/weights/last.pt \ data=my-dataset.yaml resume=trueResume restores the run's saved training arguments, and an argument passed
explicitly overrides the saved one. It keeps writing into the checkpoint's run
directory. It restores the trained weights, the optimizer state, the EMA weights
and update count, the best-metric tracking, the GradScaler scale, and the
PyTorch, CUDA and NumPy random states. It starts at the checkpoint's epoch plus
one and fast-forwards the schedule to that position.
Three things it will not do. resume=True cannot be combined with pretrained,
which raises. Released weights and a run that already reached its epochs hold
nothing to resume, and raise a ValueError that says so. And when the
checkpoint's best-metric key differs from the current run's, best-metric
tracking resets to zero with a warning rather than comparing values that do not
mean the same thing.
Recipes in a file
cfg= loads a YAML mapping of TrainConfig field names and merges it under the
explicit keyword arguments, so a kwarg always wins over the file.
from libreyolo import LibreYOLO # Keys in the yaml are TrainConfig field names. Explicit kwargs win.model = LibreYOLO("LibreYOLO9s.pt")model.train(data="my-dataset.yaml", cfg="my-recipe.yaml", epochs=50)size and num_classes are stripped from the file, because the model instance
already owns them. There is no --cfg flag on the CLI; the file path is a Python
argument.
Related
- Datasets for what
data=accepts. - Augmentations for the augmentation knobs and which families honor them.
- Layer freezing and LoRA for training a subset of the weights.
- Validation and metrics for what the run reports.
Class selection and loss weighting
For YOLO9, RF-DETR, EdgeCrafter, RT-DETR, D-FINE, DEIM, TinyFormer and YOLO-NAS detection, classes=None keeps every dataset class; a list filters supervision while preserving original IDs, nc and names. single_cls=False can be enabled to map retained labels to class 0, named object. Resume and validation inherit saved settings. Model OBB training rejects single_cls.
ResNet, ConvNeXt, ConvNeXt V2, MobileNetV4, EfficientNetV2 and DINOv2 support cls_pw=0.0: values in [0, 1] weight each class by inverse frequency to that power, normalized to mean 1. class_weights=False selects the alternative N / (C * n_c) weighting when enabled. It cannot combine with positive cls_pw; resume requires matching weighting settings.
plot_samples=8 sets the validation sample-image budget. Use 0 for none or -1 for all; it does not reduce the images evaluated.