Faz2 dep: code/meshai_train/models.py
Browse files- code/meshai_train/models.py +76 -0
code/meshai_train/models.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
|
| 6 |
+
from meshai_bridge.latent_adapter import TrellisHunyuanLatentAdapter
|
| 7 |
+
|
| 8 |
+
GEOM_IN_DIM = 4096 + 6
|
| 9 |
+
VOXEL_OUT_DIM = 32 * 32 * 32
|
| 10 |
+
TEXTURE_LATENT_DIM = 512
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class GeometryVoxelHead(nn.Module):
|
| 14 |
+
def __init__(self, in_dim: int = GEOM_IN_DIM, out_dim: int = VOXEL_OUT_DIM) -> None:
|
| 15 |
+
super().__init__()
|
| 16 |
+
self.net = nn.Sequential(
|
| 17 |
+
nn.Linear(in_dim, 2048),
|
| 18 |
+
nn.GELU(),
|
| 19 |
+
nn.Linear(2048, 4096),
|
| 20 |
+
nn.GELU(),
|
| 21 |
+
nn.Linear(4096, out_dim),
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 25 |
+
return self.net(x)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
class TextureViewEncoder(nn.Module):
|
| 29 |
+
"""Multi-view CNN -> conditioning vector for Hunyuan path."""
|
| 30 |
+
|
| 31 |
+
def __init__(self, out_dim: int = TEXTURE_LATENT_DIM, render_size: int = 128) -> None:
|
| 32 |
+
super().__init__()
|
| 33 |
+
self.render_size = render_size
|
| 34 |
+
self.backbone = nn.Sequential(
|
| 35 |
+
nn.Conv2d(3, 32, 3, stride=2, padding=1),
|
| 36 |
+
nn.GELU(),
|
| 37 |
+
nn.Conv2d(32, 64, 3, stride=2, padding=1),
|
| 38 |
+
nn.GELU(),
|
| 39 |
+
nn.Conv2d(64, 128, 3, stride=2, padding=1),
|
| 40 |
+
nn.GELU(),
|
| 41 |
+
nn.AdaptiveAvgPool2d(1),
|
| 42 |
+
)
|
| 43 |
+
flat = 128
|
| 44 |
+
self.proj = nn.Linear(flat, out_dim)
|
| 45 |
+
|
| 46 |
+
def forward(self, views: torch.Tensor) -> torch.Tensor:
|
| 47 |
+
# views: [B, V, 3, H, W] — mean pool over views
|
| 48 |
+
b, v, c, h, w = views.shape
|
| 49 |
+
x = views.reshape(b * v, c, h, w)
|
| 50 |
+
feats = self.backbone(x).reshape(b, v, -1).mean(dim=1)
|
| 51 |
+
return self.proj(feats)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class MeshAIHybridTrainBundle(nn.Module):
|
| 55 |
+
"""Geometry voxel + texture views + TRELLIS→Hunyuan latent bridge."""
|
| 56 |
+
|
| 57 |
+
def __init__(self) -> None:
|
| 58 |
+
super().__init__()
|
| 59 |
+
self.geometry = GeometryVoxelHead()
|
| 60 |
+
self.texture = TextureViewEncoder()
|
| 61 |
+
self.bridge = TrellisHunyuanLatentAdapter(
|
| 62 |
+
trellis_dim=GEOM_IN_DIM,
|
| 63 |
+
hunyuan_dim=TEXTURE_LATENT_DIM,
|
| 64 |
+
hidden_dim=512,
|
| 65 |
+
depth=3,
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
def forward(self, geom_in: torch.Tensor, views: torch.Tensor) -> dict[str, torch.Tensor]:
|
| 69 |
+
voxel_pred = self.geometry(geom_in)
|
| 70 |
+
tex_latent = self.texture(views)
|
| 71 |
+
bridge_out = self.bridge(geom_in)
|
| 72 |
+
return {
|
| 73 |
+
"voxel_pred": voxel_pred,
|
| 74 |
+
"tex_latent": tex_latent,
|
| 75 |
+
"bridge_out": bridge_out,
|
| 76 |
+
}
|