PixelModel-v6 / preview.py
TobiasLogic's picture
Publish PixelModel v6: MMDiT + REPA, 150k steps, FID 23.62 at cfg 3.0
6c311ad verified
Raw
History Blame Contribute Delete
4.02 kB
from __future__ import annotations
import argparse
import numpy as np
import torch
from PIL import Image
from diffusers import AutoencoderKL
from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
from dit_v6 import MMDiT
PROMPTS = [
"a bowl of ramen with a soft boiled egg",
"a red fox sitting in a snowy forest",
"a lighthouse on a cliff at sunset",
"a wooden cabin in the mountains",
"a cup of coffee on a wooden table",
"a golden retriever running on a beach",
"a city street at night with neon signs",
"a bowl of fresh strawberries",
"a sailboat on a calm lake",
]
@torch.no_grad()
def sample(model, seq, mask, pool, null_seq, null_mask, null_pool, steps, cfg, dev):
B = seq.shape[0]
x = torch.randn(B, 4, 32, 32, device=dev)
ns, nm, npo = null_seq.expand(B, -1, -1), null_mask.expand(B, -1), null_pool.expand(B, -1)
dt = 1.0 / steps
for i in range(steps):
t = torch.full((B,), i * dt, device=dev)
with torch.autocast("cuda", dtype=torch.bfloat16):
vc = model(x, t, seq, mask, pool)
vu = model(x, t, ns, nm, npo)
x = x + (vu + cfg * (vc - vu)).float() * dt
return x
@torch.no_grad()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--ckpt", default="/root/runs/pm6/best.pt")
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
ap.add_argument("--t5", default="google/flan-t5-base")
ap.add_argument("--steps", type=int, default=50)
ap.add_argument("--cfg", type=float, default=5.0)
ap.add_argument("--t5-len", type=int, default=32)
ap.add_argument("--clip-len", type=int, default=40)
ap.add_argument("--out", default="/root/preview.png")
args = ap.parse_args()
dev = "cuda"
ck = torch.load(args.ckpt, map_location=dev)
c = ck["cfg"]
model = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"],
t5_len=c["t5_len"]).to(dev).eval()
model.load_state_dict(ck["ema"])
print(f"[preview] loaded {args.ckpt} step {ck['step']}", flush=True)
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
vae_scale = vae.config.scaling_factor
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
t5 = T5EncoderModel.from_pretrained(args.t5).to(dev).eval()
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
clip_txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
def enc(strings):
te = t5_tok(strings, padding="max_length", max_length=args.t5_len, truncation=True,
return_tensors="pt").to(dev)
seq = t5(input_ids=te["input_ids"], attention_mask=te["attention_mask"]).last_hidden_state.float()
ce = clip_tok(strings, padding="max_length", max_length=args.clip_len, truncation=True,
return_tensors="pt").to(dev)
pool = clip_txt(input_ids=ce["input_ids"]).pooler_output.float()
return seq, te["attention_mask"].float(), pool
null_seq, null_mask, null_pool = enc([""])
cell, pad, cols = 256, 8, 3
rows = (len(PROMPTS) + cols - 1) // cols
sheet = Image.new("RGB", (cols * cell + (cols + 1) * pad, rows * cell + (rows + 1) * pad), (245, 246, 248))
for i, prompt in enumerate(PROMPTS):
seq, mask, pool = enc([prompt])
z = sample(model, seq, mask, pool, null_seq, null_mask, null_pool, args.steps, args.cfg, dev)
img = vae.decode((z / vae_scale).half()).sample.float()
img = ((img.clamp(-1, 1) + 1) / 2)[0].permute(1, 2, 0).cpu().numpy()
a = (img * 255).round().astype(np.uint8)
r, cc = divmod(i, cols)
sheet.paste(Image.fromarray(a), (pad + cc * (cell + pad), pad + r * (cell + pad)))
print(f"[preview] {i+1}/{len(PROMPTS)}: {prompt}", flush=True)
sheet.save(args.out)
print(f"[preview] wrote {args.out}", flush=True)
if __name__ == "__main__":
main()