-
Notifications
You must be signed in to change notification settings - Fork 360
(draft) feat: add LeWM, an action-conditioned latent world model trained with SIGReg #2032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
gabrielfruet
wants to merge
16
commits into
master
Choose a base branch
from
feat/lewm
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
0a26e73
Add LeWM latent world model
gabrielfruet 9021781
Reach the fused attention kernel through getattr
gabrielfruet fea0671
refactor: require fused attention in LatentDynamicsPredictor
gabrielfruet 44af827
docs: document keyword-only forward and ONNX export in LeWMLoss
gabrielfruet 810f111
feat: add LeWMProjectionHead to the head api
gabrielfruet 4eea61f
refactor: parameterize LeWM example and use LeWMProjectionHead
gabrielfruet 642c432
Merge branch 'master' into feat/lewm
gabrielfruet 55ee663
refactor: remove unnecessary forward comment in LeWMLoss
gabrielfruet 9819388
refactor: rely on LeWM example module defaults instead of constants
gabrielfruet 96e063e
Merge branch 'master' into feat/lewm
gabrielfruet f9e4a51
feat: make LeWM predictor conditioning optional and expose PredictorB…
gabrielfruet 5b088b0
feat: add batch_norm opt-out to LeWMProjectionHead
gabrielfruet 4ec5312
docs: scope LeWM loss docstrings to continuous-latent methods
gabrielfruet b640f07
fix: validate LeWM loss embeddings and guard rollout output_dim
gabrielfruet 60c1b22
docs: fix LeWM example shape contract, timm scope and run command
gabrielfruet 623af45
refactor: extract AdaLNZero conditioning module in LeWM predictor
gabrielfruet File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| .. _lewm: | ||
|
|
||
| LeWM | ||
| ==== | ||
|
|
||
| LeWM [0]_ is a latent world model. It predicts the embedding of the next frame | ||
| from the embeddings of the past frames and the actions that were taken, and it | ||
| never reconstructs pixels. The encoder is trained from pixels together with the | ||
| predictor. SIGReg [1]_ keeps the embeddings close to an isotropic Gaussian, | ||
| which is what prevents collapse, so LeWM needs no stop-gradient, no teacher | ||
| network and no exponential moving average. | ||
|
|
||
| This is the self-supervised idea with one more axis. An SSL method predicts the | ||
| embedding of one view from another view. A world model predicts the embedding | ||
| of the next frame from the past ones, given what the agent did. | ||
|
|
||
| .. warning:: | ||
|
|
||
| LeWM and the ``world_model`` modules are experimental. Their shapes and | ||
| signatures may change in a minor release. | ||
|
|
||
| Key Components | ||
| -------------- | ||
|
|
||
| - **Encoder**: Any image encoder maps a frame to an embedding. The example uses | ||
| a ViT-tiny with a :class:`lightly.models.modules.LeWMProjectionHead` on the | ||
| class token. | ||
| - **Action encoder**: :class:`lightly.models.modules.ActionEncoder` maps a | ||
| low-dimensional action vector to the width of the predictor. | ||
| - **Predictor**: :class:`lightly.models.modules.LatentDynamicsPredictor` is a | ||
| causal transformer over frames. The action at frame ``t`` conditions every | ||
| block through AdaLN-Zero. It is action-conditioned and causal by default; | ||
| ``conditional=False`` gives an actionless predictor and ``causal=False`` a | ||
| bidirectional one, both built from | ||
| :class:`lightly.models.modules.PredictorBlock`. | ||
| - **Loss**: :class:`lightly.loss.LeWMLoss` adds a next-embedding prediction | ||
| term and :class:`lightly.loss.SIGReg`. The weight of the SIGReg term is the | ||
| only hyperparameter that needs tuning. | ||
|
|
||
| The shape contract | ||
| ------------------ | ||
|
|
||
| The predictor reads:: | ||
|
|
||
| embeddings (B, T, D) | ||
| action_emb (B, T, D) | ||
|
|
||
| and returns the predicted next-frame embeddings of shape ``(B, T, D)``. ``B`` | ||
| is the batch, ``T`` the frames of one clip and ``D`` the width. Entry | ||
| ``t`` of the output predicts frame ``t + 1``, and ``action_emb[:, t]`` is the | ||
| action taken **at** frame ``t``. A shape check cannot catch a phase error, so a | ||
| training step reads:: | ||
|
|
||
| predicted = predictor(emb[:, :-1], action_emb=action_emb[:, :-1]) | ||
| target = emb[:, 1:] | ||
|
|
||
| Good to Know | ||
| ------------ | ||
|
|
||
| - **Same regularizer as LeJEPA**: LeWM is LeJEPA over time, with actions. Both | ||
| methods use the same :class:`lightly.loss.SIGReg` class. | ||
| - **The encoder is interchangeable**: The predictor reads embeddings, not | ||
| images, so any backbone works, and a frozen pretrained encoder is | ||
| interchangeable with one trained from scratch. A frozen encoder also cannot | ||
| collapse, because its targets cannot move. | ||
| - **Planning is out of scope**: | ||
| :meth:`lightly.models.modules.LatentDynamicsPredictor.rollout` feeds the | ||
| model its own predictions, which is how a planner scores candidate action | ||
| sequences. The planner itself needs an environment and an episode, so it | ||
| belongs to a control library rather than here. | ||
|
|
||
| .. note:: | ||
|
|
||
| A projection head that ends in ``BatchNorm`` behaves differently in train | ||
| and eval mode, and planning runs in eval mode. Check that the embeddings | ||
| agree between the two modes before trusting a rollout. | ||
|
|
||
| Reference: | ||
|
|
||
| .. [0] `LeWorldModel, 2026 <https://arxiv.org/abs/2603.19312>`_ | ||
| .. [1] `LeJEPA, 2025 <https://arxiv.org/abs/2511.08544>`_ | ||
|
|
||
| .. note:: | ||
|
|
||
| This example requires `TIMM | ||
| <https://github.com/huggingface/pytorch-image-models>`_ to be installed | ||
|
|
||
| .. code-block:: bash | ||
|
|
||
| pip install "lightly[timm]" | ||
|
|
||
| .. tabs:: | ||
| .. tab:: PyTorch | ||
|
|
||
| .. image:: https://img.shields.io/badge/Open%20in%20Colab-blue?logo=googlecolab&label=%20&labelColor=5c5c5c | ||
| :target: https://colab.research.google.com/github/lightly-ai/lightly/blob/master/examples/notebooks/pytorch/lewm.ipynb | ||
|
|
||
| The example generates its own trajectories, so it runs without an | ||
| environment or a recorded dataset. It can be run from the command line | ||
| with:: | ||
|
|
||
| python examples/pytorch/lewm.py | ||
|
|
||
| .. literalinclude:: ../../../examples/pytorch/lewm.py |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: lightly-ai/lightly
Length of output: 5551
🏁 Script executed:
Repository: lightly-ai/lightly
Length of output: 19768
Run the documented Sphinx build.
Run
make html-noplotfromdocs/and fix any unresolved autodoc targets before merge.🤖 Prompt for AI Agents
Source: Coding guidelines