Skip to content

Deprecate mae pixio decoder timm - #2006

Open
lorinczszabolcs wants to merge 6 commits into
lightly-ai:masterfrom
lorinczszabolcs:deprecate-mae-pixio-decoder-timm
Open

Deprecate mae pixio decoder timm#2006
lorinczszabolcs wants to merge 6 commits into
lightly-ai:masterfrom
lorinczszabolcs:deprecate-mae-pixio-decoder-timm

Conversation

@lorinczszabolcs

Copy link
Copy Markdown
Contributor

Follow-up to #1978. Now that MaskedVisionTransformerDecoderTIMM covers both, this deprecates the old TIMM decoders, as discussed in the review (#1978 (comment)).

  • MAEDecoderTIMM and PixioDecoderTIMM emit a DeprecationWarning on init pointing to MaskedVisionTransformerDecoderTIMM, and get a docstring note. Both stay functional and exported.
  • Migrated the last first-party consumer (the imagenette benchmark) off MAEDecoderTIMM.
  • Added deprecation tests; marked the existing decoder and equivalence tests to ignore the warning.

@lorinczszabolcs
lorinczszabolcs force-pushed the deprecate-mae-pixio-decoder-timm branch from 4611b13 to f37c5c6 Compare July 28, 2026 20:11
@lorinczszabolcs

Copy link
Copy Markdown
Contributor Author

@gabrielfruet this is the follow-up PR to deprecate MAEDecoderTIMM and PixioDecoderTIMM.

@gabrielfruet gabrielfruet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration is correct. I ran the MAE flow end to end and the mask semantics match the old code. Tests pass: 18 passed, 4 skipped.

Two blockers. PixioDecoderTIMM users never see the deprecation warning, and the benchmark lost the decoder weight init. The other comments are smaller.


One more that will not anchor, because lightly/models/modules/__init__.py is not in the diff.

lightly/models/modules/__init__.py, the MAEDecoderTIMM, PixioDecoderTIMM import

This warns nobody who imports the name and never makes an instance. After the removal, those users get an ImportError with no hint.

A module __getattr__ covers both cases. It needs Python 3.7. Our CI floor is 3.7.

def __getattr__(name: str) -> Any:
    if name in ("MAEDecoderTIMM", "PixioDecoderTIMM"):
        from lightly.models.modules import masked_autoencoder_timm

        warn_deprecated(name, "MaskedVisionTransformerDecoderTIMM", removed_in="1.7.0")
        return getattr(masked_autoencoder_timm, name)
    raise AttributeError(name)

Remove the eager import. If the attribute already exists, __getattr__ never runs. Keep the timm_vit_available() guard.

Keep the warning in the constructor too. A direct import from lightly.models.modules.masked_autoencoder_timm does not pass through here.


Filed #2019 for the repo-wide part, which is out of scope here.

Comment thread lightly/models/modules/masked_autoencoder_timm.py Outdated
Comment thread lightly/models/modules/masked_autoencoder_timm.py
Comment thread tests/models/modules/test_masked_autoencoder_timm.py Outdated
self.sequence_length = vit.patch_embed.num_patches + 1
self.backbone = MaskedVisionTransformerTIMM(vit=vit)
self.decoder = MAEDecoderTIMM(
self.decoder_embed = nn.Linear(vit.embed_dim, decoder_dim)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decoder_embed and prediction_head are plain nn.Linear layers outside the decoder. Nothing initializes them now. Before, _initialize_weights reached them through self.apply(init_weights): xavier uniform weights, zero bias.

At 768 to 512, the decoder_embed weight std moves from 0.0395 to 0.0208, and the max absolute bias moves from 0.0 to 0.0359. This changes what the benchmark trains.

self.decoder_embed.apply(init_weights)
self.prediction_head.apply(init_weights)

test_matches_mae_decoder_full_flow cannot catch this. It copies the weights before it compares. examples/pytorch/mae.py and the other examples have the same gap. That matters more, because people copy the examples.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! Restored, decoder_embed and prediction_head now get init_weights (xavier uniform, zero bias), matching the old decoder init. On the examples having the same gap, they are outside this PR's diff, so I would suggest a small follow-up (or folding it into #2019).

Comment thread docs/source/getting_started/benchmarks/imagenette_benchmark.py Outdated
- add lightly/utils/deprecation.py::warn_deprecated: FutureWarning (shown by the
  default filter, unlike DeprecationWarning) with the 1.7.0 removal version, called
  from each decoder __init__ so the stacklevel points at the caller
- add a package __getattr__ so importing the deprecated names warns and, once
  removed, raises AttributeError instead of a hintless ImportError
- restore the imagenette benchmark decoder init (apply init_weights to decoder_embed
  and prediction_head) and take sequence_length from the backbone
@lorinczszabolcs

Copy link
Copy Markdown
Contributor Author

@gabrielfruet Thanks for the review! Addressed most of it, left a few conversations open with some comments, let me know your thoughts how to proceed.

@gabrielfruet gabrielfruet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything from the last round looks right, thanks. One reversal from me below — the __getattr__ I suggested isn't worth it, sorry for the churn.

Comment thread lightly/models/modules/__init__.py Outdated
Comment thread lightly/models/modules/masked_autoencoder_timm.py
Comment thread lightly/models/modules/masked_autoencoder_timm.py Outdated
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.

2 participants