| --- |
| license: mit |
| tags: |
| - reinforcement-learning |
| - autoencoder |
| - games |
| --- |
| |
| # OpenFront spatial autoencoder |
|
|
| Frozen spatial observation encoder for [OpenFront.io](https://openfront.io) |
| RL agents: compresses tile ownership + terrain + fallout + static structures |
| into a latent grid (any map size). Structure detection is at precision/recall |
| 1.0 per class for every model below. |
|
|
| **Current best: `ae_v31_d8.pt`** — v3.1 architecture (terrain-conditioned |
| nearest-upsample decoder, focal loss, border-dense sampling, cosine LR) with |
| the latent at 1/8 resolution instead of 1/16. Trained 40k steps on a mixed |
| corpus of bot self-play and real archived human games. |
|
|
| Border-tile accuracy (the hard metric — overall tile accuracy saturates at |
| ~99% for all models), uniform 256-crop eval: |
|
|
| | checkpoint | latent | human border | bot border | human tiles | bot tiles | |
| |---|---|---|---|---|---| |
| | `ae_v31_d8.pt` | 64ch @ 1/8 | **89.3%** | **96.1%** | 99.6% | 99.8% | |
| | `ae_v31.pt` | 64ch @ 1/16 | 78.5% | 90.7% | 99.1% | 99.6% | |
| | `ae_v3.pt` (bot-only) | 64ch @ 1/16 | 71.8% | 87.5% | 99.2% | 99.4% | |
|
|
| The ablation story: mixing human games into training fixes the human-domain |
| gap, the v3.1 decoder/loss fixes add a few points, and latent *resolution* |
| (not channel count) is what finally cracks border geometry — borders are |
| high-frequency spatial detail that can't be bought back with more channels. |
|
|
| Full details, training code, results, and roadmap: |
| **[github.com/djmango/openfront-ai](https://github.com/djmango/openfront-ai)** |
|
|
|  |
|
|
| Trained on |
| [djmango/openfront-snapshots](https://huggingface.co/datasets/djmango/openfront-snapshots) |
| (bot) and |
| [djmango/openfront-human-games](https://huggingface.co/datasets/djmango/openfront-human-games) |
| (human). |
|
|
| ```python |
| import torch |
| from ae.model_v3 import SpatialAE |
| |
| ckpt = torch.load("ae_v31_d8.pt", map_location="cpu", weights_only=False) |
| a = ckpt["args"] |
| model = SpatialAE( |
| latent_c=a["latent_c"], |
| terrain_cond=a.get("terrain_cond", False), |
| upsample_decoder=a.get("upsample_decoder", False), |
| latent_down=a.get("latent_down", 16), |
| ) |
| model.load_state_dict(ckpt["model_state_dict"]) |
| model.eval() |
| z = model.encode(owner_slots, terrain, static_planes) # (B, 64, H/8, W/8) |
| ``` |
|
|
| `ae.pt` (v1 tile-only `TileAutoencoder` in `model.py`) is kept for history. |
|
|