MCPcopy Create free account
hub / github.com/AlmondGod/tinyworlds / DynamicsModel

Class DynamicsModel

models/dynamics.py:9–207  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

7from einops import repeat
8
9class DynamicsModel(nn.Module):
10 def __init__(self, frame_size=(128, 128), patch_size=4, embed_dim=128, num_heads=8,
11 hidden_dim=128, num_blocks=4, num_bins=4, n_actions=8, conditioning_dim=3, latent_dim=5,
12 use_moe=False, num_experts=4, top_k_experts=2, moe_aux_loss_coeff=0.01):
13 super().__init__()
14 H, W = frame_size
15 codebook_size = num_bins**latent_dim
16
17 self.latent_embed = nn.Linear(latent_dim, embed_dim)
18 self.transformer = STTransformer(
19 embed_dim, num_heads, hidden_dim, num_blocks, causal=True,
20 conditioning_dim=conditioning_dim,
21 use_moe=use_moe, num_experts=num_experts,
22 top_k_experts=top_k_experts, moe_aux_loss_coeff=moe_aux_loss_coeff,
23 )
24 self.output_mlp = nn.Linear(embed_dim, codebook_size)
25
26 # shared spatial-only PE (zeros in temporal tail)
27 pe_spatial = build_spatial_only_pe((H, W), patch_size, embed_dim, device='cpu', dtype=torch.float32) # [1,P,E]
28 self.register_buffer("pos_spatial_dec", pe_spatial, persistent=False)
29
30 # learnable mask token latent
31 # TODO; try leanable mask embedding in embed space instead of latent space
32 self.mask_token = nn.Parameter(torch.randn(1, 1, 1, latent_dim) * 0.02) # [1, 1, 1, L]
33
34 def forward(self, discrete_latents, training=True, conditioning=None, targets=None):
35 # discrete_latents: [B, T, P, L]
36 # targets: [B, T, P] indices
37 # conditioning: [B, T, A]
38 B, T, P, L = discrete_latents.shape
39
40 # convert latents to float for embedding
41 discrete_latents = discrete_latents.to(dtype=torch.float32)
42
43 # apply MaskGIT random masking during training
44 if training and self.training:
45 # per-batch mask ratio in [0.5, 1.0)
46 mask_ratio = 0.5 + torch.rand((), device=discrete_latents.device) * 0.5
47 mask_positions = (torch.rand(B, T, P, device=discrete_latents.device) < mask_ratio) # [B, T, P]
48
49 # guarantee at least one unmasked temporal anchor per (B, P)
50 # pick a random timestep for each (B,P) and force it to unmask
51 anchor_idx = torch.randint(0, T, (B, P), device=discrete_latents.device) # [B, P]
52 mask_positions[torch.arange(B)[:, None], anchor_idx, torch.arange(P)[None, :]] = False # [B, T, P]
53
54 # replace selected latents with mask tokens
55 mask_token = repeat(self.mask_token.to(discrete_latents.device, discrete_latents.dtype), '1 1 1 L -> B T P L', B=B, T=T, P=P) # [B, T, P, L]
56 discrete_latents = torch.where(mask_positions.unsqueeze(-1), mask_token, discrete_latents) # [B, T, P, L]
57 else:
58 mask_positions = None
59
60 embeddings = self.latent_embed(discrete_latents) # [B, T, P, E]
61
62 # add spatial PE (affects only first 2/3 of dimensions)
63 # STTransformer adds temporal PE to last 1/3 of dimensions
64 embeddings = embeddings + self.pos_spatial_dec.to(embeddings.device, embeddings.dtype)
65 transformed = self.transformer(embeddings, conditioning=conditioning) # [B, T, P, E]
66

Callers 2

mainFunction · 0.90

Calls

no outgoing calls

Tested by

no test coverage detected