djmango commited on
Commit
7e3d211
·
verified ·
1 Parent(s): 4c070b4

Upload model.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. model.py +72 -0
model.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Fully-convolutional autoencoder over OpenFront tile states.
2
+
3
+ Input encoding per tile:
4
+ - owner slot -> learned embedding (static slot per player for a whole game,
5
+ slot 0 = unowned, slots 1..MAX_SLOTS-1 assigned by smallID order at spawn)
6
+ - terrain scalars: land flag, normalized magnitude, fallout flag
7
+
8
+ The encoder downsamples by 16x into a spatial latent grid (LATENT_C channels
9
+ per 16x16 tile region), so any map size divisible by 16 works. The decoder
10
+ reconstructs per-tile owner-slot logits.
11
+ """
12
+
13
+ import torch
14
+ import torch.nn as nn
15
+
16
+ MAX_SLOTS = 128 # owner classes: 0 = unowned, 1..127 player slots
17
+ OWNER_EMB_DIM = 8
18
+ TERRAIN_CHANNELS = 3 # land, magnitude, fallout
19
+
20
+
21
+ def conv_block(c_in: int, c_out: int, stride: int) -> nn.Sequential:
22
+ return nn.Sequential(
23
+ nn.Conv2d(c_in, c_out, kernel_size=3, stride=stride, padding=1),
24
+ nn.GroupNorm(8, c_out),
25
+ nn.SiLU(),
26
+ )
27
+
28
+
29
+ def deconv_block(c_in: int, c_out: int) -> nn.Sequential:
30
+ return nn.Sequential(
31
+ nn.ConvTranspose2d(c_in, c_out, kernel_size=4, stride=2, padding=1),
32
+ nn.GroupNorm(8, c_out),
33
+ nn.SiLU(),
34
+ )
35
+
36
+
37
+ class TileAutoencoder(nn.Module):
38
+ def __init__(self, latent_c: int = 64):
39
+ super().__init__()
40
+ self.owner_emb = nn.Embedding(MAX_SLOTS, OWNER_EMB_DIM)
41
+ c_in = OWNER_EMB_DIM + TERRAIN_CHANNELS
42
+
43
+ self.encoder = nn.Sequential(
44
+ conv_block(c_in, 32, stride=1),
45
+ conv_block(32, 64, stride=2), # /2
46
+ conv_block(64, 96, stride=2), # /4
47
+ conv_block(96, 128, stride=2), # /8
48
+ conv_block(128, 128, stride=2), # /16
49
+ nn.Conv2d(128, latent_c, kernel_size=1),
50
+ )
51
+
52
+ self.decoder = nn.Sequential(
53
+ conv_block(latent_c, 128, stride=1),
54
+ deconv_block(128, 128), # /8
55
+ deconv_block(128, 96), # /4
56
+ deconv_block(96, 64), # /2
57
+ deconv_block(64, 32), # /1
58
+ nn.Conv2d(32, MAX_SLOTS, kernel_size=1),
59
+ )
60
+
61
+ def encode(self, owners: torch.Tensor, terrain: torch.Tensor) -> torch.Tensor:
62
+ """owners: (B, H, W) int64 slots; terrain: (B, 3, H, W) float."""
63
+ emb = self.owner_emb(owners).permute(0, 3, 1, 2) # (B, E, H, W)
64
+ x = torch.cat([emb, terrain], dim=1)
65
+ return self.encoder(x)
66
+
67
+ def forward(
68
+ self, owners: torch.Tensor, terrain: torch.Tensor
69
+ ) -> tuple[torch.Tensor, torch.Tensor]:
70
+ z = self.encode(owners, terrain)
71
+ logits = self.decoder(z) # (B, MAX_SLOTS, H, W)
72
+ return logits, z