Instructions to use litert-community/Idol with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LiteRT
How to use litert-community/Idol with LiteRT:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
Download python/idol_graphs.py from litert-community/Idol: direct link, hf CLI and curl.
- Browser
- Download file 26.6 kB
-
https://huggingface.co/litert-community/Idol/resolve/main/python/idol_graphs.py
- Command line
-
hf download hf://litert-community/Idol/python/idol_graphs.py
-
curl -L -o idol_graphs.py https://huggingface.co/litert-community/Idol/resolve/main/python/idol_graphs.py
26.6 kB
| """The shipped Idol graph set: GPU-shaped modules built from the real weights, one module per LiteRT graph. | |
| Every GPU call stays well under 2 s on the S26 (CONTRACT.md "Forms"), so the big parts are split: | |
| denoiser den_ctx (condition refiner, once per LoRA phase), den_in (time embedding, noise refiner, camera MLP), | |
| den_joint_00 .. den_joint_23 (one joint block each; _00 concatenates the streams, _23 adds the heads) | |
| octree oct (one graph, one signature per row bucket 64 / 256 / 1024 / 4096 / 8192: the weights are shared) | |
| gaussians gs_0 .. gs_7 (two blocks each; gs_0 embeds the anchors, gs_7 projects to the 480 features) | |
| dinov3 dino_0 .. dino_3 (eight layers each; dino_0 normalises and embeds the pixels, dino_3 ends in both norms) | |
| vae vae_0 .. vae_2 (one down stage each), vae_3 (down 3 + mid resnet 0), vae_attn (mid attention, fp32), | |
| vae_4 (mid resnet 1, head, quant_conv) | |
| Host inputs instead of in-graph math, for fp16 range: sinusoidal features of the diffusion time and the octree level | |
| (args up to 1000 rad), the point position embeddings (args up to 2^16 * 2pi), the denoiser's fixed latent-token | |
| position embedding, and DINOv3's RoPE tables. The turbo LoRA is kept as side matmuls: one graph set, and a gate input | |
| [1, 64] = (4 * slow, 4 * fast) per 32 ranks selects the phase. | |
| """ | |
| import math | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| import gpu_blocks as G | |
| LORA_SCALE = 128.0 / 32.0 | |
| DEN_TOKENS, COND_TOKENS = 8192, 4101 | |
| OCT_BUCKETS = (64, 256, 1024, 4096, 8192) | |
| def lora_pair(sd, key): | |
| """-> A [64, in] (slow rows then fast rows), B [out, 64] (slow columns then fast columns).""" | |
| a = torch.cat([sd[f'{key}.slow_A'], sd[f'{key}.fast_A']], 0).float() | |
| b = torch.cat([sd[f'{key}.slow_B'], sd[f'{key}.fast_B']], 1).float() | |
| return a, b | |
| def lora_gate(phase): | |
| g = torch.zeros(1, 64) | |
| g[:, :32] = LORA_SCALE if phase == 'slow' else 0.0 | |
| g[:, 32:] = LORA_SCALE if phase == 'fast' else 0.0 | |
| return g | |
| class DenBlock(G.DenoiserBlockGPU): | |
| """DenoiserBlockGPU + the turbo LoRA on qkv, out, fc1, fc2: forward(x, mod or None, gate [1, 64]).""" | |
| def __init__(self, block, repo, lora_sd, key, chunk): | |
| super().__init__(block, repo, chunk=chunk) | |
| c, h, d = self.c, self.h, self.d | |
| perm = G.deinterleave_perm(d) | |
| a, b = lora_pair(lora_sd, f'{key}.attn.qkv') | |
| self.qkv_a = G._linear(a, None) | |
| def rows(i, permute): | |
| bi = b[i * c:(i + 1) * c].reshape(h, d, 64) | |
| if permute: | |
| bi = bi[:, perm] | |
| return G._linear(bi.reshape(c, 64), None) | |
| self.q_b, self.k_b, self.v_b = rows(0, True), rows(1, True), rows(2, False) | |
| self.out_a, self.out_b = [G._linear(t, None) for t in lora_pair(lora_sd, f'{key}.attn.out')] | |
| self.fc1_a, self.fc1_b = [G._linear(t, None) for t in lora_pair(lora_sd, f'{key}.mlp.mlp.0')] | |
| self.fc2_a, self.fc2_b = [G._linear(t, None) for t in lora_pair(lora_sd, f'{key}.mlp.mlp.2')] | |
| def attn_l(self, hh, cos, sin, gate): | |
| b, l, _ = hh.shape | |
| half = self.d // 2 | |
| def rope(t): | |
| t0, t1 = t[..., :half], t[..., half:] | |
| return torch.cat([t0 * cos - t1 * sin, t0 * sin + t1 * cos], dim=-1) | |
| ax = self.qkv_a(hh) * gate | |
| q = G.safe_rms_unit(rope((self.q(hh) + self.q_b(ax)).reshape(b, l, self.h, self.d))) * self.gq | |
| k = G.safe_rms_unit(rope((self.k(hh) + self.k_b(ax)).reshape(b, l, self.h, self.d))) * self.gk | |
| v = (self.v(hh) + self.v_b(ax)).reshape(b, l, self.h, self.d) | |
| o = G.attention(q.permute(0, 2, 1, 3), k.permute(0, 2, 1, 3), v.permute(0, 2, 1, 3), self.chunk) | |
| o = o.reshape(b, l, self.c) | |
| return self.out(o) + self.out_b(self.out_a(o) * gate) | |
| def mlp_l(self, hh, gate): | |
| u = self.fc1(hh) + self.fc1_b(self.fc1_a(hh) * gate) | |
| u = G._gelu_tanh(u) | |
| return self.fc2(u) + self.fc2_b(self.fc2_a(u) * gate) | |
| def forward(self, x, mod, gate): | |
| cos, sin = self.repo(x) | |
| if not self.modulation: | |
| x = x + self.attn_l(G.safe_layer_norm(x, self.eps1, self.n1w, self.n1b), cos, sin, gate) | |
| return x + self.mlp_l(G.safe_layer_norm(x, self.eps2, self.n2w, self.n2b), gate) | |
| m = mod + self.shift_table | |
| c = self.c | |
| shift_msa, scale_msa, gate_msa = m[:, 0:c], m[:, c:2 * c], m[:, 2 * c:3 * c] | |
| shift_mlp, scale_mlp, gate_mlp = m[:, 3 * c:4 * c], m[:, 4 * c:5 * c], m[:, 5 * c:6 * c] | |
| hh = G.safe_layer_norm(x, self.eps1) * (1 + scale_msa.unsqueeze(1)) + shift_msa.unsqueeze(1) | |
| x = x + self.attn_l(hh, cos, sin, gate) * gate_msa.unsqueeze(1) | |
| hh = G.safe_layer_norm(x, self.eps2) * (1 + scale_mlp.unsqueeze(1)) + shift_mlp.unsqueeze(1) | |
| return x + self.mlp_l(hh, gate) * gate_mlp.unsqueeze(1) | |
| def _mlp_seq(seq): | |
| """nn.Sequential(Linear, SiLU or GELU(tanh), Linear) -> a float copy.""" | |
| return nn.Sequential(*[G._linear(m.weight, m.bias) if isinstance(m, nn.Linear) else m for m in seq]) | |
| class DenCtx(nn.Module): | |
| """(feature1 [1, 4101, 1280], feature2 [1, 4101, 128], gate) -> h_cond [1, 4101, 1024].""" | |
| def __init__(self, den, lora_sd, chunk): | |
| super().__init__() | |
| self.e1 = G._linear(den.cond_embedder.weight, den.cond_embedder.bias) | |
| self.e2 = G._linear(den.cond_embedder2.weight, den.cond_embedder2.bias) | |
| self.blocks = nn.ModuleList([DenBlock(b.float(), r.float(), lora_sd, f'context_refiner.{i}', chunk) | |
| for i, (b, r) in enumerate(zip(den.context_refiner, den.context_repo_layers))]) | |
| def forward(self, feature1, feature2, gate): | |
| h = self.e1(feature1) + self.e2(feature2) | |
| for blk in self.blocks: | |
| h = blk(h, None, gate) | |
| return h | |
| class DenIn(nn.Module): | |
| """(latent [1, 8192, 16], camera [1, 1, 5], t_freq [1, 256], pos_emb [1, 8192, 1024], gate) | |
| -> h_x [1, 8192, 1024], h_cam [1, 1, 1024], t_mod [1, 6144], t_emb [1, 1024].""" | |
| def __init__(self, den, lora_sd, chunk): | |
| super().__init__() | |
| self.t_mlp = _mlp_seq(den.t_embedder.mlp) | |
| self.ada = _mlp_seq(den.adaLN_modulation) | |
| self.inp = G._linear(den.input_layer.weight, den.input_layer.bias) | |
| self.blocks = nn.ModuleList([DenBlock(b.float(), r.float(), lora_sd, f'noise_refiner.{i}', chunk) | |
| for i, (b, r) in enumerate(zip(den.noise_refiner, den.noise_repo_layers))]) | |
| self.cam = _mlp_seq(den.cam_refiner.mlp) | |
| def forward(self, latent, camera, t_freq, pos_emb, gate): | |
| t_emb = self.t_mlp(t_freq) | |
| t_mod = self.ada(t_emb) | |
| h = self.inp(latent) + pos_emb | |
| for blk in self.blocks: | |
| h = blk(h, t_mod, gate) | |
| return h, self.cam(camera), t_mod, t_emb | |
| class DenJoint(nn.Module): | |
| """Joint block k. first: (h_x, h_cond, h_cam, t_mod, gate) -> h; middle: (h, t_mod, gate) -> h; | |
| last: (h, t_mod, t_emb, gate) -> v_latent [1, 8192, 16], v_camera [1, 1, 5].""" | |
| def __init__(self, den, k, lora_sd, chunk): | |
| super().__init__() | |
| self.first, self.last = k == 0, k == len(den.blocks) - 1 | |
| self.block = DenBlock(den.blocks[k].float(), den.repo_layers[k].float(), lora_sd, f'blocks.{k}', chunk) | |
| if self.last: | |
| self.shift_table = nn.Parameter(den.shift_table.detach().float().clone(), requires_grad=False) | |
| self.out = G._linear(den.out_layer.weight, den.out_layer.bias) | |
| self.cam_out = G._linear(den.cam_out_layer.weight, den.cam_out_layer.bias) | |
| def forward(self, *args): | |
| if self.first: | |
| h_x, h_cond, h_cam, t_mod, gate = args | |
| h = torch.cat([h_x, h_cond, h_cam], dim=1) | |
| elif self.last: | |
| h, t_mod, t_emb, gate = args | |
| else: | |
| h, t_mod, gate = args | |
| h = self.block(h, t_mod, gate) | |
| if not self.last: | |
| return h | |
| st = self.shift_table + t_emb.unsqueeze(1) | |
| shift, scale = st[:, 0:1], st[:, 1:2] | |
| hx = G.safe_layer_norm(h[:, :DEN_TOKENS], 1e-5) * (1 + scale) + shift | |
| hc = G.safe_layer_norm(h[:, -1:], 1e-5) * (1 + scale) + shift | |
| return self.out(hx), self.cam_out(hc) | |
| class Octree(nn.Module): | |
| """(cells [1, L, 3], cells_pe [1, L, 1024], l_freq [1, 256], latent [1, 8192, 16]) -> logits [1, L, 8].""" | |
| def __init__(self, dec, chunk): | |
| super().__init__() | |
| self.in_proj = G._linear(dec.in_proj.weight, dec.in_proj.bias) | |
| self.inp = G._linear(dec.input_layer.weight, dec.input_layer.bias) | |
| self.l_mlp = _mlp_seq(dec.l_embedder.mlp) | |
| self.ada = _mlp_seq(dec.adaLN_modulation) | |
| self.blocks = nn.ModuleList([G.OctreeBlockGPU(b.float(), chunk) for b in dec.blocks]) | |
| self.out = G._linear(dec.out_proj.weight, dec.out_proj.bias) | |
| def forward(self, cells, cells_pe, l_freq, latent): | |
| h = self.inp(self.in_proj(cells) + cells_pe) | |
| mod = self.ada(self.l_mlp(l_freq)) | |
| for blk in self.blocks: | |
| h = blk(h, mod, latent) | |
| return self.out(G.safe_layer_norm(h, 1e-5)) | |
| class Gauss(nn.Module): | |
| """Blocks [lo, hi) of the Gaussian decoder. first: (anchors [1, A, 3], anchors_pe [1, A, 1024], latent) -> h; | |
| others: (h, latent) -> h; the last ends in the output projection -> features [1, A, 480].""" | |
| def __init__(self, dgs, lo, hi, chunk): | |
| super().__init__() | |
| self.first, self.last = lo == 0, hi == len(dgs.blocks) | |
| if self.first: | |
| self.in_proj = G._linear(dgs.in_proj.weight, dgs.in_proj.bias) | |
| self.inp = G._linear(dgs.input_layer.weight, dgs.input_layer.bias) | |
| self.blocks = nn.ModuleList([G.GaussianBlockGPU(dgs.blocks[i].float(), chunk) for i in range(lo, hi)]) | |
| if self.last: | |
| self.out = G._linear(dgs.out_proj.weight, dgs.out_proj.bias) | |
| def forward(self, *args): | |
| if self.first: | |
| anchors, anchors_pe, latent = args | |
| h = self.inp(self.in_proj(anchors) + anchors_pe) | |
| else: | |
| h, latent = args | |
| for blk in self.blocks: | |
| h = blk(h, latent) | |
| return self.out(G.safe_layer_norm(h, 1e-5)) if self.last else h | |
| IMAGENET_MEAN = (0.485, 0.456, 0.406) | |
| IMAGENET_STD = (0.229, 0.224, 0.225) | |
| class Dino(nn.Module): | |
| """DINOv3 layers [lo, hi). first: (pixels [1, 3, 1024, 1024] in [0, 1], cos, sin) -> h [1, 4101, 1280]; | |
| others: (h, cos, sin) -> h; the last ends in the model norm and idol's F.layer_norm -> feature1.""" | |
| def __init__(self, model, lo, hi, chunk): | |
| super().__init__() | |
| self.first, self.last = lo == 0, hi == len(model.model.layer) | |
| emb = model.embeddings | |
| if self.first: | |
| self.register_buffer('mean', torch.tensor(IMAGENET_MEAN).view(1, 3, 1, 1)) | |
| self.register_buffer('inv_std', 1.0 / torch.tensor(IMAGENET_STD).view(1, 3, 1, 1)) | |
| pe = emb.patch_embeddings | |
| self.patch = nn.Conv2d(3, pe.out_channels, pe.kernel_size, pe.stride, bias=True) | |
| self.patch.weight.data = pe.weight.detach().float().clone() | |
| self.patch.bias.data = pe.bias.detach().float().clone() | |
| self.cls = nn.Parameter(emb.cls_token.detach().float().clone(), requires_grad=False) | |
| self.reg = nn.Parameter(emb.register_tokens.detach().float().clone(), requires_grad=False) | |
| self.layers = nn.ModuleList([G.DinoBlockGPU(model.model.layer[i].float(), 20, chunk) for i in range(lo, hi)]) | |
| if self.last: | |
| self.nw = nn.Parameter(model.norm.weight.detach().float().clone(), requires_grad=False) | |
| self.nb = nn.Parameter(model.norm.bias.detach().float().clone(), requires_grad=False) | |
| self.neps = model.norm.eps | |
| def forward(self, x, cos, sin): | |
| if self.first: | |
| p = self.patch((x - self.mean) * self.inv_std) # [1, 1280, 64, 64] | |
| p = p.flatten(2).transpose(1, 2) | |
| x = torch.cat([self.cls, self.reg, p], dim=1) | |
| for layer in self.layers: | |
| x = layer(x, cos, sin) | |
| if self.last: | |
| x = G.safe_layer_norm(x, self.neps, self.nw, self.nb) | |
| x = G.safe_layer_norm(x, 1e-5) | |
| return x | |
| # -- FLUX.2 VAE encoder ---------------------------------------------------------------------------------------- | |
| class PooledGroupNorm(nn.Module): | |
| """GroupNorm without moving channels into the batch: per-channel spatial means and abs-maxes by a hierarchy of | |
| pools (no reduction over more than 1024 values at once), group statistics on [1, C] vectors, and the centred map | |
| divided by its per-group abs-max before squaring so the fp16 squares cannot overflow. Exact in real arithmetic. | |
| The abs-max goes through a max pool first (exact: a max of maxes): one REDUCE_MAX over the 1024 x 1024 map of | |
| the VAE's first stage made each call of that graph 8 s on the Galaxy S26 GPU (vae_1 at 512 x 512: 1.6 s).""" | |
| def __init__(self, gn, hw): | |
| super().__init__() | |
| self.g, self.c, self.eps = gn.num_groups, gn.num_channels, gn.eps | |
| self.w = nn.Parameter(gn.weight.detach().float().clone().view(1, -1, 1, 1), requires_grad=False) | |
| self.b = nn.Parameter(gn.bias.detach().float().clone().view(1, -1, 1, 1), requires_grad=False) | |
| self.k = max(1, hw // 32) | |
| # group -> channel expansion as a one-hot FULLY_CONNECTED (an expand or a broadcast MUL by ones becomes | |
| # BROADCAST_TO, which has no GPU op); exact: each output is 1 * one group value | |
| self.expand = nn.Linear(self.g, self.c, bias=False) | |
| self.expand.weight.data = (torch.arange(self.c)[:, None] // (self.c // self.g) == | |
| torch.arange(self.g)[None, :]).float() | |
| def _chan_mean(self, x): | |
| if self.k > 1: | |
| x = F.avg_pool2d(x, self.k) | |
| return x.mean(dim=(2, 3), keepdim=True) # [1, C, 1, 1] | |
| def _group(self, v): # [1, C, 1, 1] -> group mean, per channel | |
| g = v.reshape(1, self.g, self.c // self.g).mean(-1) | |
| return self.expand(g).reshape(1, self.c, 1, 1) | |
| def forward(self, x): | |
| d = x - self._group(self._chan_mean(x)) | |
| m = d.abs() | |
| if self.k > 1: | |
| m = F.max_pool2d(m, self.k) | |
| m = m.amax(dim=(2, 3), keepdim=True) | |
| s = m.reshape(1, self.g, self.c // self.g).amax(-1) | |
| s = self.expand(s).reshape(1, self.c, 1, 1).clamp(min=1e-2) | |
| ds = d / s | |
| var = self._group(self._chan_mean(ds * ds)) | |
| return ds * torch.rsqrt(var + self.eps / (s * s)) * self.w + self.b | |
| def _patch_gn(module, hw): | |
| for name, child in list(module.named_children()): | |
| if isinstance(child, nn.GroupNorm): | |
| setattr(module, name, PooledGroupNorm(child, hw)) | |
| else: | |
| _patch_gn(child, hw) | |
| class VaeAttn(nn.Module): | |
| """diffusers Attention of the VAE mid block (one head, residual, rescale 1) with chunked rank-4 attention.""" | |
| def __init__(self, attn, chunk, hw): | |
| super().__init__() | |
| self.gn = PooledGroupNorm(attn.group_norm, hw) | |
| self.q, self.k, self.v = [G._linear(m.weight, m.bias) for m in (attn.to_q, attn.to_k, attn.to_v)] | |
| self.o = G._linear(attn.to_out[0].weight, attn.to_out[0].bias) | |
| self.heads, self.scale, self.chunk = attn.heads, attn.scale, chunk | |
| self.residual, self.rescale = attn.residual_connection, attn.rescale_output_factor | |
| def forward(self, x, *args, **kwargs): | |
| b, c, hh, ww = x.shape | |
| h = self.gn(x).reshape(b, c, hh * ww).transpose(1, 2) | |
| d = c // self.heads | |
| q = (self.q(h) * self.scale).reshape(b, hh * ww, self.heads, d).permute(0, 2, 1, 3) | |
| k = self.k(h).reshape(b, hh * ww, self.heads, d).permute(0, 2, 1, 3) | |
| v = self.v(h).reshape(b, hh * ww, self.heads, d).permute(0, 2, 1, 3) | |
| o = G.attention(q, k, v, self.chunk).reshape(b, hh * ww, c) | |
| o = self.o(o).transpose(1, 2).reshape(b, c, hh, ww) | |
| if self.residual: | |
| o = o + x | |
| return o / self.rescale | |
| class Vae(nn.Module): | |
| """FLUX.2 VAE encoder, part p: | |
| 0: x in [0, 1] [1, 3, 1024, 1024] -> conv_in, down 0 -> [1, 128, 512, 512]; 1: down 1 -> [1, 256, 256, 256]; | |
| 2: down 2 -> [1, 512, 128, 128]; 3: down 3, mid resnet 0 -> [1, 512, 128, 128]; | |
| 'attn': the mid block's attention (one head over 16,384 tokens, its own graph to keep each GPU call short); | |
| 4: mid resnet 1, norm, SiLU, conv_out, quant_conv -> moments [1, 64, 128, 128].""" | |
| SIZES = {0: 1024, 1: 512, 2: 256, 3: 128, 'attn': 128, 4: 128} | |
| PARTS = (0, 1, 2, 3, 'attn', 4) | |
| def __init__(self, vae, part, chunk): | |
| super().__init__() | |
| enc = vae.encoder | |
| self.part = part | |
| hw = self.SIZES[part] | |
| if part in (0, 1, 2, 3): | |
| self.down = enc.down_blocks[part] | |
| _patch_gn(self.down, hw) | |
| if part == 0: | |
| self.conv_in = enc.conv_in | |
| mid = enc.mid_block | |
| if part == 3: | |
| self.res = mid.resnets[0] | |
| _patch_gn(self.res, hw) | |
| if part == 'attn': | |
| self.attn = VaeAttn(mid.attentions[0], chunk, hw) | |
| if part == 4: | |
| self.res = mid.resnets[1] | |
| _patch_gn(self.res, hw) | |
| self.norm_out = PooledGroupNorm(enc.conv_norm_out, hw) | |
| self.conv_out = enc.conv_out | |
| self.quant_conv = vae.quant_conv | |
| def forward(self, x): | |
| p = self.part | |
| if p == 0: | |
| x = self.conv_in(x * 2 - 1) | |
| if p in (0, 1, 2, 3): | |
| x = self.down(x) | |
| if p == 3: | |
| x = self.res(x, None) | |
| if p == 'attn': | |
| x = self.attn(x) | |
| if p == 4: | |
| x = self.res(x, None) | |
| x = self.quant_conv(self.conv_out(F.silu(self.norm_out(x)))) | |
| return x | |
| # -- host-side features (float32 on the CPU; the Kotlin glue computes the same) ---------------------------------- | |
| def sinusoid(value, dim=256, max_period=10000.0, two_pi=False): | |
| """SinusoidalEmbedder's frequency features of one scalar -> [1, dim] float32.""" | |
| half = dim // 2 | |
| freqs = torch.exp(-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half) | |
| args = torch.tensor([float(value)], dtype=torch.float32)[:, None] * freqs[None] | |
| if two_pi: | |
| args = args * 2 * torch.pi | |
| return torch.cat([torch.cos(args), torch.sin(args)], dim=-1) | |
| def point_pe(points, channels=1024, max_res=10): | |
| """PcdAbsolutePositionEmbedderv2 of points [N, 3] in [0, 1] -> [N, 1024] float32.""" | |
| freq_dim = channels // 3 // 2 | |
| freqs = torch.pow(2.0, torch.linspace(0.0, float(max_res), steps=freq_dim, dtype=torch.float32)) | |
| ang = points.float().unsqueeze(-1) * freqs * torch.pi | |
| emb = torch.cat([torch.sin(ang), torch.cos(ang)], dim=-1).reshape(points.shape[0], -1) | |
| return torch.cat([emb, torch.zeros(points.shape[0], channels - emb.shape[1])], dim=-1) | |
| # ---------------------------------------------------------------- shared middle joint block (state lever, round 2) | |
| # The weight inputs of the shared joint graph after (h, t_mod, gate), in input order args_3 .. args_32. Linear weights | |
| # are passed transposed ([1, in, out]), so each projection is one BATCH_MATMUL with a runtime operand. | |
| SHARED_WEIGHT_NAMES = ['repo_norm_w', 'repo_norm_b', 'repo_gate_t', 'repo_content_t', 'repo_ang_t', | |
| 'q_t', 'q_b', 'k_t', 'k_b', 'v_t', 'v_b', 'gq', 'gk', 'out_t', 'out_b', 'fc1_t', 'fc1_b', | |
| 'fc2_t', 'fc2_b', 'shift', 'lqkv_a_t', 'lq_b_t', 'lk_b_t', 'lv_b_t', 'lout_a_t', 'lout_b_t', | |
| 'lfc1_a_t', 'lfc1_b_t', 'lfc2_a_t', 'lfc2_b_t'] | |
| def shared_block_weights(jb): | |
| """A middle DenJoint's weights in SHARED_WEIGHT_NAMES order (float32 tensors, the shapes of the graph inputs).""" | |
| def tw(lin): | |
| return lin.weight.detach().float().t().contiguous()[None] | |
| def row(v): | |
| return v.detach().float()[None, None] | |
| b = jb.block | |
| r = b.repo | |
| return [row(r.norm_w), row(r.norm_b), tw(r.gate), tw(r.content), tw(r.ang), | |
| tw(b.q), row(b.q.bias), tw(b.k), row(b.k.bias), tw(b.v), row(b.v.bias), b.gq.detach().float(), | |
| b.gk.detach().float(), tw(b.out), row(b.out.bias), tw(b.fc1), row(b.fc1.bias), tw(b.fc2), row(b.fc2.bias), | |
| b.shift_table.detach().float(), tw(b.qkv_a), tw(b.q_b), tw(b.k_b), tw(b.v_b), tw(b.out_a), tw(b.out_b), | |
| tw(b.fc1_a), tw(b.fc1_b), tw(b.fc2_a), tw(b.fc2_b)] | |
| class DenJointShared(nn.Module): | |
| """One graph for every middle joint block: (h [1, L, 1024], t_mod [1, 6144], gate [1, 64], *weights) -> h, the | |
| block's weights as runtime inputs (shared_block_weights order). Same arithmetic as DenBlock.forward; compiled once | |
| per photo on the phone instead of once per block.""" | |
| def __init__(self, ref_joint): | |
| super().__init__() | |
| b = ref_joint.block | |
| self.c, self.h, self.d, self.chunk = b.c, b.h, b.d, b.chunk | |
| self.eps1, self.eps2, self.repo_eps, self.repo_half = b.eps1, b.eps2, b.repo.eps, b.repo.half | |
| def forward(self, x, mod, gate, *w): | |
| W = dict(zip(SHARED_WEIGHT_NAMES, w)) | |
| c, H, d = self.c, self.h, self.d | |
| bsz, L, _ = x.shape | |
| mm = torch.matmul | |
| g = gate[:, None, :] | |
| hr = G.safe_layer_norm(x, self.repo_eps, W['repo_norm_w'], W['repo_norm_b']) | |
| a = mm(F.silu(mm(hr, W['repo_gate_t'])) * mm(hr, W['repo_content_t']), W['repo_ang_t']) | |
| a = a.reshape(bsz, L, H, self.repo_half) | |
| cos, sin = torch.cos(a), torch.sin(a) | |
| m = mod + W['shift'] | |
| shift_msa, scale_msa, gate_msa = m[:, 0:c], m[:, c:2 * c], m[:, 2 * c:3 * c] | |
| shift_mlp, scale_mlp, gate_mlp = m[:, 3 * c:4 * c], m[:, 4 * c:5 * c], m[:, 5 * c:6 * c] | |
| hh = G.safe_layer_norm(x, self.eps1) * (1 + scale_msa.unsqueeze(1)) + shift_msa.unsqueeze(1) | |
| half = d // 2 | |
| def rope(t): | |
| t0, t1 = t[..., :half], t[..., half:] | |
| return torch.cat([t0 * cos - t1 * sin, t0 * sin + t1 * cos], dim=-1) | |
| ax = mm(hh, W['lqkv_a_t']) * g | |
| q = G.safe_rms_unit(rope((mm(hh, W['q_t']) + W['q_b'] + mm(ax, W['lq_b_t'])).reshape(bsz, L, H, d))) * W['gq'] | |
| k = G.safe_rms_unit(rope((mm(hh, W['k_t']) + W['k_b'] + mm(ax, W['lk_b_t'])).reshape(bsz, L, H, d))) * W['gk'] | |
| v = (mm(hh, W['v_t']) + W['v_b'] + mm(ax, W['lv_b_t'])).reshape(bsz, L, H, d) | |
| o = G.attention(q.permute(0, 2, 1, 3), k.permute(0, 2, 1, 3), v.permute(0, 2, 1, 3), self.chunk) | |
| o = o.reshape(bsz, L, c) | |
| x = x + (mm(o, W['out_t']) + W['out_b'] + mm(mm(o, W['lout_a_t']) * g, W['lout_b_t'])) * gate_msa.unsqueeze(1) | |
| hh = G.safe_layer_norm(x, self.eps2) * (1 + scale_mlp.unsqueeze(1)) + shift_mlp.unsqueeze(1) | |
| u = G._gelu_tanh(mm(hh, W['fc1_t']) + W['fc1_b'] + mm(mm(hh, W['lfc1_a_t']) * g, W['lfc1_b_t'])) | |
| return x + (mm(u, W['fc2_t']) + W['fc2_b'] + mm(mm(u, W['lfc2_a_t']) * g, W['lfc2_b_t'])) * gate_mlp.unsqueeze(1) | |
| # ---------------------------------------------------------------- shared middle Gaussian decoder graph (state lever) | |
| # One GaussianBlockGPU's weights as graph inputs, in input order: self-attention, cross-attention, norm2's affine, MLP. | |
| # Linear weights are passed transposed ([1, in, out]), as for the shared joint block. | |
| GAUSS_BLOCK_WEIGHT_NAMES = ['sa_q_t', 'sa_q_b', 'sa_k_t', 'sa_k_b', 'sa_v_t', 'sa_v_b', 'sa_gq', 'sa_gk', 'sa_out_t', | |
| 'sa_out_b', 'ca_q_t', 'ca_q_b', 'ca_k_t', 'ca_k_b', 'ca_v_t', 'ca_v_b', 'ca_gq', 'ca_gk', | |
| 'ca_out_t', 'ca_out_b', 'n2_w', 'n2_b', 'fc1_t', 'fc1_b', 'fc2_t', 'fc2_b'] | |
| def gauss_block_weights(gb): | |
| """One GaussianBlockGPU's weights in GAUSS_BLOCK_WEIGHT_NAMES order (float32 tensors, the graph input shapes).""" | |
| def tw(lin): | |
| return lin.weight.detach().float().t().contiguous()[None] | |
| def row(v): | |
| return v.detach().float().reshape(1, 1, -1) | |
| def mha(m): | |
| return [tw(m.q), row(m.q.bias), tw(m.k), row(m.k.bias), tw(m.v), row(m.v.bias), m.gq.detach().float(), | |
| m.gk.detach().float(), tw(m.out), row(m.out.bias)] | |
| assert gb.n2w is not None and gb.n2b is not None | |
| return (mha(gb.self_attn) + mha(gb.cross_attn) + | |
| [row(gb.n2w), row(gb.n2b), tw(gb.fc1), row(gb.fc1.bias), tw(gb.fc2), row(gb.fc2.bias)]) | |
| def gauss_shared_weights(g): | |
| """A middle Gauss graph's weights: its blocks' gauss_block_weights one after another.""" | |
| return [t for b in g.blocks for t in gauss_block_weights(b)] | |
| class GaussShared(nn.Module): | |
| """One graph for the Gaussian decoder's middle graphs (gs_1 .. gs_6, two blocks each): (h [1, A, 1024], | |
| latent [1, 8192, 16], *weights) -> h, the blocks' weights as runtime inputs (gauss_shared_weights order). Same | |
| arithmetic as Gauss.forward for a middle graph; compiled once per photo on the phone instead of six times.""" | |
| def __init__(self, ref): | |
| super().__init__() | |
| assert not ref.first and not ref.last | |
| b0 = ref.blocks[0] | |
| self.n = len(ref.blocks) | |
| self.eps = (b0.e1, b0.e2, b0.e3) | |
| self.sa = (b0.self_attn.h, b0.self_attn.c, b0.self_attn.d, b0.self_attn.chunk) | |
| self.ca = (b0.cross_attn.h, b0.cross_attn.c, b0.cross_attn.d, b0.cross_attn.chunk) | |
| def _mha(x, src, W, p, heads, c, d, chunk): | |
| mm = torch.matmul | |
| b, lq, _ = x.shape | |
| lk = src.shape[1] | |
| q = G.safe_rms_unit((mm(x, W[p + 'q_t']) + W[p + 'q_b']).reshape(b, lq, heads, d)) * W[p + 'gq'] | |
| k = G.safe_rms_unit((mm(src, W[p + 'k_t']) + W[p + 'k_b']).reshape(b, lk, heads, d)) * W[p + 'gk'] | |
| v = (mm(src, W[p + 'v_t']) + W[p + 'v_b']).reshape(b, lk, heads, d) | |
| o = G.attention(q.permute(0, 2, 1, 3), k.permute(0, 2, 1, 3), v.permute(0, 2, 1, 3), chunk) | |
| return mm(o.reshape(b, lq, c), W[p + 'out_t']) + W[p + 'out_b'] | |
| def forward(self, h, latent, *w): | |
| n = len(GAUSS_BLOCK_WEIGHT_NAMES) | |
| assert len(w) == n * self.n, len(w) | |
| e1, e2, e3 = self.eps | |
| for i in range(self.n): | |
| W = dict(zip(GAUSS_BLOCK_WEIGHT_NAMES, w[i * n:(i + 1) * n])) | |
| x = G.safe_layer_norm(h, e1) | |
| h = h + self._mha(x, x, W, 'sa_', *self.sa) | |
| h = h + self._mha(G.safe_layer_norm(h, e2, W['n2_w'], W['n2_b']), latent, W, 'ca_', *self.ca) | |
| u = G._gelu_tanh(torch.matmul(G.safe_layer_norm(h, e3), W['fc1_t']) + W['fc1_b']) | |
| h = h + (torch.matmul(u, W['fc2_t']) + W['fc2_b']) | |
| return h | |