oggata commited on
Commit
1b49036
ยท
verified ยท
1 Parent(s): b2a88f9
Files changed (1) hide show
  1. README.md +228 -0
README.md CHANGED
@@ -1,3 +1,231 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ language:
4
+ - en
5
+ - ja
6
+ library_name: pytorch
7
+ pipeline_tag: other
8
+ tags:
9
+ - world-model
10
+ - dino-wm
11
+ - dinov2
12
+ - simulation
13
+ - video-prediction
14
+ - model-based-planning
15
+ - inverse-dynamics
16
+ - multi-agent
17
  ---
18
+
19
+ # MESA World Model
20
+
21
+ <p align="center">
22
+ <img src="https://static.zenn.studio/user-upload/4b2a18cffa5b-20261111.png" width="400"/>
23
+ </p>
24
+
25
+ <p align="center">
26
+ ๐Ÿ–ฅ๏ธ <a href="https://github.com/oggata/mesa-clouds-renderer">GitHub</a> &nbsp;&nbsp;|&nbsp;&nbsp;
27
+ ๐Ÿค— <a href="https://huggingface.co/oggata">Hugging Face</a> &nbsp;&nbsp;|&nbsp;&nbsp;
28
+ ๐ŸŽฎ <a href="https://huggingface.co/spaces/oggata/mesa-world-model-sim">Demo (Space)</a> &nbsp;&nbsp;|&nbsp;&nbsp;
29
+ ๐Ÿ“‘ <a href="https://zenn.dev/oggata/books/fccaa80b4c38bb">Blog</a> &nbsp;&nbsp;|&nbsp;&nbsp;
30
+ ๐ŸŽฌ <a href="https://www.youtube.com/watch?v=jidF7Oky-XU">Video</a>
31
+ </p>
32
+
33
+ -----
34
+
35
+ **MESA** (**M**ulti **E**ntity **S**imulation **A**rchitecture) is a town simulation in which many residents live and walk around a procedurally generated city.
36
+ This repository contains a small **action-conditioned world model** that has learned what a MESA resident *sees* when they walk.
37
+
38
+ Given the last few first-person frames and an action (**forward / turn left / turn right / backward**), the model predicts **what the resident will see next**.
39
+ It does this in the feature space of a frozen DINOv2 encoder, following the [DINO-WM](https://arxiv.org/abs/2411.04983) recipe, and a separate decoder turns the predicted features back into images so you can watch the model "dream".
40
+
41
+ - ๐Ÿง  **Learned simulator**: the forward-dynamics Transformer replaces the renderer. Chain its predictions and you can walk through the town entirely inside the model's imagination.
42
+ - ๐Ÿ—บ๏ธ **Generalizes to unseen towns**: trained on 64 procedurally generated towns and evaluated on 16 towns it has never seen. It learns *how the view moves* when you walk or turn, not a memorized map.
43
+ - ๐Ÿ” **Forward and inverse dynamics**: besides predicting the future, an inverse-dynamics head recovers the action taken between two frames (video โ†’ action).
44
+ - ๐ŸŽฏ **Planning in imagination**: given only a goal image, the agent can search for action sequences inside the model (CEM + MPC) and then execute them in the real environment.
45
+ - ๐Ÿชถ **Small and cheap**: about 11M trainable parameters in the world model. It runs on a free CPU Space, and the whole pipeline trains from scratch in one Colab notebook (about 40โ€“60 minutes on an A100).
46
+
47
+ ## Video Demos
48
+
49
+ <p align="center">
50
+ <a href="https://www.youtube.com/watch?v=jidF7Oky-XU">
51
+ <img src="https://img.youtube.com/vi/jidF7Oky-XU/maxresdefault.jpg" width="80%" alt="MESA World Model demo video"/>
52
+ </a>
53
+ </p>
54
+
55
+ ## Try it in the browser
56
+
57
+ The [**MESA World Model Simulator**](https://huggingface.co/spaces/oggata/mesa-world-model-sim) Space loads the weights from this repository.
58
+ Press **forward / left / right / back** and the Space renders two videos side by side:
59
+
60
+ - **Left: the real renderer**, which executes your actions in the actual town.
61
+ - **Right: the world model's imagination**, which starts from DINOv2 features of what the resident currently sees and predicts each next step from the action alone.
62
+
63
+ Untick "re-imagine from what is actually visible each time" to keep dreaming on top of the model's own predictions, and you can watch the errors build up over time.
64
+
65
+ ## Model Overview
66
+
67
+ ```
68
+ first-person image โ”€โ”€DINOv2 ViT-S/14 (frozen)โ”€โ”€> z_t (16ร—16 patch tokens ร— 384) โ”€โ”
69
+ โ”œโ”€ World model (Transformer) โ”€> z_{t+1}
70
+ action a_t โˆˆ {forward, left, right, backward} โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
71
+ (z_t, z_{t+1}) โ”€โ”€ Inverse dynamics โ”€โ”€> a_t
72
+ z โ”€โ”€ Decoder โ”€โ”€> 128ร—128 image (only used to look at the imagination, never for planning)
73
+ ```
74
+
75
+ | Component | Architecture | Params | Notes |
76
+ | --- | --- | --- | --- |
77
+ | Encoder | DINOv2 ViT-S/14 (`facebookresearch/dinov2:dinov2_vits14`) | 21M (frozen) | 224ร—224 image โ†’ 16ร—16 patch tokens, 384-d each. Not stored here; loaded from `torch.hub` |
78
+ | World model (forward dynamics) | Pre-norm Transformer encoder, width 384, 6 layers, 8 heads | 11.0M | Context of 3 frames (768 tokens). Action embedding is added to every token. A frame-level causal mask lets frame *i* attend only to frames 0..*i*. Predicts a residual on top of the previous frame's features, so training starts from "nothing changes" |
79
+ | Decoder | Conv up-sampler (16ร—16 โ†’ 128ร—128) with residual blocks | 4.9M | Also receives the last real frame as a context image, so wall textures and colors can be copied from it. Trained with L1 + VGG16 perceptual + PatchGAN losses and EMA weights |
80
+ | Inverse dynamics | Linear reduction (384 โ†’ 32) + 3-layer MLP | 8.7M | (z_t, z_{t+1}) โ†’ logits over the 4 actions |
81
+
82
+ ### Action space
83
+
84
+ Each step either moves the resident 0.2 cells or rotates them by 12ยฐ.
85
+
86
+ | Index | Action | `config.json` label |
87
+ | --- | --- | --- |
88
+ | 0 | forward | `ๅ‰้€ฒ` |
89
+ | 1 | turn left | `ๅทฆ` |
90
+ | 2 | turn right | `ๅณ` |
91
+ | 3 | backward | `ๅพŒ้€€` |
92
+
93
+ Walking into a building or tree is blocked, and the view stays the same. The model has learned to predict this as well.
94
+
95
+ ## Files
96
+
97
+ | File | Contents |
98
+ | --- | --- |
99
+ | `world_model.safetensors` | World model (forward dynamics) |
100
+ | `decoder.safetensors` | Features โ†’ `thumb`ร—`thumb` image decoder |
101
+ | `inverse_dynamics.safetensors` | (current, next) features โ†’ action |
102
+ | `feat_stats.safetensors` | Mean `mu` and std `sd` used to standardize DINOv2 features (required before feeding the world model) |
103
+ | `config.json` | Model sizes, action order, renderer settings, the town seeds used for training and evaluation, and the full training config (`train.preset`) |
104
+
105
+ ## Quickstart
106
+
107
+ The loader, renderer and simulator code live in the `mesa_wm` package of the Space.
108
+
109
+ ```sh
110
+ pip install torch numpy pillow safetensors huggingface_hub
111
+ hf download oggata/mesa-world-model-sim --repo-type space --local-dir mesa-world-model-sim
112
+ cd mesa-world-model-sim
113
+ ```
114
+
115
+ ```python
116
+ from huggingface_hub import snapshot_download
117
+ from mesa_wm import Simulator, save_gif
118
+
119
+ sim = Simulator(snapshot_download("oggata/mesa-world-model-sharp-v01"), device="cpu") # or "cuda"
120
+
121
+ # Stand on a road in a town that was never used for training
122
+ st = sim.reset(seed=sim.cfg["maps"]["test_seeds"][0], start_seed=0)
123
+
124
+ # Walk forward 6 steps, then turn left 6 steps
125
+ real, imagined, st = sim.run(st, [0] * 6 + [1] * 6)
126
+
127
+ save_gif(real, imagined, "walk.gif") # left: real renderer, right: imagination
128
+ ```
129
+
130
+ `sim.run(..., sync=False)` keeps imagining from the previous imagination instead of re-encoding what is actually visible.
131
+
132
+ To run the Gradio app locally:
133
+
134
+ ```sh
135
+ MODEL_REPO=oggata/mesa-world-model-sharp-v01 python app.py
136
+ ```
137
+
138
+ ## Training
139
+
140
+ ### Data
141
+
142
+ All data is generated on the fly, so no external dataset is needed.
143
+
144
+ - **Towns**: 30ร—30-cell procedural cities built with the same map generator as the MESA simulation (a road grid with some roads randomly removed, buildings and trees). There are 64 towns for training and a separate 16 for evaluation.
145
+ - **Renderer**: a textured DDA ray caster matched to [mesa-clouds-renderer](https://github.com/oggata/mesa-clouds-renderer). It uses the same building photos and per-business heights (including 2ร—2 buildings), asphalt with sidewalks and road markings, grass, dirt, trees, a daytime sky and distance fog.
146
+ - **Behavior**: a random walker that keeps an action for a while and occasionally switches (forward 45%, left / right 20% each, backward 15%), so all actions are well covered.
147
+ - **Size**: 64 towns ร— 8 episodes ร— 101 frames = **51,712 training frames**, plus 6,464 evaluation frames from unseen towns.
148
+
149
+ ### Procedure
150
+
151
+ Everything is trained from scratch in a single notebook ([`colab/world_model_mesa.ipynb`](colab/world_model_mesa.ipynb)). The notebook has three presets. **The weights in this repository use `sharp`.**
152
+
153
+ | Preset | Tokens | Decoded image | World model (width ยท layers ยท params) | WM steps | Rollout | Decoder | A100 time |
154
+ | --- | --- | --- | --- | --- | --- | --- | --- |
155
+ | `fast` | 8ร—8 | 64ร—64 | 256 ยท 6 ยท ~5M | 12k | 1 | L1 only | ~10 min |
156
+ | **`sharp`** โœ… | 16ร—16 | 128ร—128 | 384 ยท 6 ยท ~11M | 20k | 2 | L1 + perceptual + GAN, context image | 40โ€“60 min |
157
+ | `sharper` | 16ร—16 | 128ร—128 | 512 ยท 8 ยท ~26M | 30k | 2 | wider, 2 res blocks | 1.5โ€“2.5 h |
158
+
159
+ Key hyper-parameters for `sharp`: batch 32, AdamW with lr 3e-4. The world model is trained with a 2-step rollout loss, feeding its own prediction back as input, which reduces blurring over long horizons. The decoder is trained for 10k steps with perceptual weight 0.2 and GAN weight 0.1. To make it robust to imagined features, training adds noise of 0.3 to the features and uses imagined features for 25% of samples. The inverse-dynamics head is trained for 3k steps.
160
+
161
+ ## Evaluation
162
+
163
+ The model is evaluated on **towns never seen during training**. It gets the last 3 real frames plus the next 15 actions, and its imagined features are compared with the features from actually walking those actions. The baseline predicts "nothing changes", reusing the last observed frame.
164
+
165
+ Reference numbers from the `fast` preset (book, chapter 14). Feature MSE, lower is better:
166
+
167
+ | Horizon | World model | "Nothing changes" baseline |
168
+ | --- | --- | --- |
169
+ | 1 step | โ‰ˆ 0.22 | โ‰ˆ 0.49 |
170
+ | 15 steps | โ‰ˆ 1.0 | โ‰ˆ 1.54 |
171
+
172
+ The world model beats the baseline at every horizon. The `sharp` model in this repository uses 4ร— more tokens, a larger model and a rollout loss. Its own numbers are printed by the notebook but have not been reported in this card yet.
173
+
174
+ The notebook also evaluates:
175
+
176
+ - **Counterfactuals ("what if?")**: imagining different action plans from the same spot, side by side with the real renderer. This includes walking straight into a wall and stopping.
177
+ - **Inverse dynamics**: accuracy of recovering the action from two consecutive frames. A blocked forward step is inherently ambiguous, because both frames are identical.
178
+ - **Goal-image planning**: CEM in imagination (10-step plans, MPC re-planning every step), compared with a random walker. Success means getting within 0.5 cells and 25ยฐ of the goal.
179
+
180
+ ## Limitations
181
+
182
+ - Trained **only on the synthetic MESA renderer** (30ร—30-cell towns). It will not work on photos or real street imagery.
183
+ - Imagination is autoregressive: each prediction is fed back as input, so frames **get blurrier the further ahead you go**.
184
+ - Decoded images are 128ร—128 (64ร—64 for `fast`), so fine details such as text on shop signs are not reproduced.
185
+ - The released `sharp` weights were trained **without other residents (NPCs)** (`NPCS = 0`). The architecture supports NPCs as extra tokens, which pass the residents' positions as a tensor, but these weights do not use them.
186
+ - `config.json` stores action labels in Japanese. Use the integer indices above.
187
+
188
+ ## Intended Use
189
+
190
+ This is a research and education model. It is meant for learning how latent world models work (forward and inverse dynamics, imagination rollouts, planning in latent space) on a small, fully controllable world, and as a building block for experiments with agents in the MESA town simulation.
191
+
192
+ ## Related
193
+
194
+ - ๐Ÿ“‘ Blog / book (Japanese): [NVIDIA Cosmos 3 practical guide](https://zenn.dev/oggata/books/fccaa80b4c38bb). Chapter 14 builds this world model, chapter 14.5 improves the decoder, and chapter 17 drives it with language goals through Cosmos Reason.
195
+ - ๐Ÿ–ฅ๏ธ Renderer: [oggata/mesa-clouds-renderer](https://github.com/oggata/mesa-clouds-renderer)
196
+ - ๐ŸŽฎ Space: [oggata/mesa-world-model-sim](https://huggingface.co/spaces/oggata/mesa-world-model-sim)
197
+
198
+ ## Citation
199
+
200
+ If you find this work useful, please cite this repository and the works it builds on:
201
+
202
+ ```bibtex
203
+ @misc{mesa_world_model_2026,
204
+ title = {MESA World Model: an action-conditioned DINO-WM style world model for the MESA town simulation},
205
+ author = {oggata},
206
+ year = {2026},
207
+ howpublished = {\url{https://huggingface.co/oggata/mesa-world-model-sharp-v01}}
208
+ }
209
+
210
+ @article{zhou2024dinowm,
211
+ title = {DINO-WM: World Models on Pre-trained Visual Features enable Zero-shot Planning},
212
+ author = {Zhou, Gaoyue and Pan, Hengkai and LeCun, Yann and Pinto, Lerrel},
213
+ journal = {arXiv preprint arXiv:2411.04983},
214
+ year = {2024}
215
+ }
216
+
217
+ @article{oquab2023dinov2,
218
+ title = {DINOv2: Learning Robust Visual Features without Supervision},
219
+ author = {Oquab, Maxime and Darcet, Timoth{\'e}e and Moutakanni, Th{\'e}o and others},
220
+ journal = {arXiv preprint arXiv:2304.07193},
221
+ year = {2023}
222
+ }
223
+ ```
224
+
225
+ ## License
226
+
227
+ The weights in this repository are released under the Apache 2.0 License. The frozen DINOv2 encoder is downloaded separately from [facebookresearch/dinov2](https://github.com/facebookresearch/dinov2) and is subject to its own license.
228
+
229
+ ## Acknowledgements
230
+
231
+ Thanks to the authors of [DINO-WM](https://github.com/gaoyuezhou/dino_wm) for the world-model recipe, [DINOv2](https://github.com/facebookresearch/dinov2) for the visual features, and [Hugging Face](https://huggingface.co) for hosting the model and the Space.