AbstractPhil commited on
Commit
b08edd4
·
verified ·
1 Parent(s): 6d3fbb7

Create cell2_model.py

Browse files
Files changed (1) hide show
  1. cell2_model.py +117 -0
cell2_model.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Superposition Patch Classifier - Architecture & Loss
3
+ =====================================================
4
+ Colab Cell 2 of 3 - depends on Cell 1 (generator.py) namespace.
5
+
6
+ Defines model architecture and loss.
7
+ """
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+
13
+ # Cell 1 provides: all constants (GZ, GY, GX, MACRO_*, PATCH_*, NUM_CLASSES, NUM_GATES, CLASS_NAMES, etc.)
14
+ # generate_dataset, analyze_patches_torch
15
+
16
+ # === Model Architecture =======================================================
17
+ NUM_DIMS, NUM_CURVS, NUM_TOPOS = 4, 3, 2
18
+
19
+
20
+ class PatchEmbedding3D(nn.Module):
21
+ def __init__(self, patch_dim=64):
22
+ super().__init__()
23
+ self.proj = nn.Linear(PATCH_VOL, patch_dim)
24
+ pz = torch.arange(MACRO_Z).float() / MACRO_Z
25
+ py = torch.arange(MACRO_Y).float() / MACRO_Y
26
+ px = torch.arange(MACRO_X).float() / MACRO_X
27
+ pos = torch.stack(torch.meshgrid(pz, py, px, indexing='ij'), dim=-1).reshape(MACRO_N, 3)
28
+ self.register_buffer('pos_embed', pos)
29
+ self.pos_proj = nn.Linear(3, patch_dim)
30
+
31
+ def forward(self, x):
32
+ B = x.shape[0]
33
+ patches = x.view(B, MACRO_Z, PATCH_Z, MACRO_Y, PATCH_Y, MACRO_X, PATCH_X)
34
+ patches = patches.permute(0, 1, 3, 5, 2, 4, 6).contiguous().view(B, MACRO_N, PATCH_VOL)
35
+ return self.proj(patches) + self.pos_proj(self.pos_embed)
36
+
37
+
38
+ class TransformerBlock(nn.Module):
39
+ def __init__(self, dim, n_heads, dropout=0.1):
40
+ super().__init__()
41
+ self.attn = nn.MultiheadAttention(dim, n_heads, dropout=dropout, batch_first=True)
42
+ self.ff = nn.Sequential(
43
+ nn.Linear(dim, dim * 4), nn.GELU(), nn.Dropout(dropout),
44
+ nn.Linear(dim * 4, dim), nn.Dropout(dropout)
45
+ )
46
+ self.ln1, self.ln2 = nn.LayerNorm(dim), nn.LayerNorm(dim)
47
+
48
+ def forward(self, x):
49
+ x = x + self.attn(self.ln1(x), self.ln1(x), self.ln1(x))[0]
50
+ return x + self.ff(self.ln2(x))
51
+
52
+
53
+ class SuperpositionPatchClassifier(nn.Module):
54
+ def __init__(self, embed_dim=128, patch_dim=64, n_layers=4, n_heads=4, dropout=0.1):
55
+ super().__init__()
56
+ self.patch_embed = PatchEmbedding3D(patch_dim)
57
+ self.proj = nn.Linear(patch_dim, embed_dim)
58
+ self.blocks = nn.ModuleList([TransformerBlock(embed_dim, n_heads, dropout) for _ in range(n_layers)])
59
+
60
+ # Per-patch heads
61
+ self.patch_dim_head = nn.Linear(embed_dim, NUM_DIMS)
62
+ self.patch_curv_head = nn.Linear(embed_dim, NUM_CURVS)
63
+ self.patch_topo_head = nn.Linear(embed_dim, NUM_TOPOS)
64
+ self.patch_gate_head = nn.Linear(embed_dim, NUM_GATES)
65
+ self.patch_shape_head = nn.Linear(embed_dim, NUM_CLASSES)
66
+ self.patch_conf_head = nn.Linear(embed_dim, 1)
67
+
68
+ # Global heads
69
+ self.global_pool = nn.Sequential(nn.Linear(embed_dim, embed_dim), nn.GELU(), nn.Linear(embed_dim, embed_dim))
70
+ self.global_gate_head = nn.Linear(embed_dim, NUM_GATES)
71
+ self.global_shape_head = nn.Linear(embed_dim, NUM_CLASSES)
72
+
73
+ def forward(self, x):
74
+ h = self.proj(self.patch_embed(x))
75
+ for blk in self.blocks:
76
+ h = blk(h)
77
+ g = self.global_pool(h.mean(dim=1))
78
+ return {
79
+ "patch_features": h,
80
+ "patch_dim_logits": self.patch_dim_head(h),
81
+ "patch_curv_logits": self.patch_curv_head(h),
82
+ "patch_topo_logits": self.patch_topo_head(h),
83
+ "patch_gate_logits": self.patch_gate_head(h),
84
+ "patch_gate_soft": torch.sigmoid(self.patch_gate_head(h)),
85
+ "patch_shape_logits": self.patch_shape_head(h),
86
+ "patch_confidence": torch.sigmoid(self.patch_conf_head(h)).squeeze(-1),
87
+ "global_features": g,
88
+ "global_gates": self.global_gate_head(g),
89
+ "global_shapes": self.global_shape_head(g),
90
+ }
91
+
92
+
93
+ class SuperpositionLoss(nn.Module):
94
+ def __init__(self, patch_weight=1.0, global_weight=0.5, cross_weight=0.1, conf_weight=0.1):
95
+ super().__init__()
96
+ self.pw, self.gw, self.cw, self.confw = patch_weight, global_weight, cross_weight, conf_weight
97
+
98
+ def forward(self, outputs, targets):
99
+ occ_mask = targets["patch_occupancy"] > 0.01
100
+ n_occ = occ_mask.sum().clamp(min=1)
101
+
102
+ dims_loss = F.cross_entropy(outputs["patch_dim_logits"].view(-1, NUM_DIMS), targets["patch_dims"].clamp(0, NUM_DIMS-1).view(-1), reduction='none').view_as(occ_mask)
103
+ curv_loss = F.cross_entropy(outputs["patch_curv_logits"].view(-1, NUM_CURVS), targets["patch_curvature"].clamp(0, NUM_CURVS-1).view(-1), reduction='none').view_as(occ_mask)
104
+ topo_loss = F.cross_entropy(outputs["patch_topo_logits"].view(-1, NUM_TOPOS), targets["patch_topology"].clamp(0, NUM_TOPOS-1).view(-1), reduction='none').view_as(occ_mask)
105
+ gate_loss = F.binary_cross_entropy_with_logits(outputs["patch_gate_logits"], targets["patch_labels"], reduction='none').mean(dim=-1)
106
+ shape_loss = F.binary_cross_entropy_with_logits(outputs["patch_shape_logits"], targets["patch_shape_membership"], reduction='none').mean(dim=-1)
107
+
108
+ patch_loss = ((dims_loss + curv_loss + topo_loss + gate_loss + shape_loss) * occ_mask.float()).sum() / n_occ
109
+
110
+ global_gate_loss = F.binary_cross_entropy_with_logits(outputs["global_gates"], targets["global_gates"])
111
+ global_shape_loss = F.binary_cross_entropy_with_logits(outputs["global_shapes"], targets["global_shapes"])
112
+ global_loss = global_gate_loss + global_shape_loss
113
+
114
+ return {"total": self.pw * patch_loss + self.gw * global_loss, "patch": patch_loss, "global": global_loss}
115
+
116
+
117
+ print("✓ Model ready")