HayrettinIscan commited on
Commit
c6b84b3
·
verified ·
1 Parent(s): 2453fd8

Faz2: code/meshai_train/base_weights.py

Browse files
Files changed (1) hide show
  1. code/meshai_train/base_weights.py +165 -0
code/meshai_train/base_weights.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """HF MeshAI-Base-Models (dataset) uzerinden TRELLIS/Hunyuan agirlik indirme + LoRA hedef secimi."""
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+
12
+ BASE_DATASET_REPO = "HayrettinIscan/MeshAI-Base-Models"
13
+
14
+ # A100 icin makul ilk paket (Hunyuan DiT ~5GB — VM disk yeterli)
15
+ DEFAULT_WEIGHT_FILES = (
16
+ "Microsoft-TRELLIS/ckpts/slat_enc_swin8_B_64l8_fp16.safetensors",
17
+ "Microsoft-TRELLIS/ckpts/ss_enc_conv3d_16l8_fp16.safetensors",
18
+ "Microsoft-TRELLIS/ckpts/slat_dec_mesh_swin8_B_64l8m256c_fp16.safetensors",
19
+ "Tencent-Hunyuan3D/hunyuan3d-dit-v2-0-turbo/model.fp16.safetensors",
20
+ )
21
+
22
+
23
+ def ensure_base_weights(
24
+ *,
25
+ token: str,
26
+ cache_dir: Path,
27
+ files: tuple[str, ...] = DEFAULT_WEIGHT_FILES,
28
+ log_fn: Any = print,
29
+ ) -> dict[str, Path]:
30
+ """Indirilen safetensors yollarini dondurur (HF hub cache veya local_dir)."""
31
+ from huggingface_hub import hf_hub_download
32
+
33
+ cache_dir.mkdir(parents=True, exist_ok=True)
34
+ out: dict[str, Path] = {}
35
+ for rel in files:
36
+ log_fn(f"[faz2] indiriliyor: {rel}")
37
+ path = Path(
38
+ hf_hub_download(
39
+ repo_id=BASE_DATASET_REPO,
40
+ filename=rel,
41
+ repo_type="dataset",
42
+ token=token,
43
+ local_dir=str(cache_dir),
44
+ )
45
+ )
46
+ # hf bazen local_dir/rel yazar
47
+ candidate = cache_dir / rel
48
+ if candidate.exists():
49
+ path = candidate
50
+ out[rel] = path
51
+ log_fn(f"[faz2] hazir: {path} ({path.stat().st_size // (1024 * 1024)} MB)")
52
+ meta = cache_dir / "faz2_weight_manifest.json"
53
+ meta.write_text(
54
+ json.dumps({k: str(v) for k, v in out.items()}, indent=2),
55
+ encoding="utf-8",
56
+ )
57
+ return out
58
+
59
+
60
+ def _load_safetensors(path: Path) -> dict[str, torch.Tensor]:
61
+ try:
62
+ from safetensors.torch import load_file
63
+
64
+ return load_file(str(path))
65
+ except Exception:
66
+ # fallback: torch.load for .ckpt/.pt
67
+ return torch.load(path, map_location="cpu", weights_only=True)
68
+
69
+
70
+ def pick_lora_targets(
71
+ state: dict[str, torch.Tensor],
72
+ *,
73
+ max_matrices: int = 8,
74
+ min_in: int = 64,
75
+ max_in: int = 8192,
76
+ ) -> list[tuple[str, torch.Tensor]]:
77
+ """2D weight matrislerinden LoRA adaylarini sec (buyukten kucuge)."""
78
+ cands: list[tuple[str, torch.Tensor, int]] = []
79
+ for key, tensor in state.items():
80
+ if not key.endswith("weight"):
81
+ continue
82
+ if tensor.ndim != 2:
83
+ continue
84
+ out_f, in_f = int(tensor.shape[0]), int(tensor.shape[1])
85
+ if in_f < min_in or in_f > max_in:
86
+ continue
87
+ if out_f < 16:
88
+ continue
89
+ cands.append((key, tensor.detach().float().cpu(), out_f * in_f))
90
+ cands.sort(key=lambda x: x[2], reverse=True)
91
+ return [(k, t) for k, t, _ in cands[:max_matrices]]
92
+
93
+
94
+ class FrozenLinearLoRA(nn.Module):
95
+ """W frozen + LoRA(A,B). y = x @ W.T + scale * (x @ A.T) @ B.T"""
96
+
97
+ def __init__(
98
+ self,
99
+ weight: torch.Tensor,
100
+ *,
101
+ rank: int = 8,
102
+ scale: float = 1.0,
103
+ name: str = "",
104
+ ) -> None:
105
+ super().__init__()
106
+ out_f, in_f = weight.shape
107
+ self.name = name
108
+ self.in_features = in_f
109
+ self.out_features = out_f
110
+ self.scale = scale
111
+ self.register_buffer("weight", weight.contiguous())
112
+ self.lora_A = nn.Parameter(torch.zeros(rank, in_f))
113
+ self.lora_B = nn.Parameter(torch.zeros(out_f, rank))
114
+ nn.init.kaiming_uniform_(self.lora_A, a=5**0.5)
115
+ nn.init.zeros_(self.lora_B)
116
+
117
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
118
+ base = nn.functional.linear(x, self.weight)
119
+ delta = (x @ self.lora_A.T) @ self.lora_B.T
120
+ return base + self.scale * delta
121
+
122
+
123
+ class BaseLoRATower(nn.Module):
124
+ """Birden fazla frozen+LoRA katmani; giris projesi ile dim hizalama."""
125
+
126
+ def __init__(
127
+ self,
128
+ targets: list[tuple[str, torch.Tensor]],
129
+ *,
130
+ input_dim: int,
131
+ rank: int = 8,
132
+ out_dim: int = 512,
133
+ ) -> None:
134
+ super().__init__()
135
+ if not targets:
136
+ raise ValueError("LoRA hedefi yok")
137
+ layers = nn.ModuleList()
138
+ # Ilk katman in_features'a proj_in
139
+ first_in = int(targets[0][1].shape[1])
140
+ self.proj_in = nn.Linear(input_dim, first_in)
141
+ prev_out = first_in
142
+ for name, w in targets:
143
+ w = w.contiguous()
144
+ # Zincir: onceki out != bu in ise ara projeksiyon
145
+ if prev_out != int(w.shape[1]):
146
+ layers.append(nn.Linear(prev_out, int(w.shape[1])))
147
+ layers.append(nn.GELU())
148
+ layers.append(FrozenLinearLoRA(w, rank=rank, name=name))
149
+ layers.append(nn.GELU())
150
+ prev_out = int(w.shape[0])
151
+ self.layers = layers
152
+ self.proj_out = nn.Linear(prev_out, out_dim)
153
+
154
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
155
+ h = self.proj_in(x)
156
+ for layer in self.layers:
157
+ h = layer(h)
158
+ return self.proj_out(h)
159
+
160
+ def lora_parameters(self) -> list[nn.Parameter]:
161
+ params: list[nn.Parameter] = []
162
+ for m in self.modules():
163
+ if isinstance(m, FrozenLinearLoRA):
164
+ params.extend([m.lora_A, m.lora_B])
165
+ return params