File size: 2,350 Bytes
92eea42
 
 
 
 
 
 
 
edcb633
92eea42
edcb633
 
c8182c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92eea42
edcb633
 
92eea42
edcb633
92eea42
c8182c9
 
 
 
 
92eea42
 
 
edcb633
92eea42
c8182c9
 
 
 
 
 
 
 
92eea42
 
c8182c9
92eea42
c8182c9
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
---
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)**

![reconstruction](recon_v3_world.png)

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.