Spaces:
Running
Running
Upload 7 files
#5
by wop - opened
- .gitattributes +43 -43
- README.md +14 -14
- app.py +219 -158
- mmdit.py +141 -0
- pixel_dit.py +133 -133
- requirements.txt +13 -11
- voxel_dit.py +134 -134
.gitattributes
CHANGED
|
@@ -1,43 +1,43 @@
|
|
| 1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
-
examples/demo19.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
-
assets/DA-2K.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
-
assets/examples_video/basketball.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
-
assets/examples_video/ferris_wheel.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 40 |
-
assets/examples/demo19.jpg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
-
assets/teaser.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
-
metric_depth/assets/compare_zoedepth.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
-
metric_depth/dataset/splits/hypersim/train.txt filter=lfs diff=lfs merge=lfs -text
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
examples/demo19.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
assets/DA-2K.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
assets/examples_video/basketball.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
assets/examples_video/ferris_wheel.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
assets/examples/demo19.jpg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
assets/teaser.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
metric_depth/assets/compare_zoedepth.png filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
metric_depth/dataset/splits/hypersim/train.txt filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: BenchLabs Models
|
| 3 |
-
emoji: 🏛️
|
| 4 |
-
colorFrom: red
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 5.50.0
|
| 8 |
-
app_file: app.py
|
| 9 |
-
pinned: false
|
| 10 |
-
license: apache-2.0
|
| 11 |
-
---
|
| 12 |
-
|
| 13 |
-
# BenchLabs Inference Space
|
| 14 |
-
This space runs **PixelModel-v5** (Text-to-Image) and **VoxelModel-v1** (Text-to-3D) dynamically on CPU.
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: BenchLabs Models
|
| 3 |
+
emoji: 🏛️
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: blue
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 5.50.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
license: apache-2.0
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# BenchLabs Inference Space
|
| 14 |
+
This space runs **PixelModel-v5** (Text-to-Image) and **VoxelModel-v1** (Text-to-3D) dynamically on CPU.
|
app.py
CHANGED
|
@@ -1,158 +1,219 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
import tempfile
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
from
|
| 15 |
-
from
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
print("[boot]
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
)
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
)
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import tempfile
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
os.environ.setdefault("HF_HOME", r"D:\hf-cache")
|
| 7 |
+
os.environ.setdefault("HUGGINGFACE_HUB_CACHE", r"D:\hf-cache\hub")
|
| 8 |
+
|
| 9 |
+
import gradio as gr
|
| 10 |
+
import numpy as np
|
| 11 |
+
import torch
|
| 12 |
+
import trimesh
|
| 13 |
+
from diffusers import AutoencoderKL
|
| 14 |
+
from huggingface_hub import hf_hub_download
|
| 15 |
+
from safetensors.torch import load_file
|
| 16 |
+
from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
| 17 |
+
|
| 18 |
+
from pixel_dit import DiT
|
| 19 |
+
from voxel_dit import VoxelDiT
|
| 20 |
+
from mmdit import MMDiT
|
| 21 |
+
|
| 22 |
+
DEV = "cpu"
|
| 23 |
+
SCALE = 0.18215
|
| 24 |
+
CLIP_ID = "openai/clip-vit-base-patch32"
|
| 25 |
+
MAX_TOKENS = 40
|
| 26 |
+
|
| 27 |
+
print("[boot] loading shared CLIP text encoder...")
|
| 28 |
+
tokenizer = CLIPTokenizer.from_pretrained(CLIP_ID)
|
| 29 |
+
text_encoder = CLIPTextModel.from_pretrained(CLIP_ID).to(DEV).eval()
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
@torch.no_grad()
|
| 33 |
+
def encode(strings: list[str]):
|
| 34 |
+
t = tokenizer(strings, padding="max_length", max_length=MAX_TOKENS, truncation=True, return_tensors="pt").to(DEV)
|
| 35 |
+
o = text_encoder(**t)
|
| 36 |
+
return o.last_hidden_state.float(), o.pooler_output.float()
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
null_seq, null_pool = encode([""])
|
| 40 |
+
|
| 41 |
+
print("[boot] loading PixelModel v5...")
|
| 42 |
+
pm5_weights = hf_hub_download("bench-labs/PixelModel-v5", "model.safetensors")
|
| 43 |
+
pm5_state = load_file(pm5_weights)
|
| 44 |
+
pixel_model = DiT(dim=384, depth=12, heads=6).to(DEV).eval()
|
| 45 |
+
pixel_model.load_state_dict({k[len("dit."):]: v for k, v in pm5_state.items() if k.startswith("dit.")})
|
| 46 |
+
vae = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse").to(DEV).eval()
|
| 47 |
+
|
| 48 |
+
print("[boot] loading VoxelModel v1...")
|
| 49 |
+
vm1_weights = hf_hub_download("bench-labs/VoxelModel-v1", "model.safetensors")
|
| 50 |
+
voxel_model = VoxelDiT().to(DEV).eval()
|
| 51 |
+
voxel_model.load_state_dict(load_file(vm1_weights))
|
| 52 |
+
|
| 53 |
+
print("[boot] loading PixelModel v6...")
|
| 54 |
+
v6_weights = hf_hub_download("bench-labs/PixelModel-v6", "model.safetensors")
|
| 55 |
+
pixel_model_v6 = MMDiT().to(DEV).eval()
|
| 56 |
+
pixel_model_v6.load_state_dict(load_file(v6_weights), strict=False)
|
| 57 |
+
t5_tokenizer = T5TokenizerFast.from_pretrained("google/flan-t5-base")
|
| 58 |
+
t5_encoder = T5EncoderModel.from_pretrained("google/flan-t5-base").to(DEV).eval()
|
| 59 |
+
vae_v6 = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix").to(DEV).float().eval()
|
| 60 |
+
null_v6_seq, null_v6_mask, null_v6_pool = None, None, None
|
| 61 |
+
|
| 62 |
+
print("[boot] ready.")
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
@torch.no_grad()
|
| 66 |
+
def sample_image(prompt: str, steps: int, cfg: float, seed: int, progress=gr.Progress()):
|
| 67 |
+
if not prompt.strip():
|
| 68 |
+
raise gr.Error("Type a prompt first.")
|
| 69 |
+
steps = int(steps)
|
| 70 |
+
g = torch.Generator(device=DEV).manual_seed(int(seed))
|
| 71 |
+
seq, pool = encode([prompt])
|
| 72 |
+
x = torch.randn(1, 4, 32, 32, device=DEV, generator=g)
|
| 73 |
+
dt = 1.0 / steps
|
| 74 |
+
for i in progress.tqdm(range(steps), desc="sampling"):
|
| 75 |
+
t = torch.full((1,), i * dt, device=DEV)
|
| 76 |
+
vc = pixel_model(x, t, seq, pool)
|
| 77 |
+
vu = pixel_model(x, t, null_seq, null_pool)
|
| 78 |
+
x = x + (vu + cfg * (vc - vu)) * dt
|
| 79 |
+
img = vae.decode((x / SCALE)).sample
|
| 80 |
+
img = ((img.clamp(-1, 1) + 1) / 2).permute(0, 2, 3, 1).numpy()[0]
|
| 81 |
+
return (img * 255).round().astype(np.uint8)
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
@torch.no_grad()
|
| 85 |
+
def sample_voxel(prompt: str, steps: int, cfg: float, threshold: float, seed: int, progress=gr.Progress()):
|
| 86 |
+
if not prompt.strip():
|
| 87 |
+
raise gr.Error("Type a prompt first.")
|
| 88 |
+
steps = int(steps)
|
| 89 |
+
g = torch.Generator(device=DEV).manual_seed(int(seed))
|
| 90 |
+
seq, pool = encode([prompt])
|
| 91 |
+
x = torch.randn(1, 1, 32, 32, 32, device=DEV, generator=g)
|
| 92 |
+
dt = 1.0 / steps
|
| 93 |
+
for i in progress.tqdm(range(steps), desc="sampling"):
|
| 94 |
+
t = torch.full((1,), i * dt, device=DEV)
|
| 95 |
+
vc = voxel_model(x, t, seq, pool)
|
| 96 |
+
vu = voxel_model(x, t, null_seq, null_pool)
|
| 97 |
+
x = x + (vu + cfg * (vc - vu)) * dt
|
| 98 |
+
grid = (x[0, 0] > threshold).numpy()
|
| 99 |
+
if not grid.any():
|
| 100 |
+
raise gr.Error("Nothing came back above the occupancy threshold — try lowering it or re-rolling the seed.")
|
| 101 |
+
return grid_to_glb(grid)
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
@torch.no_grad()
|
| 105 |
+
def sample_image_v6(prompt: str, steps: int, cfg: float, seed: int, progress=gr.Progress()):
|
| 106 |
+
global null_v6_seq, null_v6_mask, null_v6_pool
|
| 107 |
+
if not prompt.strip():
|
| 108 |
+
raise gr.Error("Type a prompt first.")
|
| 109 |
+
steps = int(steps)
|
| 110 |
+
|
| 111 |
+
def encode_v6(strings):
|
| 112 |
+
t = t5_tokenizer(strings, padding="max_length", max_length=32, truncation=True, return_tensors="pt").to(DEV)
|
| 113 |
+
seq = t5_encoder(**t).last_hidden_state.float()
|
| 114 |
+
_, pool = encode(strings)
|
| 115 |
+
return seq, t["attention_mask"].float(), pool
|
| 116 |
+
|
| 117 |
+
seq, mask, pool = encode_v6([prompt])
|
| 118 |
+
if null_v6_seq is None:
|
| 119 |
+
null_v6_seq, null_v6_mask, null_v6_pool = encode_v6([""])
|
| 120 |
+
g = torch.Generator(device=DEV).manual_seed(int(seed))
|
| 121 |
+
x = torch.randn(1, 4, 32, 32, device=DEV, generator=g)
|
| 122 |
+
dt = 1.0 / steps
|
| 123 |
+
for i in progress.tqdm(range(steps), desc="sampling"):
|
| 124 |
+
t = torch.full((1,), i * dt, device=DEV)
|
| 125 |
+
vc = pixel_model_v6(x, t, seq, mask, pool)
|
| 126 |
+
vu = pixel_model_v6(x, t, null_v6_seq, null_v6_mask, null_v6_pool)
|
| 127 |
+
x = x + (vu + cfg * (vc - vu)) * dt
|
| 128 |
+
img = vae_v6.decode(x / vae_v6.config.scaling_factor).sample
|
| 129 |
+
return (((img.clamp(-1, 1) + 1) / 2).permute(0, 2, 3, 1).numpy()[0] * 255).round().astype(np.uint8)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def grid_to_glb(grid: np.ndarray) -> str:
|
| 133 |
+
voxel = trimesh.voxel.VoxelGrid(encoding=grid)
|
| 134 |
+
mesh = voxel.as_boxes()
|
| 135 |
+
mesh.visual.face_colors = [180, 180, 190, 255]
|
| 136 |
+
path = tempfile.NamedTemporaryFile(suffix=".glb", delete=False).name
|
| 137 |
+
mesh.export(path)
|
| 138 |
+
return path
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
with gr.Blocks(title="BenchLabs Models") as demo:
|
| 142 |
+
gr.Markdown(
|
| 143 |
+
"# BenchLabs Models\n"
|
| 144 |
+
"Two tiny diffusion models, running live on CPU, no GPU behind this Space. "
|
| 145 |
+
"Both are under 45M trained parameters, so generation is slower than a hosted API "
|
| 146 |
+
"but the whole model fits in a PNG image if you're curious — see the model pages linked below."
|
| 147 |
+
)
|
| 148 |
+
with gr.Tab("Text → Image (PixelModel v6)"):
|
| 149 |
+
gr.Markdown("A larger MMDiT model conditioned by T5 and CLIP. CPU generation is slower; 256x256 output.")
|
| 150 |
+
with gr.Row():
|
| 151 |
+
with gr.Column():
|
| 152 |
+
v6_prompt = gr.Textbox(label="Prompt", placeholder="a red fox sitting in a snowy forest")
|
| 153 |
+
v6_steps = gr.Slider(10, 100, value=50, step=5, label="Detail (sampling steps)")
|
| 154 |
+
v6_cfg = gr.Slider(1.0, 10.0, value=3.0, step=0.5, label="Prompt strength (CFG)")
|
| 155 |
+
v6_seed = gr.Number(value=0, precision=0, label="Seed")
|
| 156 |
+
v6_btn = gr.Button("Generate image", variant="primary")
|
| 157 |
+
with gr.Column():
|
| 158 |
+
v6_out = gr.Image(label="Result", type="numpy")
|
| 159 |
+
v6_btn.click(sample_image_v6, [v6_prompt, v6_steps, v6_cfg, v6_seed], v6_out)
|
| 160 |
+
gr.Examples(
|
| 161 |
+
[["a red fox sitting in a snowy forest", 50, 3.0, 0],
|
| 162 |
+
["a lighthouse on a cliff at sunset", 50, 3.0, 0],
|
| 163 |
+
["a city street at night with neon signs", 50, 3.0, 0]],
|
| 164 |
+
[v6_prompt, v6_steps, v6_cfg, v6_seed],
|
| 165 |
+
)
|
| 166 |
+
|
| 167 |
+
with gr.Tab("Text → 3D (VoxelModel v1)"):
|
| 168 |
+
gr.Markdown(
|
| 169 |
+
"Good at bulky objects: chairs, tables, cars, mushrooms. "
|
| 170 |
+
"Thin objects (swords, keys) don't survive 32³ voxelization, in the training "
|
| 171 |
+
"data or the model, so expect a blob rather than a blade."
|
| 172 |
+
)
|
| 173 |
+
with gr.Row():
|
| 174 |
+
with gr.Column():
|
| 175 |
+
vox_prompt = gr.Textbox(label="Prompt", placeholder="a wooden chair")
|
| 176 |
+
vox_steps = gr.Slider(10, 50, value=25, step=1, label="Detail (sampling steps)")
|
| 177 |
+
vox_cfg = gr.Slider(1.0, 10.0, value=5.0, step=0.5, label="Prompt strength (CFG)")
|
| 178 |
+
vox_thresh = gr.Slider(-1.0, 1.0, value=0.0, step=0.05, label="Occupancy threshold")
|
| 179 |
+
vox_seed = gr.Number(value=0, precision=0, label="Seed")
|
| 180 |
+
vox_btn = gr.Button("Generate 3D model", variant="primary")
|
| 181 |
+
with gr.Column():
|
| 182 |
+
vox_out = gr.Model3D(label="Result")
|
| 183 |
+
vox_btn.click(sample_voxel, [vox_prompt, vox_steps, vox_cfg, vox_thresh, vox_seed], vox_out)
|
| 184 |
+
gr.Examples(
|
| 185 |
+
[["a wooden chair", 25, 5.0, 0.0, 0],
|
| 186 |
+
["a purple mushroom", 25, 5.0, 0.0, 0],
|
| 187 |
+
["a small boat", 25, 5.0, 0.0, 0]],
|
| 188 |
+
[vox_prompt, vox_steps, vox_cfg, vox_thresh, vox_seed],
|
| 189 |
+
)
|
| 190 |
+
|
| 191 |
+
with gr.Tab("Text → Image (PixelModel v5)"):
|
| 192 |
+
gr.Markdown(
|
| 193 |
+
"Good at material and light: food, landscapes, skies, interiors. "
|
| 194 |
+
"Weak on faces, hands, and anything needing precise structure or text."
|
| 195 |
+
)
|
| 196 |
+
with gr.Row():
|
| 197 |
+
with gr.Column():
|
| 198 |
+
img_prompt = gr.Textbox(label="Prompt", placeholder="a bowl of ramen with a soft boiled egg")
|
| 199 |
+
img_steps = gr.Slider(10, 50, value=25, step=1, label="Detail (sampling steps)")
|
| 200 |
+
img_cfg = gr.Slider(1.0, 10.0, value=5.0, step=0.5, label="Prompt strength (CFG)")
|
| 201 |
+
img_seed = gr.Number(value=0, precision=0, label="Seed")
|
| 202 |
+
img_btn = gr.Button("Generate image", variant="primary")
|
| 203 |
+
with gr.Column():
|
| 204 |
+
img_out = gr.Image(label="Result", type="numpy")
|
| 205 |
+
img_btn.click(sample_image, [img_prompt, img_steps, img_cfg, img_seed], img_out)
|
| 206 |
+
gr.Examples(
|
| 207 |
+
[["a bowl of ramen with a soft boiled egg", 25, 5.0, 0],
|
| 208 |
+
["a wet cobblestone street at night", 25, 5.0, 0],
|
| 209 |
+
["a library of wooden shelves", 25, 5.0, 0]],
|
| 210 |
+
[img_prompt, img_steps, img_cfg, img_seed],
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
gr.Markdown(
|
| 214 |
+
"Models: [PixelModel v5](https://huggingface.co/bench-labs/PixelModel-v5) · "
|
| 215 |
+
"[VoxelModel v1](https://huggingface.co/bench-labs/VoxelModel-v1)"
|
| 216 |
+
)
|
| 217 |
+
|
| 218 |
+
if __name__ == "__main__":
|
| 219 |
+
demo.queue(max_size=20).launch(server_name="0.0.0.0")
|
mmdit.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import math
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
import torch.nn.functional as F
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def modulate(x, shift, scale):
|
| 10 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def timestep_embedding(t, dim, max_period=10000):
|
| 14 |
+
half = dim // 2
|
| 15 |
+
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 16 |
+
args = t[:, None].float() * freqs[None]
|
| 17 |
+
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 18 |
+
return torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1) if dim % 2 else emb
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def rope_freqs(positions, dim, base=10000.0):
|
| 22 |
+
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
|
| 23 |
+
return torch.outer(positions.float(), inv_freq)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def rope_cos_sin(freqs):
|
| 27 |
+
emb = torch.cat([freqs, freqs], dim=-1)
|
| 28 |
+
return emb.cos(), emb.sin()
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def rotate_half(x):
|
| 32 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 33 |
+
return torch.cat([-x2, x1], dim=-1)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def apply_rope(x, cos, sin):
|
| 37 |
+
return x * cos + rotate_half(x) * sin
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def apply_rope_2d(x, row_cos, row_sin, col_cos, col_sin):
|
| 41 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 42 |
+
return torch.cat([apply_rope(x1, row_cos, row_sin), apply_rope(x2, col_cos, col_sin)], dim=-1)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class RMSNormHead(nn.Module):
|
| 46 |
+
def __init__(self, head_dim, eps=1e-6):
|
| 47 |
+
super().__init__()
|
| 48 |
+
self.weight = nn.Parameter(torch.ones(head_dim))
|
| 49 |
+
self.eps = eps
|
| 50 |
+
|
| 51 |
+
def forward(self, x):
|
| 52 |
+
return x * x.pow(2).mean(-1, keepdim=True).add(self.eps).rsqrt() * self.weight
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class SwiGLU(nn.Module):
|
| 56 |
+
def __init__(self, dim, hidden):
|
| 57 |
+
super().__init__()
|
| 58 |
+
self.gate = nn.Linear(dim, hidden)
|
| 59 |
+
self.up = nn.Linear(dim, hidden)
|
| 60 |
+
self.down = nn.Linear(hidden, dim)
|
| 61 |
+
|
| 62 |
+
def forward(self, x):
|
| 63 |
+
return self.down(F.silu(self.gate(x)) * self.up(x))
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
class JointBlock(nn.Module):
|
| 67 |
+
def __init__(self, dim, heads, mlp_hidden):
|
| 68 |
+
super().__init__()
|
| 69 |
+
self.heads, self.head_dim = heads, dim // heads
|
| 70 |
+
self.norm1_img = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 71 |
+
self.norm1_txt = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 72 |
+
self.qkv_img = nn.Linear(dim, 3 * dim)
|
| 73 |
+
self.qkv_txt = nn.Linear(dim, 3 * dim)
|
| 74 |
+
self.qn_img, self.kn_img = RMSNormHead(self.head_dim), RMSNormHead(self.head_dim)
|
| 75 |
+
self.qn_txt, self.kn_txt = RMSNormHead(self.head_dim), RMSNormHead(self.head_dim)
|
| 76 |
+
self.proj_img, self.proj_txt = nn.Linear(dim, dim), nn.Linear(dim, dim)
|
| 77 |
+
self.norm2_img = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 78 |
+
self.norm2_txt = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 79 |
+
self.mlp_img, self.mlp_txt = SwiGLU(dim, mlp_hidden), SwiGLU(dim, mlp_hidden)
|
| 80 |
+
self.ada_img = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 81 |
+
self.ada_txt = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 82 |
+
|
| 83 |
+
def forward(self, img, txt, c, rope_img, rope_txt, key_valid):
|
| 84 |
+
s1i, sc1i, g1i, s2i, sc2i, g2i = self.ada_img(c).chunk(6, dim=-1)
|
| 85 |
+
s1t, sc1t, g1t, s2t, sc2t, g2t = self.ada_txt(c).chunk(6, dim=-1)
|
| 86 |
+
xi, xt = modulate(self.norm1_img(img), s1i, sc1i), modulate(self.norm1_txt(txt), s1t, sc1t)
|
| 87 |
+
b, ni, cdim = xi.shape; nt = xt.shape[1]; h, d = self.heads, self.head_dim
|
| 88 |
+
qi, ki, vi = self.qkv_img(xi).reshape(b, ni, 3, h, d).permute(2, 0, 3, 1, 4)
|
| 89 |
+
qt, kt, vt = self.qkv_txt(xt).reshape(b, nt, 3, h, d).permute(2, 0, 3, 1, 4)
|
| 90 |
+
qi, ki, qt, kt = self.qn_img(qi), self.kn_img(ki), self.qn_txt(qt), self.kn_txt(kt)
|
| 91 |
+
rc, rs, cc, cs = rope_img; tc, ts = rope_txt
|
| 92 |
+
qi, ki = apply_rope_2d(qi, rc, rs, cc, cs), apply_rope_2d(ki, rc, rs, cc, cs)
|
| 93 |
+
qt, kt = apply_rope(qt, tc, ts), apply_rope(kt, tc, ts)
|
| 94 |
+
q, k, v = torch.cat([qi, qt], 2), torch.cat([ki, kt], 2), torch.cat([vi, vt], 2)
|
| 95 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=key_valid[:, None, None, :])
|
| 96 |
+
o = o.transpose(1, 2).reshape(b, ni + nt, cdim)
|
| 97 |
+
oi, ot = o[:, :ni], o[:, ni:]
|
| 98 |
+
img = img + g1i[:, None] * self.proj_img(oi)
|
| 99 |
+
txt = txt + g1t[:, None] * self.proj_txt(ot)
|
| 100 |
+
img = img + g2i[:, None] * self.mlp_img(modulate(self.norm2_img(img), s2i, sc2i))
|
| 101 |
+
txt = txt + g2t[:, None] * self.mlp_txt(modulate(self.norm2_txt(txt), s2t, sc2t))
|
| 102 |
+
return img, txt
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMDiT(nn.Module):
|
| 106 |
+
def __init__(self, latent_ch=4, latent_size=32, patch=2, dim=512, depth=16, heads=8,
|
| 107 |
+
t5_dim=768, clip_dim=512, t5_len=32, mlp_hidden=1408, repa_dim=384, repa_layer=8):
|
| 108 |
+
super().__init__()
|
| 109 |
+
self.latent_ch, self.latent_size, self.patch = latent_ch, latent_size, patch
|
| 110 |
+
self.grid, self.patch_dim, self.dim = latent_size // patch, latent_ch * patch * patch, dim
|
| 111 |
+
self.t5_len, self.repa_layer = t5_len, repa_layer
|
| 112 |
+
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 113 |
+
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 114 |
+
self.clip_proj, self.t5_proj = nn.Linear(clip_dim, dim), nn.Linear(t5_dim, dim)
|
| 115 |
+
self.blocks = nn.ModuleList([JointBlock(dim, heads, mlp_hidden) for _ in range(depth)])
|
| 116 |
+
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 117 |
+
self.ada_out, self.head = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim)), nn.Linear(dim, self.patch_dim)
|
| 118 |
+
self.repa_head = nn.Sequential(nn.Linear(dim, dim), nn.GELU(approximate="tanh"), nn.Linear(dim, repa_dim))
|
| 119 |
+
hd2 = (dim // heads) // 2
|
| 120 |
+
rows = torch.arange(self.grid).repeat_interleave(self.grid); cols = torch.arange(self.grid).repeat(self.grid)
|
| 121 |
+
for name, value in zip(("row_cos", "row_sin", "col_cos", "col_sin"), (*rope_cos_sin(rope_freqs(rows, hd2)), *rope_cos_sin(rope_freqs(cols, hd2)))):
|
| 122 |
+
self.register_buffer(name, value, persistent=False)
|
| 123 |
+
self.register_buffer("t_cos", rope_cos_sin(rope_freqs(torch.arange(t5_len), dim // heads))[0], persistent=False)
|
| 124 |
+
self.register_buffer("t_sin", rope_cos_sin(rope_freqs(torch.arange(t5_len), dim // heads))[1], persistent=False)
|
| 125 |
+
|
| 126 |
+
def patchify(self, x):
|
| 127 |
+
b, c, h, w = x.shape; p = self.patch
|
| 128 |
+
return x.reshape(b, c, h // p, p, w // p, p).permute(0, 2, 4, 1, 3, 5).reshape(b, (h // p) * (w // p), c * p * p)
|
| 129 |
+
|
| 130 |
+
def unpatchify(self, x):
|
| 131 |
+
b, _, _ = x.shape; p, g, c = self.patch, self.grid, self.latent_ch
|
| 132 |
+
return x.reshape(b, g, g, c, p, p).permute(0, 3, 1, 4, 2, 5).reshape(b, c, g * p, g * p)
|
| 133 |
+
|
| 134 |
+
def forward(self, x, t, t5_seq, t5_mask, clip_pool):
|
| 135 |
+
b = x.shape[0]; img = self.x_embed(self.patchify(x)); txt = self.t5_proj(t5_seq)
|
| 136 |
+
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.clip_proj(clip_pool)
|
| 137 |
+
valid = torch.cat([torch.ones(b, img.shape[1], dtype=torch.bool, device=x.device), t5_mask.bool()], dim=1)
|
| 138 |
+
ri = (self.row_cos, self.row_sin, self.col_cos, self.col_sin); rt = (self.t_cos, self.t_sin)
|
| 139 |
+
for block in self.blocks: img, txt = block(img, txt, c, ri, rt, valid)
|
| 140 |
+
shift, scale = self.ada_out(c).chunk(2, dim=-1)
|
| 141 |
+
return self.unpatchify(self.head(modulate(self.norm_out(img), shift, scale)))
|
pixel_dit.py
CHANGED
|
@@ -1,133 +1,133 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
import math
|
| 4 |
-
import numpy as np
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn as nn
|
| 7 |
-
import torch.nn.functional as F
|
| 8 |
-
|
| 9 |
-
def modulate(x, shift, scale):
|
| 10 |
-
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
-
|
| 12 |
-
def timestep_embedding(t, dim, max_period=10000):
|
| 13 |
-
half = dim // 2
|
| 14 |
-
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 15 |
-
args = t[:, None].float() * freqs[None]
|
| 16 |
-
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 17 |
-
if dim % 2:
|
| 18 |
-
emb = torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1)
|
| 19 |
-
return emb
|
| 20 |
-
|
| 21 |
-
def sincos_2d(dim, grid_size):
|
| 22 |
-
g = np.arange(grid_size, dtype=np.float32)
|
| 23 |
-
gx, gy = np.meshgrid(g, g, indexing="xy")
|
| 24 |
-
assert dim % 4 == 0
|
| 25 |
-
d4 = dim // 4
|
| 26 |
-
omega = 1.0 / (10000 ** (np.arange(d4, dtype=np.float32) / d4))
|
| 27 |
-
def emb1(p):
|
| 28 |
-
out = p.reshape(-1)[:, None] * omega[None]
|
| 29 |
-
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 30 |
-
pe = np.concatenate([emb1(gx), emb1(gy)], axis=1)
|
| 31 |
-
return torch.from_numpy(pe).float()
|
| 32 |
-
|
| 33 |
-
class Attention(nn.Module):
|
| 34 |
-
def __init__(self, dim, heads):
|
| 35 |
-
super().__init__()
|
| 36 |
-
self.heads = heads
|
| 37 |
-
self.q = nn.Linear(dim, dim)
|
| 38 |
-
self.kv = nn.Linear(dim, dim * 2)
|
| 39 |
-
self.proj = nn.Linear(dim, dim)
|
| 40 |
-
|
| 41 |
-
def forward(self, x, ctx=None):
|
| 42 |
-
ctx = x if ctx is None else ctx
|
| 43 |
-
B, N, C = x.shape
|
| 44 |
-
M = ctx.shape[1]
|
| 45 |
-
h = self.heads
|
| 46 |
-
q = self.q(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 47 |
-
kv = self.kv(ctx).reshape(B, M, 2, h, C // h).permute(2, 0, 3, 1, 4)
|
| 48 |
-
k, v = kv[0], kv[1]
|
| 49 |
-
o = F.scaled_dot_product_attention(q, k, v)
|
| 50 |
-
o = o.transpose(1, 2).reshape(B, N, C)
|
| 51 |
-
return self.proj(o)
|
| 52 |
-
|
| 53 |
-
class Block(nn.Module):
|
| 54 |
-
def __init__(self, dim, heads, mlp_ratio=4.0):
|
| 55 |
-
super().__init__()
|
| 56 |
-
self.norm1 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 57 |
-
self.attn = Attention(dim, heads)
|
| 58 |
-
self.norm_ca = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 59 |
-
self.cross = Attention(dim, heads)
|
| 60 |
-
self.norm2 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 61 |
-
hidden = int(dim * mlp_ratio)
|
| 62 |
-
self.mlp = nn.Sequential(nn.Linear(dim, hidden), nn.GELU(approximate="tanh"),
|
| 63 |
-
nn.Linear(hidden, dim))
|
| 64 |
-
self.ada = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 65 |
-
self.cross_gate = nn.Parameter(torch.zeros(1))
|
| 66 |
-
|
| 67 |
-
def forward(self, x, c, text):
|
| 68 |
-
shift1, scale1, gate1, shift2, scale2, gate2 = self.ada(c).chunk(6, dim=1)
|
| 69 |
-
x = x + gate1.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift1, scale1))
|
| 70 |
-
x = x + self.cross_gate * self.cross(self.norm_ca(x), text)
|
| 71 |
-
x = x + gate2.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift2, scale2))
|
| 72 |
-
return x
|
| 73 |
-
|
| 74 |
-
class DiT(nn.Module):
|
| 75 |
-
def __init__(self, latent_ch=4, latent_size=32, patch=2, dim=384, depth=12,
|
| 76 |
-
heads=6, text_dim=512, mlp_ratio=4.0):
|
| 77 |
-
super().__init__()
|
| 78 |
-
self.latent_ch = latent_ch
|
| 79 |
-
self.latent_size = latent_size
|
| 80 |
-
self.patch = patch
|
| 81 |
-
self.grid = latent_size // patch
|
| 82 |
-
self.patch_dim = latent_ch * patch * patch
|
| 83 |
-
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 84 |
-
self.register_buffer("pos", sincos_2d(dim, self.grid).unsqueeze(0))
|
| 85 |
-
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 86 |
-
self.text_proj = nn.Linear(text_dim, dim)
|
| 87 |
-
self.text_pool = nn.Linear(text_dim, dim)
|
| 88 |
-
self.blocks = nn.ModuleList([Block(dim, heads, mlp_ratio) for _ in range(depth)])
|
| 89 |
-
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 90 |
-
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 91 |
-
self.head = nn.Linear(dim, self.patch_dim)
|
| 92 |
-
self.dim = dim
|
| 93 |
-
self._init()
|
| 94 |
-
|
| 95 |
-
def _init(self):
|
| 96 |
-
for m in self.modules():
|
| 97 |
-
if isinstance(m, nn.Linear):
|
| 98 |
-
nn.init.xavier_uniform_(m.weight)
|
| 99 |
-
if m.bias is not None:
|
| 100 |
-
nn.init.zeros_(m.bias)
|
| 101 |
-
for b in self.blocks:
|
| 102 |
-
nn.init.zeros_(b.ada[-1].weight); nn.init.zeros_(b.ada[-1].bias)
|
| 103 |
-
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 104 |
-
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 105 |
-
|
| 106 |
-
def patchify(self, x):
|
| 107 |
-
B, C, H, W = x.shape
|
| 108 |
-
p = self.patch
|
| 109 |
-
x = x.reshape(B, C, H // p, p, W // p, p)
|
| 110 |
-
x = x.permute(0, 2, 4, 1, 3, 5).reshape(B, (H // p) * (W // p), C * p * p)
|
| 111 |
-
return x
|
| 112 |
-
|
| 113 |
-
def unpatchify(self, x):
|
| 114 |
-
B, N, _ = x.shape
|
| 115 |
-
p = self.patch
|
| 116 |
-
g = self.grid
|
| 117 |
-
C = self.latent_ch
|
| 118 |
-
x = x.reshape(B, g, g, C, p, p).permute(0, 3, 1, 4, 2, 5)
|
| 119 |
-
return x.reshape(B, C, g * p, g * p)
|
| 120 |
-
|
| 121 |
-
def forward(self, x, t, text_seq, text_pool):
|
| 122 |
-
x = self.x_embed(self.patchify(x)) + self.pos
|
| 123 |
-
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.text_pool(text_pool)
|
| 124 |
-
text = self.text_proj(text_seq)
|
| 125 |
-
for blk in self.blocks:
|
| 126 |
-
x = blk(x, c, text)
|
| 127 |
-
shift, scale = self.ada_out(c).chunk(2, dim=1)
|
| 128 |
-
x = modulate(self.norm_out(x), shift, scale)
|
| 129 |
-
x = self.head(x)
|
| 130 |
-
return self.unpatchify(x)
|
| 131 |
-
|
| 132 |
-
def num_params(self):
|
| 133 |
-
return sum(p.numel() for p in self.parameters())
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import math
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
|
| 9 |
+
def modulate(x, shift, scale):
|
| 10 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
+
|
| 12 |
+
def timestep_embedding(t, dim, max_period=10000):
|
| 13 |
+
half = dim // 2
|
| 14 |
+
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 15 |
+
args = t[:, None].float() * freqs[None]
|
| 16 |
+
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 17 |
+
if dim % 2:
|
| 18 |
+
emb = torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1)
|
| 19 |
+
return emb
|
| 20 |
+
|
| 21 |
+
def sincos_2d(dim, grid_size):
|
| 22 |
+
g = np.arange(grid_size, dtype=np.float32)
|
| 23 |
+
gx, gy = np.meshgrid(g, g, indexing="xy")
|
| 24 |
+
assert dim % 4 == 0
|
| 25 |
+
d4 = dim // 4
|
| 26 |
+
omega = 1.0 / (10000 ** (np.arange(d4, dtype=np.float32) / d4))
|
| 27 |
+
def emb1(p):
|
| 28 |
+
out = p.reshape(-1)[:, None] * omega[None]
|
| 29 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 30 |
+
pe = np.concatenate([emb1(gx), emb1(gy)], axis=1)
|
| 31 |
+
return torch.from_numpy(pe).float()
|
| 32 |
+
|
| 33 |
+
class Attention(nn.Module):
|
| 34 |
+
def __init__(self, dim, heads):
|
| 35 |
+
super().__init__()
|
| 36 |
+
self.heads = heads
|
| 37 |
+
self.q = nn.Linear(dim, dim)
|
| 38 |
+
self.kv = nn.Linear(dim, dim * 2)
|
| 39 |
+
self.proj = nn.Linear(dim, dim)
|
| 40 |
+
|
| 41 |
+
def forward(self, x, ctx=None):
|
| 42 |
+
ctx = x if ctx is None else ctx
|
| 43 |
+
B, N, C = x.shape
|
| 44 |
+
M = ctx.shape[1]
|
| 45 |
+
h = self.heads
|
| 46 |
+
q = self.q(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 47 |
+
kv = self.kv(ctx).reshape(B, M, 2, h, C // h).permute(2, 0, 3, 1, 4)
|
| 48 |
+
k, v = kv[0], kv[1]
|
| 49 |
+
o = F.scaled_dot_product_attention(q, k, v)
|
| 50 |
+
o = o.transpose(1, 2).reshape(B, N, C)
|
| 51 |
+
return self.proj(o)
|
| 52 |
+
|
| 53 |
+
class Block(nn.Module):
|
| 54 |
+
def __init__(self, dim, heads, mlp_ratio=4.0):
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.norm1 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 57 |
+
self.attn = Attention(dim, heads)
|
| 58 |
+
self.norm_ca = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 59 |
+
self.cross = Attention(dim, heads)
|
| 60 |
+
self.norm2 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 61 |
+
hidden = int(dim * mlp_ratio)
|
| 62 |
+
self.mlp = nn.Sequential(nn.Linear(dim, hidden), nn.GELU(approximate="tanh"),
|
| 63 |
+
nn.Linear(hidden, dim))
|
| 64 |
+
self.ada = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 65 |
+
self.cross_gate = nn.Parameter(torch.zeros(1))
|
| 66 |
+
|
| 67 |
+
def forward(self, x, c, text):
|
| 68 |
+
shift1, scale1, gate1, shift2, scale2, gate2 = self.ada(c).chunk(6, dim=1)
|
| 69 |
+
x = x + gate1.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift1, scale1))
|
| 70 |
+
x = x + self.cross_gate * self.cross(self.norm_ca(x), text)
|
| 71 |
+
x = x + gate2.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift2, scale2))
|
| 72 |
+
return x
|
| 73 |
+
|
| 74 |
+
class DiT(nn.Module):
|
| 75 |
+
def __init__(self, latent_ch=4, latent_size=32, patch=2, dim=384, depth=12,
|
| 76 |
+
heads=6, text_dim=512, mlp_ratio=4.0):
|
| 77 |
+
super().__init__()
|
| 78 |
+
self.latent_ch = latent_ch
|
| 79 |
+
self.latent_size = latent_size
|
| 80 |
+
self.patch = patch
|
| 81 |
+
self.grid = latent_size // patch
|
| 82 |
+
self.patch_dim = latent_ch * patch * patch
|
| 83 |
+
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 84 |
+
self.register_buffer("pos", sincos_2d(dim, self.grid).unsqueeze(0))
|
| 85 |
+
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 86 |
+
self.text_proj = nn.Linear(text_dim, dim)
|
| 87 |
+
self.text_pool = nn.Linear(text_dim, dim)
|
| 88 |
+
self.blocks = nn.ModuleList([Block(dim, heads, mlp_ratio) for _ in range(depth)])
|
| 89 |
+
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 90 |
+
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 91 |
+
self.head = nn.Linear(dim, self.patch_dim)
|
| 92 |
+
self.dim = dim
|
| 93 |
+
self._init()
|
| 94 |
+
|
| 95 |
+
def _init(self):
|
| 96 |
+
for m in self.modules():
|
| 97 |
+
if isinstance(m, nn.Linear):
|
| 98 |
+
nn.init.xavier_uniform_(m.weight)
|
| 99 |
+
if m.bias is not None:
|
| 100 |
+
nn.init.zeros_(m.bias)
|
| 101 |
+
for b in self.blocks:
|
| 102 |
+
nn.init.zeros_(b.ada[-1].weight); nn.init.zeros_(b.ada[-1].bias)
|
| 103 |
+
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 104 |
+
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 105 |
+
|
| 106 |
+
def patchify(self, x):
|
| 107 |
+
B, C, H, W = x.shape
|
| 108 |
+
p = self.patch
|
| 109 |
+
x = x.reshape(B, C, H // p, p, W // p, p)
|
| 110 |
+
x = x.permute(0, 2, 4, 1, 3, 5).reshape(B, (H // p) * (W // p), C * p * p)
|
| 111 |
+
return x
|
| 112 |
+
|
| 113 |
+
def unpatchify(self, x):
|
| 114 |
+
B, N, _ = x.shape
|
| 115 |
+
p = self.patch
|
| 116 |
+
g = self.grid
|
| 117 |
+
C = self.latent_ch
|
| 118 |
+
x = x.reshape(B, g, g, C, p, p).permute(0, 3, 1, 4, 2, 5)
|
| 119 |
+
return x.reshape(B, C, g * p, g * p)
|
| 120 |
+
|
| 121 |
+
def forward(self, x, t, text_seq, text_pool):
|
| 122 |
+
x = self.x_embed(self.patchify(x)) + self.pos
|
| 123 |
+
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.text_pool(text_pool)
|
| 124 |
+
text = self.text_proj(text_seq)
|
| 125 |
+
for blk in self.blocks:
|
| 126 |
+
x = blk(x, c, text)
|
| 127 |
+
shift, scale = self.ada_out(c).chunk(2, dim=1)
|
| 128 |
+
x = modulate(self.norm_out(x), shift, scale)
|
| 129 |
+
x = self.head(x)
|
| 130 |
+
return self.unpatchify(x)
|
| 131 |
+
|
| 132 |
+
def num_params(self):
|
| 133 |
+
return sum(p.numel() for p in self.parameters())
|
requirements.txt
CHANGED
|
@@ -1,11 +1,13 @@
|
|
| 1 |
-
gradio
|
| 2 |
-
torch
|
| 3 |
-
diffusers==0.31.0
|
| 4 |
-
transformers==4.49.0
|
| 5 |
-
safetensors
|
| 6 |
-
numpy
|
| 7 |
-
Pillow
|
| 8 |
-
huggingface_hub
|
| 9 |
-
trimesh
|
| 10 |
-
scipy
|
| 11 |
-
audioop-lts
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
torch
|
| 3 |
+
diffusers==0.31.0
|
| 4 |
+
transformers==4.49.0
|
| 5 |
+
safetensors
|
| 6 |
+
numpy
|
| 7 |
+
Pillow
|
| 8 |
+
huggingface_hub
|
| 9 |
+
trimesh
|
| 10 |
+
scipy
|
| 11 |
+
audioop-lts
|
| 12 |
+
sentencepiece
|
| 13 |
+
accelerate
|
voxel_dit.py
CHANGED
|
@@ -1,134 +1,134 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
import math
|
| 4 |
-
import numpy as np
|
| 5 |
-
import torch
|
| 6 |
-
import torch.nn as nn
|
| 7 |
-
import torch.nn.functional as F
|
| 8 |
-
|
| 9 |
-
def modulate(x, shift, scale):
|
| 10 |
-
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
-
|
| 12 |
-
def timestep_embedding(t, dim, max_period=10000):
|
| 13 |
-
half = dim // 2
|
| 14 |
-
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 15 |
-
args = t[:, None].float() * freqs[None]
|
| 16 |
-
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 17 |
-
if dim % 2:
|
| 18 |
-
emb = torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1)
|
| 19 |
-
return emb
|
| 20 |
-
|
| 21 |
-
def sincos_3d(dim, grid_size):
|
| 22 |
-
assert dim % 6 == 0
|
| 23 |
-
g = np.arange(grid_size, dtype=np.float32)
|
| 24 |
-
gz, gy, gx = np.meshgrid(g, g, g, indexing="ij")
|
| 25 |
-
d6 = dim // 6
|
| 26 |
-
omega = 1.0 / (10000 ** (np.arange(d6, dtype=np.float32) / d6))
|
| 27 |
-
def emb1(p):
|
| 28 |
-
out = p.reshape(-1)[:, None] * omega[None]
|
| 29 |
-
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 30 |
-
pe = np.concatenate([emb1(gz), emb1(gy), emb1(gx)], axis=1)
|
| 31 |
-
return torch.from_numpy(pe).float()
|
| 32 |
-
|
| 33 |
-
class Attention(nn.Module):
|
| 34 |
-
def __init__(self, dim, heads):
|
| 35 |
-
super().__init__()
|
| 36 |
-
self.heads = heads
|
| 37 |
-
self.q = nn.Linear(dim, dim)
|
| 38 |
-
self.kv = nn.Linear(dim, dim * 2)
|
| 39 |
-
self.proj = nn.Linear(dim, dim)
|
| 40 |
-
|
| 41 |
-
def forward(self, x, ctx=None):
|
| 42 |
-
ctx = x if ctx is None else ctx
|
| 43 |
-
B, N, C = x.shape
|
| 44 |
-
M = ctx.shape[1]
|
| 45 |
-
h = self.heads
|
| 46 |
-
q = self.q(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 47 |
-
kv = self.kv(ctx).reshape(B, M, 2, h, C // h).permute(2, 0, 3, 1, 4)
|
| 48 |
-
k, v = kv[0], kv[1]
|
| 49 |
-
o = F.scaled_dot_product_attention(q, k, v)
|
| 50 |
-
o = o.transpose(1, 2).reshape(B, N, C)
|
| 51 |
-
return self.proj(o)
|
| 52 |
-
|
| 53 |
-
class Block(nn.Module):
|
| 54 |
-
def __init__(self, dim, heads, mlp_ratio=4.0):
|
| 55 |
-
super().__init__()
|
| 56 |
-
self.norm1 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 57 |
-
self.attn = Attention(dim, heads)
|
| 58 |
-
self.norm_ca = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 59 |
-
self.cross = Attention(dim, heads)
|
| 60 |
-
self.norm2 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 61 |
-
hidden = int(dim * mlp_ratio)
|
| 62 |
-
self.mlp = nn.Sequential(nn.Linear(dim, hidden), nn.GELU(approximate="tanh"),
|
| 63 |
-
nn.Linear(hidden, dim))
|
| 64 |
-
self.ada = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 65 |
-
self.cross_gate = nn.Parameter(torch.zeros(1))
|
| 66 |
-
|
| 67 |
-
def forward(self, x, c, text):
|
| 68 |
-
shift1, scale1, gate1, shift2, scale2, gate2 = self.ada(c).chunk(6, dim=1)
|
| 69 |
-
x = x + gate1.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift1, scale1))
|
| 70 |
-
x = x + self.cross_gate * self.cross(self.norm_ca(x), text)
|
| 71 |
-
x = x + gate2.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift2, scale2))
|
| 72 |
-
return x
|
| 73 |
-
|
| 74 |
-
class VoxelDiT(nn.Module):
|
| 75 |
-
def __init__(self, vox_ch=1, vox_size=32, patch=4, dim=384, depth=12,
|
| 76 |
-
heads=6, text_dim=512, mlp_ratio=4.0):
|
| 77 |
-
super().__init__()
|
| 78 |
-
self.vox_ch = vox_ch
|
| 79 |
-
self.vox_size = vox_size
|
| 80 |
-
self.patch = patch
|
| 81 |
-
self.grid = vox_size // patch
|
| 82 |
-
self.patch_dim = vox_ch * patch * patch * patch
|
| 83 |
-
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 84 |
-
self.register_buffer("pos", sincos_3d(dim, self.grid).unsqueeze(0))
|
| 85 |
-
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 86 |
-
self.text_proj = nn.Linear(text_dim, dim)
|
| 87 |
-
self.text_pool = nn.Linear(text_dim, dim)
|
| 88 |
-
self.blocks = nn.ModuleList([Block(dim, heads, mlp_ratio) for _ in range(depth)])
|
| 89 |
-
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 90 |
-
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 91 |
-
self.head = nn.Linear(dim, self.patch_dim)
|
| 92 |
-
self.dim = dim
|
| 93 |
-
self._init()
|
| 94 |
-
|
| 95 |
-
def _init(self):
|
| 96 |
-
for m in self.modules():
|
| 97 |
-
if isinstance(m, nn.Linear):
|
| 98 |
-
nn.init.xavier_uniform_(m.weight)
|
| 99 |
-
if m.bias is not None:
|
| 100 |
-
nn.init.zeros_(m.bias)
|
| 101 |
-
for b in self.blocks:
|
| 102 |
-
nn.init.zeros_(b.ada[-1].weight); nn.init.zeros_(b.ada[-1].bias)
|
| 103 |
-
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 104 |
-
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 105 |
-
|
| 106 |
-
def patchify(self, x):
|
| 107 |
-
B, C, D, H, W = x.shape
|
| 108 |
-
p = self.patch
|
| 109 |
-
x = x.reshape(B, C, D // p, p, H // p, p, W // p, p)
|
| 110 |
-
x = x.permute(0, 2, 4, 6, 1, 3, 5, 7)
|
| 111 |
-
return x.reshape(B, (D // p) * (H // p) * (W // p), C * p * p * p)
|
| 112 |
-
|
| 113 |
-
def unpatchify(self, x):
|
| 114 |
-
B, N, _ = x.shape
|
| 115 |
-
p = self.patch
|
| 116 |
-
g = self.grid
|
| 117 |
-
C = self.vox_ch
|
| 118 |
-
x = x.reshape(B, g, g, g, C, p, p, p)
|
| 119 |
-
x = x.permute(0, 4, 1, 5, 2, 6, 3, 7)
|
| 120 |
-
return x.reshape(B, C, g * p, g * p, g * p)
|
| 121 |
-
|
| 122 |
-
def forward(self, x, t, text_seq, text_pool):
|
| 123 |
-
x = self.x_embed(self.patchify(x)) + self.pos
|
| 124 |
-
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.text_pool(text_pool)
|
| 125 |
-
text = self.text_proj(text_seq)
|
| 126 |
-
for blk in self.blocks:
|
| 127 |
-
x = blk(x, c, text)
|
| 128 |
-
shift, scale = self.ada_out(c).chunk(2, dim=1)
|
| 129 |
-
x = modulate(self.norm_out(x), shift, scale)
|
| 130 |
-
x = self.head(x)
|
| 131 |
-
return self.unpatchify(x)
|
| 132 |
-
|
| 133 |
-
def num_params(self):
|
| 134 |
-
return sum(p.numel() for p in self.parameters())
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import math
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
|
| 9 |
+
def modulate(x, shift, scale):
|
| 10 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
+
|
| 12 |
+
def timestep_embedding(t, dim, max_period=10000):
|
| 13 |
+
half = dim // 2
|
| 14 |
+
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 15 |
+
args = t[:, None].float() * freqs[None]
|
| 16 |
+
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 17 |
+
if dim % 2:
|
| 18 |
+
emb = torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1)
|
| 19 |
+
return emb
|
| 20 |
+
|
| 21 |
+
def sincos_3d(dim, grid_size):
|
| 22 |
+
assert dim % 6 == 0
|
| 23 |
+
g = np.arange(grid_size, dtype=np.float32)
|
| 24 |
+
gz, gy, gx = np.meshgrid(g, g, g, indexing="ij")
|
| 25 |
+
d6 = dim // 6
|
| 26 |
+
omega = 1.0 / (10000 ** (np.arange(d6, dtype=np.float32) / d6))
|
| 27 |
+
def emb1(p):
|
| 28 |
+
out = p.reshape(-1)[:, None] * omega[None]
|
| 29 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 30 |
+
pe = np.concatenate([emb1(gz), emb1(gy), emb1(gx)], axis=1)
|
| 31 |
+
return torch.from_numpy(pe).float()
|
| 32 |
+
|
| 33 |
+
class Attention(nn.Module):
|
| 34 |
+
def __init__(self, dim, heads):
|
| 35 |
+
super().__init__()
|
| 36 |
+
self.heads = heads
|
| 37 |
+
self.q = nn.Linear(dim, dim)
|
| 38 |
+
self.kv = nn.Linear(dim, dim * 2)
|
| 39 |
+
self.proj = nn.Linear(dim, dim)
|
| 40 |
+
|
| 41 |
+
def forward(self, x, ctx=None):
|
| 42 |
+
ctx = x if ctx is None else ctx
|
| 43 |
+
B, N, C = x.shape
|
| 44 |
+
M = ctx.shape[1]
|
| 45 |
+
h = self.heads
|
| 46 |
+
q = self.q(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 47 |
+
kv = self.kv(ctx).reshape(B, M, 2, h, C // h).permute(2, 0, 3, 1, 4)
|
| 48 |
+
k, v = kv[0], kv[1]
|
| 49 |
+
o = F.scaled_dot_product_attention(q, k, v)
|
| 50 |
+
o = o.transpose(1, 2).reshape(B, N, C)
|
| 51 |
+
return self.proj(o)
|
| 52 |
+
|
| 53 |
+
class Block(nn.Module):
|
| 54 |
+
def __init__(self, dim, heads, mlp_ratio=4.0):
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.norm1 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 57 |
+
self.attn = Attention(dim, heads)
|
| 58 |
+
self.norm_ca = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 59 |
+
self.cross = Attention(dim, heads)
|
| 60 |
+
self.norm2 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 61 |
+
hidden = int(dim * mlp_ratio)
|
| 62 |
+
self.mlp = nn.Sequential(nn.Linear(dim, hidden), nn.GELU(approximate="tanh"),
|
| 63 |
+
nn.Linear(hidden, dim))
|
| 64 |
+
self.ada = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 65 |
+
self.cross_gate = nn.Parameter(torch.zeros(1))
|
| 66 |
+
|
| 67 |
+
def forward(self, x, c, text):
|
| 68 |
+
shift1, scale1, gate1, shift2, scale2, gate2 = self.ada(c).chunk(6, dim=1)
|
| 69 |
+
x = x + gate1.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift1, scale1))
|
| 70 |
+
x = x + self.cross_gate * self.cross(self.norm_ca(x), text)
|
| 71 |
+
x = x + gate2.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift2, scale2))
|
| 72 |
+
return x
|
| 73 |
+
|
| 74 |
+
class VoxelDiT(nn.Module):
|
| 75 |
+
def __init__(self, vox_ch=1, vox_size=32, patch=4, dim=384, depth=12,
|
| 76 |
+
heads=6, text_dim=512, mlp_ratio=4.0):
|
| 77 |
+
super().__init__()
|
| 78 |
+
self.vox_ch = vox_ch
|
| 79 |
+
self.vox_size = vox_size
|
| 80 |
+
self.patch = patch
|
| 81 |
+
self.grid = vox_size // patch
|
| 82 |
+
self.patch_dim = vox_ch * patch * patch * patch
|
| 83 |
+
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 84 |
+
self.register_buffer("pos", sincos_3d(dim, self.grid).unsqueeze(0))
|
| 85 |
+
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 86 |
+
self.text_proj = nn.Linear(text_dim, dim)
|
| 87 |
+
self.text_pool = nn.Linear(text_dim, dim)
|
| 88 |
+
self.blocks = nn.ModuleList([Block(dim, heads, mlp_ratio) for _ in range(depth)])
|
| 89 |
+
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 90 |
+
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 91 |
+
self.head = nn.Linear(dim, self.patch_dim)
|
| 92 |
+
self.dim = dim
|
| 93 |
+
self._init()
|
| 94 |
+
|
| 95 |
+
def _init(self):
|
| 96 |
+
for m in self.modules():
|
| 97 |
+
if isinstance(m, nn.Linear):
|
| 98 |
+
nn.init.xavier_uniform_(m.weight)
|
| 99 |
+
if m.bias is not None:
|
| 100 |
+
nn.init.zeros_(m.bias)
|
| 101 |
+
for b in self.blocks:
|
| 102 |
+
nn.init.zeros_(b.ada[-1].weight); nn.init.zeros_(b.ada[-1].bias)
|
| 103 |
+
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 104 |
+
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 105 |
+
|
| 106 |
+
def patchify(self, x):
|
| 107 |
+
B, C, D, H, W = x.shape
|
| 108 |
+
p = self.patch
|
| 109 |
+
x = x.reshape(B, C, D // p, p, H // p, p, W // p, p)
|
| 110 |
+
x = x.permute(0, 2, 4, 6, 1, 3, 5, 7)
|
| 111 |
+
return x.reshape(B, (D // p) * (H // p) * (W // p), C * p * p * p)
|
| 112 |
+
|
| 113 |
+
def unpatchify(self, x):
|
| 114 |
+
B, N, _ = x.shape
|
| 115 |
+
p = self.patch
|
| 116 |
+
g = self.grid
|
| 117 |
+
C = self.vox_ch
|
| 118 |
+
x = x.reshape(B, g, g, g, C, p, p, p)
|
| 119 |
+
x = x.permute(0, 4, 1, 5, 2, 6, 3, 7)
|
| 120 |
+
return x.reshape(B, C, g * p, g * p, g * p)
|
| 121 |
+
|
| 122 |
+
def forward(self, x, t, text_seq, text_pool):
|
| 123 |
+
x = self.x_embed(self.patchify(x)) + self.pos
|
| 124 |
+
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.text_pool(text_pool)
|
| 125 |
+
text = self.text_proj(text_seq)
|
| 126 |
+
for blk in self.blocks:
|
| 127 |
+
x = blk(x, c, text)
|
| 128 |
+
shift, scale = self.ada_out(c).chunk(2, dim=1)
|
| 129 |
+
x = modulate(self.norm_out(x), shift, scale)
|
| 130 |
+
x = self.head(x)
|
| 131 |
+
return self.unpatchify(x)
|
| 132 |
+
|
| 133 |
+
def num_params(self):
|
| 134 |
+
return sum(p.numel() for p in self.parameters())
|