Skip to content

Consolidate the classification augmentation base and honour the ecosystem knobs - #881

Merged
EHxuban11 merged 5 commits into
devfrom
classify-augment-base
Sep 18, 2026
Merged

EHxuban11 merged 5 commits into
devfrom
classify-augment-base

Conversation

@EHxuban11

@EHxuban11 EHxuban11 commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Opened by an agent on the maintainer's behalf. Builds on #879 (branched from it); once #879 merges this diff shrinks to the last commit.

Consolidates the classification augmentation pipeline so it has the same base as the detection recipes, and closes the remaining gaps from #870 and #878.

What changed

  • New recipe module libreyolo/data/augment/classify.py, next to the detection recipes. The transform builder, collate and batch mixer moved there; classify_dataset.py now only holds datasets and re-exports the old names, so every existing import path still works.
  • One reader for the knobs. ClassifyAugKnobs.from_config(config) reads and validates scale, flip_prob, flipud, auto_augment, erasing, mixup, cutmix once. The trainer uses it instead of a hand-written getattr list. Invalid values fail at data setup, before the first epoch.
  • Flip knobs honoured. flip_prob (CLI alias fliplr) and flipud drive the train crop; previously the flip was a fixed 0.5 and flipud was silently ignored. flip_prob=0 removes the op. Defaults reproduce the previous op list exactly.
  • no_aug_epochs means the same thing for every task. The final epochs switch off auto_augment, erasing, mixup and cutmix (crop and flips stay), through the same on_mosaic_disable and ensure_mutation_reaches_workers path detection uses for close_mosaic. Classification family configs default no_aug_epochs to 0, so this is opt-in.
  • CLI. New fliplr, flipud, cutmix options. Task-aware alias table: on a classification model the CLI mixup is the classification batch-MixUp knob (default off), on detection it is still mixup_prob. auto_augment=none is accepted as off.
  • Spec (augment/spec.py): classification families now declare flip_prob and flipud as used, and the no_aug_epochs / mixup notes match the code. The "ignores these parameters" CLI warning follows.
  • Contract page docs/classification_augmentation.md; CHANGELOG entry.

What the reviewer should check

  • libreyolo/cli/commands/train.py: _resolve_train_task and the params["mixup"] = 0.0 guard. This is what stops the detection default of 1.0 reaching a classifier.
  • libreyolo/training/trainer.py: on_mosaic_disable now handles both hook names; family overrides (YOLOX, YOLOv7, D-FINE, DEIM) are untouched.
  • Behaviour-preservation: tests/unit/test_classification.py::test_transforms_default_off_is_unchanged still pins the default op list.

Verified

  • Unit: tests/unit -k "classif or augment or train or cli or spec or trainer or config or validator or plot": 1998 passed, 100 skipped (CPU, macOS). New tests/unit/test_classify_augment.py (58 tests) and 12 CLI tests.
  • Real 2-epoch CPU run (MobileNetV4-S, tiny ImageFolder, epochs=2 no_aug_epochs=1 mixup=1.0 auto_augment=randaugment erasing=0.5 flipud=0.5): epoch 0 batches carry soft labels and RandAugment is in the transform; epoch 1 batches carry hard labels and the policy is gone.
  • Lint: no new findings in touched files.

Not verified

  • GPU / DDP runs. The hook path is the existing one; classification loaders are built without persistent_workers, so the guard is a no-op there.
  • The website augmentations page (separate repo) still describes the classification pack as API-only for mixup; it needs a follow-up edit.

Fixes #870. Closes #878 together with #879.

Code provenance

All code in this PR is original, written for LibreYOLO. The transforms are composed from torchvision's public API (BSD-3-Clause). Knob names follow the de-facto YOLO CLI conventions as documented publicly; no third-party source code was read or adapted.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the previous probability-truncation issue is fully fixed and no new actionable failure remains.

Summary

The latest changes fully address the previous MixUp/CutMix probability finding by rejecting combined probabilities above one across API, trainer, and classification CLI paths.

  • Adds shared validate_mix_probabilities validation before batch mixing.
  • Returns clean CLI errors for invalid classification probability combinations.
  • Documents and tests the additive MixUp/CutMix probability contract.
  • Preserves detection CLI behavior, where mixup continues to map to mixup_prob.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Classification training options] --> B{Invocation path}
    B -->|CLI| C[Resolve classification task]
    C --> D[Validate mixup + cutmix]
    B -->|Python API| E[Build TrainConfig]
    D --> E
    E --> F[ClassifyAugKnobs.from_config]
    F --> G[Validate mixup + cutmix]
    G --> H[build_classify_collate]
    H --> I[Validate mixup + cutmix]
    I --> J[ClassifyBatchMixer]
Loading

Reviews (2) · Last reviewed commit: "Reject mixup + cutmix above 1 instead of..."

The training RandomResizedCrop area range was hardcoded to (0.5, 1.0) and
the eval resize/center-crop ratio was a per-family class attribute with no
user override.

- TrainConfig.scale: RandomResizedCrop area range. Accepts a float lower
  bound (ecosystem spelling) or an explicit (min, max).
- TrainConfig.crop_pct / ValidationConfig.crop_pct: eval resize ratio.
  None keeps the family's native value, which is what export records, so an
  override is a deliberate train/val-only divergence.
- Both land on the train CLI, crop_pct also on the val CLI, in both
  grammars, validated up front.
- Registered in the augmentation spec so detection families warn that they
  ignore them instead of accepting them silently.

Defaults are unchanged.
- forward crop_pct into the classification epoch-validation config. It was
  only passed to the augmented train transform, which ignores it, so
  train(crop_pct=...) changed nothing and best.pt was selected against the
  family default.
- route the ViT / CLIP / SigLIP2 validator overrides through a shared
  _resolve_crop_pct so those families honor the value instead of silently
  keeping their pinned ratio. An explicit crop_pct opts SigLIP2 out of
  square_resize, which never center crops.
- validate crop_pct in val_cmd so a bad value is a config_type_error at the
  boundary, not an io_error during dataset setup.
- warn when a non-classification model is given crop_pct.
Comment thread libreyolo/data/augment/classify.py Outdated
@EHxuban11
EHxuban11 merged commit e731ebc into dev Sep 18, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant