|
Download README.md from jgalego/space-invaders-world-model: direct link, hf CLI and curl.
- Browser
- Download file 3.42 kB
-
https://huggingface.co/jgalego/space-invaders-world-model/resolve/main/README.md
- Command line
-
hf download hf://jgalego/space-invaders-world-model/README.md
-
curl -L -o README.md https://huggingface.co/jgalego/space-invaders-world-model/resolve/main/README.md
3.42 kB
| library_name: pytorch | |
| license: apache-2.0 | |
| tags: | |
| - world-model | |
| - diffusion | |
| - atari | |
| - space-invaders | |
| - video-generation | |
| model-index: | |
| - name: space-invaders-world-model | |
| results: | |
| - task: | |
| type: other | |
| name: Next-frame rollout | |
| dataset: | |
| name: Space Invaders, held-out random play | |
| type: ale/space-invaders | |
| metrics: | |
| - type: psnr_changed_1 | |
| value: 18.17 | |
| name: PSNR on changed pixels at 1 frames | |
| - type: psnr_changed_5 | |
| value: 18.35 | |
| name: PSNR on changed pixels at 5 frames | |
| - type: psnr_changed_15 | |
| value: 16.64 | |
| name: PSNR on changed pixels at 15 frames | |
| # space-invaders-world-model | |
| A diffusion world model of Atari Space Invaders, trained from scratch. Given the last 4 frames and actions, a small U-Net denoises the next 64×64 frame; fed its own frames, it generates a video that your actions steer. After [DIAMOND](https://arxiv.org/abs/2405.12399). `atari.py` in this repo collects the data, trains, plays and doubles as the loader. | |
|  | |
| Left: real game. Right: the model, from the same four starting frames and the same actions, never seeing a real frame again. | |
| ## 🚀 Usage | |
| Play it in the browser. Each button press generates one frame: | |
| ``` | |
| uv run "$(hf download jgalego/space-invaders-world-model atari.py --quiet)" play --game SpaceInvaders | |
| ``` | |
| From Python, with `atari.py` on the path: | |
| ```python | |
| import torch | |
| from atari import DEVICE, collect, load, rollout, to_float | |
| model = load("jgalego/space-invaders-world-model") | |
| frames, _, _ = collect(4, seed=0, game="SpaceInvaders") # four real frames to start from | |
| context = to_float(frames[:4])[None].to(DEVICE) | |
| moves = torch.tensor([[0, 0, 0] + [1] * 16], device=DEVICE) # FIRE for 16 frames | |
| video = rollout(model, context, moves) # (1, 16, 3, 64, 64) in [-1, 1] | |
| ``` | |
| Actions: 0 NOOP, 1 FIRE, 2 RIGHT, 3 LEFT, 4 RIGHTFIRE, 5 LEFTFIRE. | |
| ## 🏋️ Training | |
| | | | | |
| |---|---| | |
| | Model | U-Net, channels 64, 128, 256, 4.2M parameters; noise level and the last 4 actions modulate every block | | |
| | Diffusion | EDM preconditioning, σ_data 0.5, log-normal training noise; 3 Euler steps per frame from σ=5.0 | | |
| | Data | 200,000 frames (382 episodes) of a random policy that holds each uniformly random action for 1 to 6 steps; frameskip 4, no sticky actions | | |
| | Steps | 50,000, batch size 64 | | |
| | Optimizer | AdamW, lr 0.0001, gradient clipping 1.0 | | |
| | Hardware | NVIDIA A10G, 55.9 min | | |
| ## 📊 Results | |
| Rollouts on 256 windows from episodes whose seeds never appear in training. The model gets four real frames and the real actions, then only its own frames. **Repeat** keeps showing the last real frame. Much of an Atari frame never changes, so **changed pixels** scores only the pixels where the real or the predicted frame differs from the last real frame. | |
| | Frames ahead | Model, all pixels (dB) | Repeat, all pixels (dB) | Model, changed pixels (dB) | Repeat, changed pixels (dB) | | |
| |---|---|---|---|---| | |
| | 1 | 35.43 | 36.56 | 18.17 | 16.0 | | |
| | 5 | 31.07 | 30.94 | 18.35 | 15.9 | | |
| | 15 | 27.33 | 26.77 | 16.64 | 14.54 | | |
| ## ⚠️ Limitations | |
| - A random policy does not get far, so the model knows the early game best. | |
| - 64×64 frames: small sprites are a pixel or two and can blur or vanish over long rollouts. | |
| - Errors compound: every generated frame becomes input for the next. |