Skip to content

Fix AttributeError in auto-augment factories when hparams is None - #2747

Merged
rwightman merged 1 commit into
huggingface:mainfrom
winklemad:fix-auto-augment-none-hparams
Aug 26, 2026
Merged

rwightman merged 1 commit into
huggingface:mainfrom
winklemad:fix-auto-augment-none-hparams

Conversation

@winklemad

Copy link
Copy Markdown
Contributor

What

The three public auto-augment factory functions crash on their own documented default hparams=None:

from timm.data.auto_augment import (
    auto_augment_transform, rand_augment_transform, augment_and_mix_transform,
)

augment_and_mix_transform('augmix-m5-w4-d2')   # AttributeError: 'NoneType' object has no attribute 'setdefault'
rand_augment_transform('rand-m9-n3-mstd0.5')   # AttributeError
auto_augment_transform('original-mstd0.5')     # AttributeError

Each of those config strings is copied verbatim from the corresponding function's own docstring example.

Why

All three functions declare hparams: Optional[Dict] = None, but parse the mstd/mmax config sections by calling hparams.setdefault(...) before hparams is normalized:

  • auto_augment_transform — hparams.setdefault('magnitude_std', ...) (mstd path)
  • rand_augment_transform — hparams.setdefault('magnitude_std'/'magnitude_max', ...) (mstd/mmax paths)
  • augment_and_mix_transform — same for mstd, plus an unconditional hparams.setdefault('magnitude_std', float('inf')), so it raises on any config string, not just ones containing mstd.

The ops helpers these factories call (auto_augment_policy, rand_augment_ops, augmix_ops, AugmentOp) already guard with hparams = hparams or _HPARAMS_DEFAULT, but the factories dereference hparams before delegating, so that guard is never reached. The internal transforms_factory.py path always passes a real dict, which is why this wasn't caught in normal training runs — it only bites callers who use the factories directly with the documented default.

Fix

Normalize hparams at the top of each factory, mirroring the existing hparams = hparams or _HPARAMS_DEFAULT idiom — but using a copy (dict(_HPARAMS_DEFAULT)). The factories mutate hparams via setdefault, and _HPARAMS_DEFAULT has no magnitude_std key, so reusing the shared module-level dict directly would leak magnitude_std into it and pin that value for every later call that relies on the defaults. Passing a real hparams dict is unchanged.

Tests

Added a parametrized regression test in tests/test_data.py covering every factory and each affected path (the mstd/mmax sections and augmix's unconditional default), asserting the transforms build and that the shared _HPARAMS_DEFAULT is never mutated. It fails on main (6 cases) and passes with the fix; tests/test_data.py + tests/test_factory.py stay green (52 passed).

auto_augment_transform, rand_augment_transform and augment_and_mix_transform
all default hparams to None but call hparams.setdefault(...) for the mstd/mmax
config sections before normalizing it. augment_and_mix_transform also has an
unconditional hparams.setdefault('magnitude_std', inf), so it raised on ANY
config string. Each factory's own documented example (e.g. 'augmix-m5-w4-d2',
'rand-m9-n3-mstd0.5', 'original-mstd0.5') therefore crashed with
'NoneType' object has no attribute 'setdefault' when called without hparams.

Normalize to a copy of _HPARAMS_DEFAULT at the top of each factory, matching
the hparams = hparams or _HPARAMS_DEFAULT guard the ops helpers already use.
A copy is used because the factories mutate hparams via setdefault, which would
otherwise leak magnitude_std into the shared module-level default across calls.
@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

@rwightman
rwightman merged commit 520ed86 into huggingface:main Aug 26, 2026
22 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.

3 participants