Publish PixelModel v6: MMDiT + REPA, 150k steps, FID 23.62 at cfg 3.0
Browse files- .gitattributes +2 -0
- README.md +192 -0
- build_eval_set.py +90 -0
- config.json +51 -0
- dit_v6.py +233 -0
- eval_v6.py +141 -0
- examples.png +3 -0
- main.py +79 -0
- model.png +3 -0
- model.safetensors +3 -0
- model_png.json +1 -0
- pixelmodel-v6-loss.png +0 -0
- pixelmodel-v6-params.png +0 -0
- pixelmodel-v6-val.png +0 -0
- png_codec.py +80 -0
- prep_v6.py +141 -0
- preview.py +96 -0
- publish_v6.py +13 -0
- train_v6.py +286 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* 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
|
|
|
|
|
|
|
|
|
| 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.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
model.png filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
pipeline_tag: text-to-image
|
| 4 |
+
language:
|
| 5 |
+
- en
|
| 6 |
+
tags:
|
| 7 |
+
- text-to-image
|
| 8 |
+
- diffusion
|
| 9 |
+
- rectified-flow
|
| 10 |
+
- mmdit
|
| 11 |
+
- tiny
|
| 12 |
+
- custom-code
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# PixelModel v6 🖼️
|
| 16 |
+
|
| 17 |
+
<img src="examples.png" alt="Two 256px images generated by PixelModel v6: a lighthouse on a cliff at sunset, and a cup of coffee on a wooden table" style="width: 100%; max-width: 600px;">
|
| 18 |
+
|
| 19 |
+
*"a lighthouse on a cliff at sunset" / "a cup of coffee on a wooden table", cfg 4.0, single draw each, not
|
| 20 |
+
cherry-picked from multiple seeds*
|
| 21 |
+
|
| 22 |
+
PixelModel v6 is a 155,090,448 parameter text-to-image diffusion transformer. It generates 256x256
|
| 23 |
+
images in 50 sampling steps and it trained in about 55 hours across two A100s.
|
| 24 |
+
|
| 25 |
+
Where [v5](https://huggingface.co/bench-labs/PixelModel-v5) changed the data and kept v4's
|
| 26 |
+
architecture byte for byte, v6 changes the architecture and keeps v5's data. v5's own README ended
|
| 27 |
+
with a diagnosis: the model had learned appearance thoroughly and topology poorly, and topology is
|
| 28 |
+
what capacity buys. This is that bet.
|
| 29 |
+
|
| 30 |
+
## What actually changed
|
| 31 |
+
|
| 32 |
+
Six real architecture changes, not one, which is a departure from this line's usual practice of
|
| 33 |
+
isolating a single variable per release. Each change has independent literature support; the
|
| 34 |
+
combination does not, and that is worth being upfront about rather than implying six papers'
|
| 35 |
+
results simply add up.
|
| 36 |
+
|
| 37 |
+
**Joint attention instead of cross-attention.** v4 and v5 read text through cross-attention, the way
|
| 38 |
+
PixArt-alpha does it. v6 concatenates image and text tokens into one sequence and runs joint
|
| 39 |
+
self-attention over both, the way SD3's MMDiT does it, so text tokens can attend to image tokens and
|
| 40 |
+
not just the reverse.
|
| 41 |
+
|
| 42 |
+
**T5 instead of CLIP-only conditioning.** The joint stream is built from `google/flan-t5-base`
|
| 43 |
+
hidden states rather than CLIP token embeddings. CLIP's pooled vector is kept, but only for the
|
| 44 |
+
global adaLN conditioning signal. T5 conditioning is the specific change PixArt-alpha, DeepFloyd IF,
|
| 45 |
+
and SD3 all made for prompt adherence, and v5's README named exactly this failure mode: prompts
|
| 46 |
+
asking for one object in an empty scene often returned the scene without the object.
|
| 47 |
+
|
| 48 |
+
**2D RoPE instead of additive sincos position embeddings.** Image tokens get axial rotary position
|
| 49 |
+
encoding, text tokens get standard 1D rotary encoding. This is also what makes a future higher
|
| 50 |
+
resolution fine-tune cheap: RoPE carries no learned parameters, so a checkpoint trained at 256px can
|
| 51 |
+
extend to a larger token grid without retraining or interpolating a position embedding table.
|
| 52 |
+
|
| 53 |
+
**QK-norm and SwiGLU.** RMSNorm on queries and keys before attention, and a SwiGLU MLP in place of
|
| 54 |
+
GELU. Both are standard modern stabilizers, included because a bigger model trains less forgivingly
|
| 55 |
+
than a 40M one.
|
| 56 |
+
|
| 57 |
+
**REPA.** An auxiliary loss projecting mid-stack image token hidden states to align with frozen
|
| 58 |
+
DINOv2-small features of the same image, cosine similarity, weight scheduled to peak early and decay
|
| 59 |
+
to exactly zero by step 105,000. This is the one item on this list without solid precedent at this
|
| 60 |
+
scale: the original REPA paper is class-conditional ImageNet at 675M parameters, and v5's own
|
| 61 |
+
planning notes flagged that transfer to text-conditional generation at a fraction of that size as
|
| 62 |
+
genuinely unverified. The decay schedule follows the follow-up finding that the alignment loss helps
|
| 63 |
+
early and can hurt if left on too long.
|
| 64 |
+
|
| 65 |
+
**More capacity.** dim 512, depth 16, heads 8: 155.1M trainable, versus v5's 40M. Still well short of
|
| 66 |
+
SD1.5's 860M UNet or SDXL's 2.6B, but the largest this line has been.
|
| 67 |
+
|
| 68 |
+
<img src="pixelmodel-v6-params.png" alt="Trainable backbone size by version, v4 and v5 at 40M, v6 at 155.1M" style="width: 100%; max-width: 700px;">
|
| 69 |
+
|
| 70 |
+
The frozen VAE also moved from `sd-vae-ft-mse` to `madebyollin/sdxl-vae-fp16-fix`, a drop-in upgrade
|
| 71 |
+
at the same latent shape.
|
| 72 |
+
|
| 73 |
+
## Training
|
| 74 |
+
|
| 75 |
+
<img src="pixelmodel-v6-loss.png" alt="Training loss, diffusion and REPA components, over 150,000 steps" style="width: 100%; max-width: 860px;">
|
| 76 |
+
|
| 77 |
+
150,000 steps at batch 192 on the same 2,986,571 image CC12M-recaptioned set v5 used, about 9.7
|
| 78 |
+
epochs. AdamW at 2e-4, cosine decay after a 1,500 step warmup, EMA at 0.9999, 10% caption dropout,
|
| 79 |
+
gradient checkpointing throughout. The REPA loss ran at peak weight for the first 40% of training,
|
| 80 |
+
decayed linearly through the next 30%, and sat at exactly zero for the final 30%, both to follow the
|
| 81 |
+
early-stopping finding above and because computing DINOv2 targets costs real throughput: the run held
|
| 82 |
+
0.86 steps/s while REPA was active and 1.39 steps/s once it turned off.
|
| 83 |
+
|
| 84 |
+
<img src="pixelmodel-v6-val.png" alt="Held-out validation loss falling monotonically from 0.938 to 0.798" style="width: 100%; max-width: 860px;">
|
| 85 |
+
|
| 86 |
+
Held-out loss on a fixed 4,096-pair split, evaluated every 2,000 steps, fell without interruption
|
| 87 |
+
from 0.938 to 0.798 across the entire run. No overfitting turn-up at any point, same clean shape v5
|
| 88 |
+
reported.
|
| 89 |
+
|
| 90 |
+
This run was not a clean single continuous job. It moved between two rented A100s partway through
|
| 91 |
+
(a direct box-to-box transfer once the economics of a cheaper card made sense, verified byte-identical
|
| 92 |
+
by checksum before the first box was released), and survived two host-level outages on the vast.ai
|
| 93 |
+
side, both recovered from the last saved checkpoint. Total lost progress across both interruptions
|
| 94 |
+
was under a thousand steps out of 150,000. Worth stating plainly rather than pretending the run was
|
| 95 |
+
tidier than it was.
|
| 96 |
+
|
| 97 |
+
## Results
|
| 98 |
+
|
| 99 |
+
Measured on 5,000 MS-COCO val2014 images at 256 center crop, `torchmetrics` FID at 2048 features and
|
| 100 |
+
`torchmetrics` CLIPScore with `openai/clip-vit-base-patch32`. Identical protocol to v4 and v5.
|
| 101 |
+
|
| 102 |
+
| | FID ↓ | CLIP ↑ |
|
| 103 |
+
|---|---|---|
|
| 104 |
+
| PixelModel v4 | 39.54 | 28.04 |
|
| 105 |
+
| PixelModel v5 | 34.06 | 29.27 |
|
| 106 |
+
| **PixelModel v6, cfg 3.0** | **23.62** | 30.43 |
|
| 107 |
+
| real photographs | n/a | 30.05 |
|
| 108 |
+
|
| 109 |
+
v6 beats v5's best FID by over 10 points at every guidance scale tested, not just at one cherry-picked
|
| 110 |
+
value. Full sweep, same 5,000 image set and 50 sampling steps throughout:
|
| 111 |
+
|
| 112 |
+
| cfg | FID ↓ | CLIP ↑ |
|
| 113 |
+
|---|---|---|
|
| 114 |
+
| 2.0 | 25.65 | 29.65 |
|
| 115 |
+
| **3.0** | **23.62** | 30.43 |
|
| 116 |
+
| 4.0 | 23.77 | 30.81 |
|
| 117 |
+
| 5.0 | 24.42 | 31.06 |
|
| 118 |
+
| 6.0 | 25.10 | 31.12 |
|
| 119 |
+
| 7.0 | 26.26 | 31.16 |
|
| 120 |
+
| 8.0 | 26.87 | 31.17 |
|
| 121 |
+
|
| 122 |
+
FID bottoms at cfg 3.0 and rises steadily past it, the usual guidance tradeoff: more weight on the
|
| 123 |
+
text condition pulls generations away from the real-image manifold even as it pulls them closer to
|
| 124 |
+
the prompt. cfg 3.0 is the reported default. Worth flagging rather than celebrating: CLIP score
|
| 125 |
+
crosses the real-photograph baseline (30.05) starting around cfg 4.0 and keeps climbing to 31.17.
|
| 126 |
+
That is not v6 out-photographing real photographs, it is high guidance making generations more
|
| 127 |
+
literal about the prompt than an actual photo ever is, which CLIP score rewards and FID does not. Use
|
| 128 |
+
FID, not CLIP, to pick a guidance scale.
|
| 129 |
+
|
| 130 |
+
## What it does well and what it does not
|
| 131 |
+
|
| 132 |
+
Judged across several hundred samples during training, not just the checkpoint above.
|
| 133 |
+
|
| 134 |
+
It is good at material, light, and increasingly at structure that v5 could not hold: food, faces of
|
| 135 |
+
common animals, latte foam texture, boat masts and sails, neon-lit streets. Where v5's README singled
|
| 136 |
+
out faces and animal heads as a weak point, v6 renders recognizable dog and fox faces reliably by the
|
| 137 |
+
back half of training, something no earlier version in this line managed.
|
| 138 |
+
|
| 139 |
+
It is still uneven on rare subjects. Across many samples of the same fox prompt, output quality
|
| 140 |
+
varied far more than for common subjects like coffee or strawberries, which is a direct read on
|
| 141 |
+
training data frequency in CC12M rather than a model defect: the architecture change did not fix data
|
| 142 |
+
scarcity, it just makes better use of what is there.
|
| 143 |
+
|
| 144 |
+
A watermark and ghost-text artifact shows up intermittently, most often on the lighthouse and boat
|
| 145 |
+
prompts: faint illegible text-like marks bled in from CC12M's watermarked stock photography, the same
|
| 146 |
+
failure family v5 documented for actual text rendering. It did not fully train out by step 150,000.
|
| 147 |
+
|
| 148 |
+
## Specification
|
| 149 |
+
|
| 150 |
+
| | |
|
| 151 |
+
|---|---|
|
| 152 |
+
| trainable parameters | 155,090,448 |
|
| 153 |
+
| frozen VAE, `sdxl-vae-fp16-fix` | 83,653,863 |
|
| 154 |
+
| frozen text encoder, CLIP ViT-B/32 | 63,165,952 |
|
| 155 |
+
| frozen text encoder, T5-base | 109,628,544 |
|
| 156 |
+
| **combined total** | **411,538,807** |
|
| 157 |
+
| architecture | MMDiT, dim 512, depth 16, heads 8, patch 2 |
|
| 158 |
+
| tokens | 256 image (16x16 over a 32x32x4 latent) + 32 text |
|
| 159 |
+
| objective | rectified flow, target `x1 - x0`, logit-normal timesteps |
|
| 160 |
+
| conditioning | joint attention on T5 tokens, plus adaLN-zero from CLIP pooled + timestep |
|
| 161 |
+
| resolution | 256x256 |
|
| 162 |
+
| sampling | 50 steps, cfg 3.0 default (23.62 FID); see cfg sweep above for the tradeoff |
|
| 163 |
+
|
| 164 |
+
All parameter counts above are the released backbone. Training also carried a small REPA projection
|
| 165 |
+
head (459,648 params, 155,550,096 total while training) that only ever fed the auxiliary alignment
|
| 166 |
+
loss; it has no role in sampling and is dropped from the published weights.
|
| 167 |
+
|
| 168 |
+
## Usage
|
| 169 |
+
|
| 170 |
+
```bash
|
| 171 |
+
python main.py "a bowl of ramen with a soft boiled egg" --out ramen.png --cfg 3.0 --steps 50
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
As with every model in this line the weights are also stored as a PNG. `model.png` is not a picture
|
| 175 |
+
of the network, it is the network, with each parameter packed across the red and green channels of
|
| 176 |
+
one pixel.
|
| 177 |
+
|
| 178 |
+
## Files
|
| 179 |
+
|
| 180 |
+
| file | contents |
|
| 181 |
+
|---|---|
|
| 182 |
+
| `model.safetensors` | the trainable MMDiT backbone only, fp32. VAE, CLIP, and T5 load fresh from their own HF repos at inference time, same convention as v4 and v5 despite what their READMEs said |
|
| 183 |
+
| `model.png` | the same backbone weights as an image, fp16, packed via `png_codec.py`. Verified bit-exact against `model.safetensors` (rounded to fp16) before upload |
|
| 184 |
+
| `model_png.json` | manifest `png_codec.py` needs to decode `model.png` back into a state dict |
|
| 185 |
+
| `png_codec.py` | the PNG weight codec, encode and decode |
|
| 186 |
+
| `dit_v6.py` | the model |
|
| 187 |
+
| `train_v6.py` | training loop, REPA schedule, held-out split |
|
| 188 |
+
| `prep_v6.py` | streams CC12M-recaptioned, encodes latents, caches tokens |
|
| 189 |
+
| `build_eval_set.py` | builds the 5,000 image COCO val2014 eval set |
|
| 190 |
+
| `eval_v6.py` | FID / CLIPScore protocol and cfg sweep |
|
| 191 |
+
| `preview.py` | quick sampling CLI for spot checks |
|
| 192 |
+
| `main.py` | inference |
|
build_eval_set.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import io
|
| 5 |
+
import json
|
| 6 |
+
import os
|
| 7 |
+
import random
|
| 8 |
+
import zipfile
|
| 9 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import requests
|
| 13 |
+
from PIL import Image
|
| 14 |
+
|
| 15 |
+
ANN_URL = "http://images.cocodataset.org/annotations/annotations_trainval2014.zip"
|
| 16 |
+
|
| 17 |
+
def csr(img, size):
|
| 18 |
+
img = img.convert("RGB")
|
| 19 |
+
w, h = img.size
|
| 20 |
+
s = min(w, h)
|
| 21 |
+
l, t = (w - s) // 2, (h - s) // 2
|
| 22 |
+
return np.asarray(img.crop((l, t, l + s, t + s)).resize((size, size), Image.BICUBIC), dtype=np.uint8)
|
| 23 |
+
|
| 24 |
+
def fetch_one(item, size):
|
| 25 |
+
url, cap = item
|
| 26 |
+
for _ in range(3):
|
| 27 |
+
try:
|
| 28 |
+
r = requests.get(url, timeout=15)
|
| 29 |
+
if r.status_code == 200:
|
| 30 |
+
return csr(Image.open(io.BytesIO(r.content)), size), cap
|
| 31 |
+
except Exception:
|
| 32 |
+
pass
|
| 33 |
+
return None
|
| 34 |
+
|
| 35 |
+
def main():
|
| 36 |
+
ap = argparse.ArgumentParser()
|
| 37 |
+
ap.add_argument("--work", default="/root/v6cache")
|
| 38 |
+
ap.add_argument("--n", type=int, default=5000)
|
| 39 |
+
ap.add_argument("--size", type=int, default=256)
|
| 40 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 41 |
+
ap.add_argument("--workers", type=int, default=48)
|
| 42 |
+
args = ap.parse_args()
|
| 43 |
+
os.makedirs(args.work, exist_ok=True)
|
| 44 |
+
|
| 45 |
+
out_path = os.path.join(args.work, "eval_256.npz")
|
| 46 |
+
if os.path.exists(out_path):
|
| 47 |
+
print(f"[eval-set] already exists at {out_path}", flush=True)
|
| 48 |
+
return
|
| 49 |
+
|
| 50 |
+
ann_path = os.path.join(args.work, "captions_val2014.json")
|
| 51 |
+
if not os.path.exists(ann_path):
|
| 52 |
+
print("[eval-set] downloading annotations", flush=True)
|
| 53 |
+
z = os.path.join(args.work, "ann.zip")
|
| 54 |
+
with requests.get(ANN_URL, stream=True, timeout=120) as r:
|
| 55 |
+
with open(z, "wb") as f:
|
| 56 |
+
for chunk in r.iter_content(1 << 20):
|
| 57 |
+
f.write(chunk)
|
| 58 |
+
with zipfile.ZipFile(z) as zf:
|
| 59 |
+
with zf.open("annotations/captions_val2014.json") as src, open(ann_path, "wb") as dst:
|
| 60 |
+
dst.write(src.read())
|
| 61 |
+
os.remove(z)
|
| 62 |
+
|
| 63 |
+
ann = json.load(open(ann_path))
|
| 64 |
+
url_by_id = {im["id"]: im["coco_url"] for im in ann["images"]}
|
| 65 |
+
cap_by_id = {}
|
| 66 |
+
for a in ann["annotations"]:
|
| 67 |
+
cap_by_id.setdefault(a["image_id"], a["caption"])
|
| 68 |
+
items = [(url_by_id[i], cap_by_id[i]) for i in cap_by_id if i in url_by_id]
|
| 69 |
+
random.Random(args.seed).shuffle(items)
|
| 70 |
+
print(f"[eval-set] {len(items)} val2014 pairs available, target {args.n}", flush=True)
|
| 71 |
+
|
| 72 |
+
imgs, caps = [], []
|
| 73 |
+
pool = ThreadPoolExecutor(max_workers=args.workers)
|
| 74 |
+
idx, batch = 0, 64
|
| 75 |
+
while len(imgs) < args.n and idx < len(items):
|
| 76 |
+
chunk = items[idx:idx + batch]
|
| 77 |
+
idx += batch
|
| 78 |
+
results = [r for r in pool.map(lambda it: fetch_one(it, args.size), chunk) if r is not None]
|
| 79 |
+
for a, c in results:
|
| 80 |
+
imgs.append(a); caps.append(c)
|
| 81 |
+
if idx % (batch * 20) == 0:
|
| 82 |
+
print(f"[eval-set] {len(imgs)}/{args.n}", flush=True)
|
| 83 |
+
|
| 84 |
+
imgs = np.stack(imgs[:args.n])
|
| 85 |
+
caps = np.array(caps[:args.n], dtype=object)
|
| 86 |
+
np.savez(out_path, images=imgs, captions=caps)
|
| 87 |
+
print(f"[eval-set] DONE {imgs.shape} -> {out_path}", flush=True)
|
| 88 |
+
|
| 89 |
+
if __name__ == "__main__":
|
| 90 |
+
main()
|
config.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architecture": "latent-mmdit",
|
| 3 |
+
"objective": "rectified-flow",
|
| 4 |
+
"dit": {
|
| 5 |
+
"dim": 512,
|
| 6 |
+
"depth": 16,
|
| 7 |
+
"heads": 8,
|
| 8 |
+
"patch": 2,
|
| 9 |
+
"latent_ch": 4,
|
| 10 |
+
"latent_size": 32,
|
| 11 |
+
"mlp_hidden": 1408,
|
| 12 |
+
"t5_len": 32
|
| 13 |
+
},
|
| 14 |
+
"vae": "madebyollin/sdxl-vae-fp16-fix",
|
| 15 |
+
"text_encoders": {
|
| 16 |
+
"joint_stream": "google/flan-t5-base",
|
| 17 |
+
"global_conditioning": "openai/clip-vit-base-patch32"
|
| 18 |
+
},
|
| 19 |
+
"max_tokens": {
|
| 20 |
+
"t5": 32,
|
| 21 |
+
"clip": 40
|
| 22 |
+
},
|
| 23 |
+
"trainable_parameters": 155090448,
|
| 24 |
+
"total_parameters_incl_frozen": 411538807,
|
| 25 |
+
"sampling": {
|
| 26 |
+
"steps": 50,
|
| 27 |
+
"cfg": 3.0
|
| 28 |
+
},
|
| 29 |
+
"training": {
|
| 30 |
+
"steps": 150000,
|
| 31 |
+
"batch": 192,
|
| 32 |
+
"dataset": "undefined443/cc12m-wds-coco-recaptioned, 2986571 images",
|
| 33 |
+
"final_val_loss": 0.7982857534661889
|
| 34 |
+
},
|
| 35 |
+
"eval": {
|
| 36 |
+
"fid": 23.62,
|
| 37 |
+
"clip_score": 30.43,
|
| 38 |
+
"cfg_sweep": [
|
| 39 |
+
{"cfg": 2.0, "fid": 25.65, "clip_score": 29.65},
|
| 40 |
+
{"cfg": 3.0, "fid": 23.62, "clip_score": 30.43},
|
| 41 |
+
{"cfg": 4.0, "fid": 23.77, "clip_score": 30.81},
|
| 42 |
+
{"cfg": 5.0, "fid": 24.42, "clip_score": 31.06},
|
| 43 |
+
{"cfg": 6.0, "fid": 25.10, "clip_score": 31.12},
|
| 44 |
+
{"cfg": 7.0, "fid": 26.26, "clip_score": 31.16},
|
| 45 |
+
{"cfg": 8.0, "fid": 26.87, "clip_score": 31.17}
|
| 46 |
+
],
|
| 47 |
+
"n": 5000,
|
| 48 |
+
"dataset": "MS-COCO val2014, 256 center crop",
|
| 49 |
+
"protocol": "torchmetrics FrechetInceptionDistance + CLIPScore (openai/clip-vit-base-patch32)"
|
| 50 |
+
}
|
| 51 |
+
}
|
dit_v6.py
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
import torch.utils.checkpoint
|
| 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 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 |
+
def rope_cos_sin(freqs):
|
| 26 |
+
emb = torch.cat([freqs, freqs], dim=-1)
|
| 27 |
+
return emb.cos(), emb.sin()
|
| 28 |
+
|
| 29 |
+
def rotate_half(x):
|
| 30 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 31 |
+
return torch.cat([-x2, x1], dim=-1)
|
| 32 |
+
|
| 33 |
+
def apply_rope(x, cos, sin):
|
| 34 |
+
return x * cos + rotate_half(x) * sin
|
| 35 |
+
|
| 36 |
+
def apply_rope_2d(x, row_cos, row_sin, col_cos, col_sin):
|
| 37 |
+
x1, x2 = x.chunk(2, dim=-1)
|
| 38 |
+
x1 = apply_rope(x1, row_cos, row_sin)
|
| 39 |
+
x2 = apply_rope(x2, col_cos, col_sin)
|
| 40 |
+
return torch.cat([x1, x2], dim=-1)
|
| 41 |
+
|
| 42 |
+
class RMSNormHead(nn.Module):
|
| 43 |
+
def __init__(self, head_dim, eps=1e-6):
|
| 44 |
+
super().__init__()
|
| 45 |
+
self.weight = nn.Parameter(torch.ones(head_dim))
|
| 46 |
+
self.eps = eps
|
| 47 |
+
|
| 48 |
+
def forward(self, x):
|
| 49 |
+
n = x.pow(2).mean(-1, keepdim=True).add(self.eps).rsqrt()
|
| 50 |
+
return x * n * self.weight
|
| 51 |
+
|
| 52 |
+
class SwiGLU(nn.Module):
|
| 53 |
+
def __init__(self, dim, hidden):
|
| 54 |
+
super().__init__()
|
| 55 |
+
self.gate = nn.Linear(dim, hidden)
|
| 56 |
+
self.up = nn.Linear(dim, hidden)
|
| 57 |
+
self.down = nn.Linear(hidden, dim)
|
| 58 |
+
|
| 59 |
+
def forward(self, x):
|
| 60 |
+
return self.down(F.silu(self.gate(x)) * self.up(x))
|
| 61 |
+
|
| 62 |
+
class JointBlock(nn.Module):
|
| 63 |
+
def __init__(self, dim, heads, mlp_hidden):
|
| 64 |
+
super().__init__()
|
| 65 |
+
self.heads = heads
|
| 66 |
+
self.head_dim = dim // heads
|
| 67 |
+
self.norm1_img = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 68 |
+
self.norm1_txt = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 69 |
+
self.qkv_img = nn.Linear(dim, 3 * dim)
|
| 70 |
+
self.qkv_txt = nn.Linear(dim, 3 * dim)
|
| 71 |
+
self.qn_img = RMSNormHead(self.head_dim)
|
| 72 |
+
self.kn_img = RMSNormHead(self.head_dim)
|
| 73 |
+
self.qn_txt = RMSNormHead(self.head_dim)
|
| 74 |
+
self.kn_txt = RMSNormHead(self.head_dim)
|
| 75 |
+
self.proj_img = nn.Linear(dim, dim)
|
| 76 |
+
self.proj_txt = 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 = SwiGLU(dim, mlp_hidden)
|
| 80 |
+
self.mlp_txt = SwiGLU(dim, mlp_hidden)
|
| 81 |
+
self.ada_img = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 82 |
+
self.ada_txt = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 83 |
+
|
| 84 |
+
def forward(self, img, txt, c, rope_img, rope_txt, key_valid):
|
| 85 |
+
s1i, sc1i, g1i, s2i, sc2i, g2i = self.ada_img(c).chunk(6, dim=-1)
|
| 86 |
+
s1t, sc1t, g1t, s2t, sc2t, g2t = self.ada_txt(c).chunk(6, dim=-1)
|
| 87 |
+
|
| 88 |
+
xi = modulate(self.norm1_img(img), s1i, sc1i)
|
| 89 |
+
xt = modulate(self.norm1_txt(txt), s1t, sc1t)
|
| 90 |
+
|
| 91 |
+
B, Ni, C = xi.shape
|
| 92 |
+
Nt = xt.shape[1]
|
| 93 |
+
H, D = self.heads, self.head_dim
|
| 94 |
+
|
| 95 |
+
qi, ki, vi = self.qkv_img(xi).reshape(B, Ni, 3, H, D).permute(2, 0, 3, 1, 4)
|
| 96 |
+
qt, kt, vt = self.qkv_txt(xt).reshape(B, Nt, 3, H, D).permute(2, 0, 3, 1, 4)
|
| 97 |
+
|
| 98 |
+
qi, ki = self.qn_img(qi), self.kn_img(ki)
|
| 99 |
+
qt, kt = self.qn_txt(qt), self.kn_txt(kt)
|
| 100 |
+
|
| 101 |
+
row_cos, row_sin, col_cos, col_sin = rope_img
|
| 102 |
+
qi = apply_rope_2d(qi, row_cos, row_sin, col_cos, col_sin)
|
| 103 |
+
ki = apply_rope_2d(ki, row_cos, row_sin, col_cos, col_sin)
|
| 104 |
+
|
| 105 |
+
t_cos, t_sin = rope_txt
|
| 106 |
+
qt = apply_rope(qt, t_cos, t_sin)
|
| 107 |
+
kt = apply_rope(kt, t_cos, t_sin)
|
| 108 |
+
|
| 109 |
+
q = torch.cat([qi, qt], dim=2)
|
| 110 |
+
k = torch.cat([ki, kt], dim=2)
|
| 111 |
+
v = torch.cat([vi, vt], dim=2)
|
| 112 |
+
|
| 113 |
+
mask = key_valid[:, None, None, :]
|
| 114 |
+
o = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 115 |
+
o = o.transpose(1, 2).reshape(B, Ni + Nt, C)
|
| 116 |
+
oi, ot = o[:, :Ni], o[:, Ni:]
|
| 117 |
+
|
| 118 |
+
img = img + g1i.unsqueeze(1) * self.proj_img(oi)
|
| 119 |
+
txt = txt + g1t.unsqueeze(1) * self.proj_txt(ot)
|
| 120 |
+
|
| 121 |
+
img = img + g2i.unsqueeze(1) * self.mlp_img(modulate(self.norm2_img(img), s2i, sc2i))
|
| 122 |
+
txt = txt + g2t.unsqueeze(1) * self.mlp_txt(modulate(self.norm2_txt(txt), s2t, sc2t))
|
| 123 |
+
return img, txt
|
| 124 |
+
|
| 125 |
+
class MMDiT(nn.Module):
|
| 126 |
+
def __init__(self, latent_ch=4, latent_size=32, patch=2, dim=512, depth=16, heads=8,
|
| 127 |
+
t5_dim=768, clip_dim=512, t5_len=32, mlp_hidden=1408,
|
| 128 |
+
repa_dim=384, repa_layer=8):
|
| 129 |
+
super().__init__()
|
| 130 |
+
self.latent_ch = latent_ch
|
| 131 |
+
self.latent_size = latent_size
|
| 132 |
+
self.patch = patch
|
| 133 |
+
self.grid = latent_size // patch
|
| 134 |
+
self.patch_dim = latent_ch * patch * patch
|
| 135 |
+
self.dim = dim
|
| 136 |
+
self.depth = depth
|
| 137 |
+
self.heads = heads
|
| 138 |
+
self.head_dim = dim // heads
|
| 139 |
+
self.t5_len = t5_len
|
| 140 |
+
self.repa_layer = repa_layer
|
| 141 |
+
|
| 142 |
+
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 143 |
+
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 144 |
+
self.clip_proj = nn.Linear(clip_dim, dim)
|
| 145 |
+
self.t5_proj = nn.Linear(t5_dim, dim)
|
| 146 |
+
|
| 147 |
+
self.blocks = nn.ModuleList([JointBlock(dim, heads, mlp_hidden) for _ in range(depth)])
|
| 148 |
+
|
| 149 |
+
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 150 |
+
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 151 |
+
self.head = nn.Linear(dim, self.patch_dim)
|
| 152 |
+
|
| 153 |
+
self.repa_head = nn.Sequential(nn.Linear(dim, dim), nn.GELU(approximate="tanh"), nn.Linear(dim, repa_dim))
|
| 154 |
+
|
| 155 |
+
hd2 = self.head_dim // 2
|
| 156 |
+
rows = torch.arange(self.grid).repeat_interleave(self.grid)
|
| 157 |
+
cols = torch.arange(self.grid).repeat(self.grid)
|
| 158 |
+
row_cos, row_sin = rope_cos_sin(rope_freqs(rows, hd2))
|
| 159 |
+
col_cos, col_sin = rope_cos_sin(rope_freqs(cols, hd2))
|
| 160 |
+
self.register_buffer("row_cos", row_cos, persistent=False)
|
| 161 |
+
self.register_buffer("row_sin", row_sin, persistent=False)
|
| 162 |
+
self.register_buffer("col_cos", col_cos, persistent=False)
|
| 163 |
+
self.register_buffer("col_sin", col_sin, persistent=False)
|
| 164 |
+
t_cos, t_sin = rope_cos_sin(rope_freqs(torch.arange(t5_len), self.head_dim))
|
| 165 |
+
self.register_buffer("t_cos", t_cos, persistent=False)
|
| 166 |
+
self.register_buffer("t_sin", t_sin, persistent=False)
|
| 167 |
+
|
| 168 |
+
self._init()
|
| 169 |
+
|
| 170 |
+
def _init(self):
|
| 171 |
+
for m in self.modules():
|
| 172 |
+
if isinstance(m, nn.Linear):
|
| 173 |
+
nn.init.xavier_uniform_(m.weight)
|
| 174 |
+
if m.bias is not None:
|
| 175 |
+
nn.init.zeros_(m.bias)
|
| 176 |
+
for b in self.blocks:
|
| 177 |
+
nn.init.zeros_(b.ada_img[-1].weight); nn.init.zeros_(b.ada_img[-1].bias)
|
| 178 |
+
nn.init.zeros_(b.ada_txt[-1].weight); nn.init.zeros_(b.ada_txt[-1].bias)
|
| 179 |
+
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 180 |
+
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 181 |
+
|
| 182 |
+
def patchify(self, x):
|
| 183 |
+
B, C, H, W = x.shape
|
| 184 |
+
p = self.patch
|
| 185 |
+
x = x.reshape(B, C, H // p, p, W // p, p)
|
| 186 |
+
x = x.permute(0, 2, 4, 1, 3, 5).reshape(B, (H // p) * (W // p), C * p * p)
|
| 187 |
+
return x
|
| 188 |
+
|
| 189 |
+
def unpatchify(self, x):
|
| 190 |
+
B, N, _ = x.shape
|
| 191 |
+
p = self.patch
|
| 192 |
+
g = self.grid
|
| 193 |
+
C = self.latent_ch
|
| 194 |
+
x = x.reshape(B, g, g, C, p, p).permute(0, 3, 1, 4, 2, 5)
|
| 195 |
+
return x.reshape(B, C, g * p, g * p)
|
| 196 |
+
|
| 197 |
+
def forward(self, x, t, t5_seq, t5_mask, clip_pool, return_repa=False, use_checkpoint=False):
|
| 198 |
+
B = x.shape[0]
|
| 199 |
+
img = self.x_embed(self.patchify(x))
|
| 200 |
+
txt = self.t5_proj(t5_seq)
|
| 201 |
+
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.clip_proj(clip_pool)
|
| 202 |
+
|
| 203 |
+
key_valid = torch.cat([
|
| 204 |
+
torch.ones(B, img.shape[1], dtype=torch.bool, device=x.device),
|
| 205 |
+
t5_mask.bool(),
|
| 206 |
+
], dim=1)
|
| 207 |
+
|
| 208 |
+
rope_img = (self.row_cos, self.row_sin, self.col_cos, self.col_sin)
|
| 209 |
+
rope_txt = (self.t_cos, self.t_sin)
|
| 210 |
+
|
| 211 |
+
repa_hidden = None
|
| 212 |
+
for i, blk in enumerate(self.blocks):
|
| 213 |
+
if use_checkpoint and self.training:
|
| 214 |
+
img, txt = torch.utils.checkpoint.checkpoint(
|
| 215 |
+
blk, img, txt, c, rope_img, rope_txt, key_valid, use_reentrant=False)
|
| 216 |
+
else:
|
| 217 |
+
img, txt = blk(img, txt, c, rope_img, rope_txt, key_valid)
|
| 218 |
+
if return_repa and i == self.repa_layer:
|
| 219 |
+
repa_hidden = img
|
| 220 |
+
|
| 221 |
+
shift, scale = self.ada_out(c).chunk(2, dim=-1)
|
| 222 |
+
img = modulate(self.norm_out(img), shift, scale)
|
| 223 |
+
out = self.unpatchify(self.head(img))
|
| 224 |
+
|
| 225 |
+
if return_repa:
|
| 226 |
+
return out, self.repa_head(repa_hidden)
|
| 227 |
+
return out
|
| 228 |
+
|
| 229 |
+
def num_params(self):
|
| 230 |
+
return sum(p.numel() for p in self.parameters())
|
| 231 |
+
|
| 232 |
+
def num_backbone_params(self):
|
| 233 |
+
return sum(p.numel() for n, p in self.named_parameters() if not n.startswith("repa_head"))
|
eval_v6.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
import torch
|
| 9 |
+
from PIL import Image
|
| 10 |
+
from diffusers import AutoencoderKL
|
| 11 |
+
from transformers import CLIPModel, CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
| 12 |
+
|
| 13 |
+
from dit_v6 import MMDiT
|
| 14 |
+
|
| 15 |
+
def patch_clip_score():
|
| 16 |
+
def get_image_features(self, pixel_values, **kw):
|
| 17 |
+
pooled = self.vision_model(pixel_values=pixel_values).pooler_output
|
| 18 |
+
return self.visual_projection(pooled)
|
| 19 |
+
|
| 20 |
+
def get_text_features(self, input_ids=None, attention_mask=None, **kw):
|
| 21 |
+
pooled = self.text_model(input_ids=input_ids, attention_mask=attention_mask).pooler_output
|
| 22 |
+
return self.text_projection(pooled)
|
| 23 |
+
|
| 24 |
+
CLIPModel.get_image_features = get_image_features
|
| 25 |
+
CLIPModel.get_text_features = get_text_features
|
| 26 |
+
|
| 27 |
+
@torch.no_grad()
|
| 28 |
+
def sample(model, seq, mask, pool, null_seq, null_mask, null_pool, steps, cfg, dev):
|
| 29 |
+
B = seq.shape[0]
|
| 30 |
+
x = torch.randn(B, 4, 32, 32, device=dev)
|
| 31 |
+
ns, nm, npo = null_seq.expand(B, -1, -1), null_mask.expand(B, -1), null_pool.expand(B, -1)
|
| 32 |
+
dt = 1.0 / steps
|
| 33 |
+
for i in range(steps):
|
| 34 |
+
t = torch.full((B,), i * dt, device=dev)
|
| 35 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 36 |
+
vc = model(x, t, seq, mask, pool)
|
| 37 |
+
vu = model(x, t, ns, nm, npo)
|
| 38 |
+
x = x + (vu + cfg * (vc - vu)).float() * dt
|
| 39 |
+
return x
|
| 40 |
+
|
| 41 |
+
@torch.no_grad()
|
| 42 |
+
def main():
|
| 43 |
+
ap = argparse.ArgumentParser()
|
| 44 |
+
ap.add_argument("--work", default="/root/v6cache")
|
| 45 |
+
ap.add_argument("--ckpt", default="/root/runs/pm6/best.pt")
|
| 46 |
+
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
|
| 47 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 48 |
+
ap.add_argument("--t5", default="google/flan-t5-base")
|
| 49 |
+
ap.add_argument("--n", type=int, default=5000)
|
| 50 |
+
ap.add_argument("--batch", type=int, default=50)
|
| 51 |
+
ap.add_argument("--steps", type=int, default=50)
|
| 52 |
+
ap.add_argument("--cfg", type=float, nargs="+", default=[5.0])
|
| 53 |
+
ap.add_argument("--t5-len", type=int, default=32)
|
| 54 |
+
ap.add_argument("--clip-len", type=int, default=40)
|
| 55 |
+
ap.add_argument("--out", default="/root/runs/pm6/eval_results.jsonl")
|
| 56 |
+
ap.add_argument("--preview", default="")
|
| 57 |
+
args = ap.parse_args()
|
| 58 |
+
dev = "cuda"
|
| 59 |
+
|
| 60 |
+
ck = torch.load(args.ckpt, map_location=dev)
|
| 61 |
+
c = ck["cfg"]
|
| 62 |
+
model = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"],
|
| 63 |
+
t5_len=c["t5_len"]).to(dev).eval()
|
| 64 |
+
model.load_state_dict(ck["ema"])
|
| 65 |
+
print(f"[eval] loaded {args.ckpt} step {ck['step']} params {model.num_params():,}", flush=True)
|
| 66 |
+
|
| 67 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 68 |
+
vae_scale = vae.config.scaling_factor
|
| 69 |
+
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
|
| 70 |
+
t5 = T5EncoderModel.from_pretrained(args.t5).to(dev).eval()
|
| 71 |
+
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 72 |
+
clip_txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 73 |
+
|
| 74 |
+
def enc(strings):
|
| 75 |
+
te = t5_tok(strings, padding="max_length", max_length=args.t5_len, truncation=True, return_tensors="pt").to(dev)
|
| 76 |
+
seq = t5(input_ids=te["input_ids"], attention_mask=te["attention_mask"]).last_hidden_state.float()
|
| 77 |
+
ce = clip_tok(strings, padding="max_length", max_length=args.clip_len, truncation=True,
|
| 78 |
+
return_tensors="pt").to(dev)
|
| 79 |
+
pool = clip_txt(input_ids=ce["input_ids"]).pooler_output.float()
|
| 80 |
+
return seq, te["attention_mask"].float(), pool
|
| 81 |
+
|
| 82 |
+
null_seq, null_mask, null_pool = enc([""])
|
| 83 |
+
|
| 84 |
+
d = np.load(os.path.join(args.work, "eval_256.npz"), allow_pickle=True)
|
| 85 |
+
real = d["images"][:args.n]
|
| 86 |
+
caps = [str(x) for x in d["captions"][:args.n]]
|
| 87 |
+
n = len(caps)
|
| 88 |
+
|
| 89 |
+
patch_clip_score()
|
| 90 |
+
from torchmetrics.image.fid import FrechetInceptionDistance
|
| 91 |
+
from torchmetrics.multimodal.clip_score import CLIPScore
|
| 92 |
+
|
| 93 |
+
results = []
|
| 94 |
+
for cfg_val in args.cfg:
|
| 95 |
+
fid = FrechetInceptionDistance(feature=2048, normalize=True).to(dev)
|
| 96 |
+
clip_metric = CLIPScore(model_name_or_path=args.clip).to(dev)
|
| 97 |
+
for i in range(0, n, args.batch):
|
| 98 |
+
rb = torch.from_numpy(real[i:i + args.batch].astype(np.float32) / 255.0).permute(0, 3, 1, 2).to(dev)
|
| 99 |
+
fid.update(rb, real=True)
|
| 100 |
+
|
| 101 |
+
preview_imgs = []
|
| 102 |
+
for i in range(0, n, args.batch):
|
| 103 |
+
cb = caps[i:i + args.batch]
|
| 104 |
+
seq, mask, pool = enc(cb)
|
| 105 |
+
z = sample(model, seq, mask, pool, null_seq, null_mask, null_pool, args.steps, cfg_val, dev)
|
| 106 |
+
img = vae.decode((z / vae_scale).half()).sample.float()
|
| 107 |
+
img = (img.clamp(-1, 1) + 1) / 2
|
| 108 |
+
fid.update(img, real=False)
|
| 109 |
+
clip_metric.update((img * 255).to(torch.uint8), cb)
|
| 110 |
+
if args.preview and cfg_val == args.cfg[0] and len(preview_imgs) < 12:
|
| 111 |
+
for j in range(min(len(cb), 12 - len(preview_imgs))):
|
| 112 |
+
a = (img[j].permute(1, 2, 0).cpu().numpy() * 255).astype(np.uint8)
|
| 113 |
+
preview_imgs.append((a, cb[j]))
|
| 114 |
+
if i % (args.batch * 10) == 0:
|
| 115 |
+
print(f"[eval] cfg={cfg_val} generated {i}/{n}", flush=True)
|
| 116 |
+
|
| 117 |
+
fid_v = float(fid.compute().item())
|
| 118 |
+
clip_v = float(clip_metric.compute().item())
|
| 119 |
+
res = {"n": n, "fid": round(fid_v, 2), "clip_score": round(clip_v, 2), "steps": args.steps,
|
| 120 |
+
"cfg": cfg_val, "render_res": 256, "fid_size": 256, "clip_model": args.clip, "step": ck["step"]}
|
| 121 |
+
results.append(res)
|
| 122 |
+
print(f"[eval] cfg={cfg_val} FID={fid_v:.2f} CLIP={clip_v:.2f} (n={n}, steps={args.steps})", flush=True)
|
| 123 |
+
|
| 124 |
+
with open(args.out, "a") as f:
|
| 125 |
+
f.write(json.dumps(res) + "\n")
|
| 126 |
+
|
| 127 |
+
if args.preview and cfg_val == args.cfg[0] and preview_imgs:
|
| 128 |
+
cell, pad = 256, 8
|
| 129 |
+
cols = 4
|
| 130 |
+
rows = (len(preview_imgs) + cols - 1) // cols
|
| 131 |
+
sheet = Image.new("RGB", (cols * cell + (cols + 1) * pad, rows * cell + (rows + 1) * pad), (245, 246, 248))
|
| 132 |
+
for k, (a, cap) in enumerate(preview_imgs):
|
| 133 |
+
r, cc = divmod(k, cols)
|
| 134 |
+
sheet.paste(Image.fromarray(a), (pad + cc * (cell + pad), pad + r * (cell + pad)))
|
| 135 |
+
sheet.save(args.preview)
|
| 136 |
+
print(f"[eval] wrote preview {args.preview}", flush=True)
|
| 137 |
+
|
| 138 |
+
print(json.dumps(results, indent=2))
|
| 139 |
+
|
| 140 |
+
if __name__ == "__main__":
|
| 141 |
+
main()
|
examples.png
ADDED
|
|
Git LFS Details
|
main.py
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
import torch
|
| 9 |
+
from PIL import Image
|
| 10 |
+
from safetensors.torch import load_file
|
| 11 |
+
from diffusers import AutoencoderKL
|
| 12 |
+
from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
| 13 |
+
|
| 14 |
+
from dit_v6 import MMDiT
|
| 15 |
+
|
| 16 |
+
@torch.no_grad()
|
| 17 |
+
def sample(model, seq, mask, pool, null_seq, null_mask, null_pool, steps, cfg, dev):
|
| 18 |
+
B = seq.shape[0]
|
| 19 |
+
x = torch.randn(B, 4, 32, 32, device=dev)
|
| 20 |
+
ns, nm, npo = null_seq.expand(B, -1, -1), null_mask.expand(B, -1), null_pool.expand(B, -1)
|
| 21 |
+
dt = 1.0 / steps
|
| 22 |
+
for i in range(steps):
|
| 23 |
+
t = torch.full((B,), i * dt, device=dev)
|
| 24 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 25 |
+
vc = model(x, t, seq, mask, pool)
|
| 26 |
+
vu = model(x, t, ns, nm, npo)
|
| 27 |
+
x = x + (vu + cfg * (vc - vu)).float() * dt
|
| 28 |
+
return x
|
| 29 |
+
|
| 30 |
+
@torch.no_grad()
|
| 31 |
+
def main():
|
| 32 |
+
ap = argparse.ArgumentParser()
|
| 33 |
+
ap.add_argument("prompt")
|
| 34 |
+
ap.add_argument("--out", default="out.png")
|
| 35 |
+
ap.add_argument("--cfg", type=float, default=5.0)
|
| 36 |
+
ap.add_argument("--steps", type=int, default=50)
|
| 37 |
+
ap.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
|
| 38 |
+
ap.add_argument("--safetensors", default="model.safetensors")
|
| 39 |
+
ap.add_argument("--config", default="config.json")
|
| 40 |
+
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
|
| 41 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 42 |
+
ap.add_argument("--t5", default="google/flan-t5-base")
|
| 43 |
+
ap.add_argument("--t5-len", type=int, default=32)
|
| 44 |
+
ap.add_argument("--clip-len", type=int, default=40)
|
| 45 |
+
args = ap.parse_args()
|
| 46 |
+
dev = args.device
|
| 47 |
+
|
| 48 |
+
d = json.load(open(args.config))["dit"] if os.path.exists(args.config) else \
|
| 49 |
+
{"dim": 512, "depth": 16, "heads": 8, "mlp_hidden": 1408, "t5_len": 32}
|
| 50 |
+
model = MMDiT(dim=d["dim"], depth=d["depth"], heads=d["heads"], mlp_hidden=d["mlp_hidden"],
|
| 51 |
+
t5_len=d["t5_len"]).to(dev).eval()
|
| 52 |
+
model.load_state_dict(load_file(args.safetensors))
|
| 53 |
+
|
| 54 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 55 |
+
vae_scale = vae.config.scaling_factor
|
| 56 |
+
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
|
| 57 |
+
t5 = T5EncoderModel.from_pretrained(args.t5).to(dev).eval()
|
| 58 |
+
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 59 |
+
clip_txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 60 |
+
|
| 61 |
+
def enc(strings):
|
| 62 |
+
te = t5_tok(strings, padding="max_length", max_length=args.t5_len, truncation=True,
|
| 63 |
+
return_tensors="pt").to(dev)
|
| 64 |
+
seq = t5(input_ids=te["input_ids"], attention_mask=te["attention_mask"]).last_hidden_state.float()
|
| 65 |
+
ce = clip_tok(strings, padding="max_length", max_length=args.clip_len, truncation=True,
|
| 66 |
+
return_tensors="pt").to(dev)
|
| 67 |
+
pool = clip_txt(input_ids=ce["input_ids"]).pooler_output.float()
|
| 68 |
+
return seq, te["attention_mask"].float(), pool
|
| 69 |
+
|
| 70 |
+
seq, mask, pool = enc([args.prompt])
|
| 71 |
+
null_seq, null_mask, null_pool = enc([""])
|
| 72 |
+
z = sample(model, seq, mask, pool, null_seq, null_mask, null_pool, args.steps, args.cfg, dev)
|
| 73 |
+
img = vae.decode((z / vae_scale).half()).sample.float()
|
| 74 |
+
img = ((img.clamp(-1, 1) + 1) / 2)[0].permute(1, 2, 0).cpu().numpy()
|
| 75 |
+
Image.fromarray((img * 255).round().astype(np.uint8)).save(args.out)
|
| 76 |
+
print(f'[main] "{args.prompt}" -> {args.out} (cfg {args.cfg}, {args.steps} steps)')
|
| 77 |
+
|
| 78 |
+
if __name__ == "__main__":
|
| 79 |
+
main()
|
model.png
ADDED
|
|
Git LFS Details
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b23bb35fdb7da8a17ddd9346f5b7434be874abf7f4ff40bac38d2e5c81774444
|
| 3 |
+
size 620406232
|
model_png.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cfg": {"dim": 512, "depth": 16, "heads": 8, "mlp_hidden": 1408, "t5_len": 32}, "params": [{"name": "x_embed.weight", "shape": [512, 16], "numel": 8192}, {"name": "x_embed.bias", "shape": [512], "numel": 512}, {"name": "t_mlp.0.weight", "shape": [512, 512], "numel": 262144}, {"name": "t_mlp.0.bias", "shape": [512], "numel": 512}, {"name": "t_mlp.2.weight", "shape": [512, 512], "numel": 262144}, {"name": "t_mlp.2.bias", "shape": [512], "numel": 512}, {"name": "clip_proj.weight", "shape": [512, 512], "numel": 262144}, {"name": "clip_proj.bias", "shape": [512], "numel": 512}, {"name": "t5_proj.weight", "shape": [512, 768], "numel": 393216}, {"name": "t5_proj.bias", "shape": [512], "numel": 512}, {"name": "blocks.0.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.0.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.0.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.0.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.0.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.0.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.0.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.0.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.0.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.0.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.0.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.0.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.0.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.0.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.0.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.0.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.0.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.0.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.0.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.0.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.0.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.0.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.0.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.0.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.0.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.0.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.0.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.0.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.1.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.1.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.1.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.1.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.1.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.1.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.1.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.1.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.1.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.1.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.1.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.1.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.1.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.1.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.1.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.1.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.1.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.1.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.1.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.1.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.1.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.1.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.1.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.1.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.1.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.1.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.1.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.1.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.2.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.2.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.2.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.2.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.2.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.2.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.2.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.2.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.2.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.2.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.2.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.2.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.2.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.2.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.2.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.2.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.2.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.2.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.2.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.2.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.2.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.2.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.2.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.2.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.2.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.2.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.2.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.2.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.3.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.3.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.3.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.3.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.3.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.3.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.3.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.3.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.3.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.3.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.3.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.3.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.3.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.3.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.3.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.3.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.3.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.3.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.3.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.3.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.3.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.3.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.3.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.3.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.3.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.3.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.3.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.3.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.4.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.4.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.4.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.4.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.4.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.4.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.4.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.4.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.4.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.4.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.4.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.4.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.4.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.4.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.4.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.4.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.4.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.4.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.4.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.4.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.4.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.4.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.4.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.4.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.4.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.4.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.4.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.4.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.5.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.5.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.5.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.5.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.5.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.5.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.5.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.5.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.5.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.5.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.5.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.5.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.5.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.5.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.5.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.5.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.5.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.5.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.5.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.5.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.5.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.5.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.5.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.5.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.5.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.5.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.5.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.5.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.6.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.6.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.6.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.6.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.6.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.6.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.6.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.6.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.6.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.6.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.6.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.6.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.6.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.6.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.6.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.6.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.6.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.6.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.6.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.6.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.6.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.6.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.6.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.6.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.6.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.6.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.6.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.6.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.7.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.7.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.7.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.7.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.7.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.7.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.7.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.7.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.7.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.7.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.7.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.7.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.7.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.7.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.7.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.7.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.7.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.7.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.7.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.7.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.7.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.7.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.7.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.7.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.7.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.7.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.7.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.7.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.8.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.8.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.8.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.8.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.8.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.8.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.8.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.8.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.8.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.8.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.8.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.8.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.8.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.8.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.8.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.8.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.8.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.8.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.8.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.8.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.8.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.8.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.8.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.8.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.8.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.8.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.8.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.8.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.9.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.9.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.9.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.9.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.9.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.9.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.9.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.9.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.9.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.9.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.9.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.9.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.9.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.9.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.9.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.9.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.9.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.9.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.9.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.9.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.9.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.9.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.9.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.9.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.9.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.9.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.9.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.9.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.10.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.10.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.10.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.10.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.10.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.10.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.10.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.10.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.10.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.10.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.10.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.10.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.10.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.10.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.10.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.10.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.10.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.10.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.10.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.10.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.10.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.10.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.10.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.10.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.10.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.10.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.10.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.10.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.11.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.11.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.11.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.11.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.11.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.11.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.11.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.11.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.11.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.11.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.11.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.11.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.11.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.11.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.11.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.11.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.11.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.11.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.11.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.11.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.11.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.11.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.11.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.11.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.11.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.11.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.11.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.11.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.12.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.12.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.12.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.12.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.12.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.12.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.12.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.12.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.12.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.12.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.12.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.12.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.12.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.12.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.12.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.12.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.12.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.12.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.12.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.12.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.12.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.12.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.12.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.12.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.12.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.12.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.12.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.12.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.13.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.13.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.13.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.13.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.13.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.13.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.13.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.13.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.13.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.13.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.13.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.13.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.13.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.13.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.13.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.13.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.13.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.13.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.13.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.13.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.13.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.13.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.13.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.13.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.13.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.13.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.13.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.13.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.14.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.14.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.14.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.14.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.14.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.14.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.14.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.14.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.14.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.14.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.14.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.14.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.14.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.14.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.14.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.14.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.14.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.14.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.14.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.14.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.14.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.14.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.14.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.14.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.14.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.14.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.14.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.14.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.15.qkv_img.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.15.qkv_img.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.15.qkv_txt.weight", "shape": [1536, 512], "numel": 786432}, {"name": "blocks.15.qkv_txt.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.15.qn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.15.kn_img.weight", "shape": [64], "numel": 64}, {"name": "blocks.15.qn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.15.kn_txt.weight", "shape": [64], "numel": 64}, {"name": "blocks.15.proj_img.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.15.proj_img.bias", "shape": [512], "numel": 512}, {"name": "blocks.15.proj_txt.weight", "shape": [512, 512], "numel": 262144}, {"name": "blocks.15.proj_txt.bias", "shape": [512], "numel": 512}, {"name": "blocks.15.mlp_img.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.15.mlp_img.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.15.mlp_img.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.15.mlp_img.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.15.mlp_img.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.15.mlp_img.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.15.mlp_txt.gate.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.15.mlp_txt.gate.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.15.mlp_txt.up.weight", "shape": [1408, 512], "numel": 720896}, {"name": "blocks.15.mlp_txt.up.bias", "shape": [1408], "numel": 1408}, {"name": "blocks.15.mlp_txt.down.weight", "shape": [512, 1408], "numel": 720896}, {"name": "blocks.15.mlp_txt.down.bias", "shape": [512], "numel": 512}, {"name": "blocks.15.ada_img.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.15.ada_img.1.bias", "shape": [3072], "numel": 3072}, {"name": "blocks.15.ada_txt.1.weight", "shape": [3072, 512], "numel": 1572864}, {"name": "blocks.15.ada_txt.1.bias", "shape": [3072], "numel": 3072}, {"name": "ada_out.1.weight", "shape": [1024, 512], "numel": 524288}, {"name": "ada_out.1.bias", "shape": [1024], "numel": 1024}, {"name": "head.weight", "shape": [16, 512], "numel": 8192}, {"name": "head.bias", "shape": [16], "numel": 16}], "total_parameters": 155090448, "side": 12454, "dtype": "float16", "channels": "R=hi,G=lo,B=unused"}
|
pixelmodel-v6-loss.png
ADDED
|
|
pixelmodel-v6-params.png
ADDED
|
|
pixelmodel-v6-val.png
ADDED
|
|
png_codec.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import argparse, json, math
|
| 3 |
+
import numpy as np
|
| 4 |
+
import torch
|
| 5 |
+
from PIL import Image
|
| 6 |
+
from dit_v6 import MMDiT
|
| 7 |
+
|
| 8 |
+
def encode(ckpt, png_path, cfg_path, which="ema"):
|
| 9 |
+
ck = torch.load(ckpt, map_location="cpu")
|
| 10 |
+
c = ck["cfg"]
|
| 11 |
+
model = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"], t5_len=c["t5_len"])
|
| 12 |
+
model.load_state_dict(ck[which])
|
| 13 |
+
parts, manifest = [], []
|
| 14 |
+
for name, p in model.named_parameters():
|
| 15 |
+
a = p.detach().to(torch.float16).contiguous().view(-1).numpy()
|
| 16 |
+
parts.append(a)
|
| 17 |
+
manifest.append({"name": name, "shape": list(p.shape), "numel": int(a.size)})
|
| 18 |
+
flat = np.concatenate(parts)
|
| 19 |
+
N = flat.size
|
| 20 |
+
side = math.ceil(math.sqrt(N))
|
| 21 |
+
u16 = flat.view(np.uint16)
|
| 22 |
+
img = np.zeros((side * side, 3), dtype=np.uint8)
|
| 23 |
+
img[:N, 0] = (u16 >> 8).astype(np.uint8)
|
| 24 |
+
img[:N, 1] = (u16 & 0xFF).astype(np.uint8)
|
| 25 |
+
Image.fromarray(img.reshape(side, side, 3), "RGB").save(png_path)
|
| 26 |
+
total = sum(m["numel"] for m in manifest)
|
| 27 |
+
with open(cfg_path, "w") as f:
|
| 28 |
+
json.dump({"cfg": c, "params": manifest, "total_parameters": total,
|
| 29 |
+
"side": side, "dtype": "float16", "channels": "R=hi,G=lo,B=unused"}, f)
|
| 30 |
+
import os
|
| 31 |
+
mb = os.path.getsize(png_path) / 1e6
|
| 32 |
+
print(f"[png] encoded {total:,} params -> {side}x{side} PNG ({mb:.1f} MB)", flush=True)
|
| 33 |
+
return total, side
|
| 34 |
+
|
| 35 |
+
def load_model_png(png_path, cfg_path, device="cpu"):
|
| 36 |
+
meta = json.load(open(cfg_path))
|
| 37 |
+
c = meta["cfg"]
|
| 38 |
+
model = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"], t5_len=c["t5_len"])
|
| 39 |
+
arr = np.asarray(Image.open(png_path).convert("RGB")).reshape(-1, 3)
|
| 40 |
+
total = meta["total_parameters"]
|
| 41 |
+
hi = arr[:total, 0].astype(np.uint16)
|
| 42 |
+
lo = arr[:total, 1].astype(np.uint16)
|
| 43 |
+
flat = ((hi << 8) | lo).astype(np.uint16).view(np.float16)
|
| 44 |
+
sd = dict(model.named_parameters())
|
| 45 |
+
off = 0
|
| 46 |
+
with torch.no_grad():
|
| 47 |
+
for m in meta["params"]:
|
| 48 |
+
n = m["numel"]
|
| 49 |
+
chunk = flat[off:off + n].astype(np.float16)
|
| 50 |
+
t = torch.from_numpy(chunk.copy()).view(*m["shape"]).to(torch.float32)
|
| 51 |
+
sd[m["name"]].copy_(t)
|
| 52 |
+
off += n
|
| 53 |
+
return model.to(device).eval()
|
| 54 |
+
|
| 55 |
+
def decode_and_verify(png_path, cfg_path, ckpt=None, which="ema"):
|
| 56 |
+
model = load_model_png(png_path, cfg_path)
|
| 57 |
+
print(f"[png] decoded -> MMDiT with {sum(p.numel() for p in model.parameters()):,} params", flush=True)
|
| 58 |
+
if ckpt:
|
| 59 |
+
ck = torch.load(ckpt, map_location="cpu")
|
| 60 |
+
c = ck["cfg"]
|
| 61 |
+
ref = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"], t5_len=c["t5_len"])
|
| 62 |
+
ref.load_state_dict(ck[which])
|
| 63 |
+
maxdiff = 0.0
|
| 64 |
+
for (n1, p1), (n2, p2) in zip(model.named_parameters(), ref.named_parameters()):
|
| 65 |
+
maxdiff = max(maxdiff, (p1.float() - p2.half().float()).abs().max().item())
|
| 66 |
+
print(f"[png] max |decoded - original(fp16)| = {maxdiff:.2e} (0 == lossless)", flush=True)
|
| 67 |
+
return model
|
| 68 |
+
|
| 69 |
+
if __name__ == "__main__":
|
| 70 |
+
ap = argparse.ArgumentParser()
|
| 71 |
+
ap.add_argument("mode", choices=["encode", "decode"])
|
| 72 |
+
ap.add_argument("--ckpt", default="ckpt/final.pt")
|
| 73 |
+
ap.add_argument("--png", default="model.png")
|
| 74 |
+
ap.add_argument("--config", default="model_png.json")
|
| 75 |
+
ap.add_argument("--which", default="ema")
|
| 76 |
+
args = ap.parse_args()
|
| 77 |
+
if args.mode == "encode":
|
| 78 |
+
encode(args.ckpt, args.png, args.config, args.which)
|
| 79 |
+
else:
|
| 80 |
+
decode_and_verify(args.png, args.config, args.ckpt, args.which)
|
prep_v6.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import io
|
| 5 |
+
import os
|
| 6 |
+
import tarfile
|
| 7 |
+
import time
|
| 8 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 9 |
+
|
| 10 |
+
import numpy as np
|
| 11 |
+
import torch
|
| 12 |
+
from PIL import Image
|
| 13 |
+
from diffusers import AutoencoderKL
|
| 14 |
+
from transformers import CLIPTokenizer, T5TokenizerFast
|
| 15 |
+
from huggingface_hub import hf_hub_download
|
| 16 |
+
|
| 17 |
+
REPO = "undefined443/cc12m-wds-coco-recaptioned"
|
| 18 |
+
|
| 19 |
+
def csr(img, size):
|
| 20 |
+
img = img.convert("RGB")
|
| 21 |
+
w, h = img.size
|
| 22 |
+
s = min(w, h)
|
| 23 |
+
l, t = (w - s) // 2, (h - s) // 2
|
| 24 |
+
return np.asarray(img.crop((l, t, l + s, t + s)).resize((size, size), Image.BICUBIC), dtype=np.uint8)
|
| 25 |
+
|
| 26 |
+
def load_shard_items(tar_path, size):
|
| 27 |
+
t = tarfile.open(tar_path)
|
| 28 |
+
raw = {}
|
| 29 |
+
for m in t.getmembers():
|
| 30 |
+
if not m.isfile():
|
| 31 |
+
continue
|
| 32 |
+
key, ext = m.name.rsplit(".", 1)
|
| 33 |
+
raw.setdefault(key, {})[ext] = t.extractfile(m).read()
|
| 34 |
+
t.close()
|
| 35 |
+
|
| 36 |
+
def proc(kv):
|
| 37 |
+
_, d = kv
|
| 38 |
+
if "jpg" not in d or "txt" not in d:
|
| 39 |
+
return None
|
| 40 |
+
try:
|
| 41 |
+
arr = csr(Image.open(io.BytesIO(d["jpg"])), size)
|
| 42 |
+
cap = d["txt"].decode("utf-8", "ignore").strip()
|
| 43 |
+
if not cap:
|
| 44 |
+
return None
|
| 45 |
+
return arr, cap
|
| 46 |
+
except Exception:
|
| 47 |
+
return None
|
| 48 |
+
|
| 49 |
+
results = []
|
| 50 |
+
with ThreadPoolExecutor(max_workers=32) as pool:
|
| 51 |
+
for r in pool.map(proc, raw.items()):
|
| 52 |
+
if r is not None:
|
| 53 |
+
results.append(r)
|
| 54 |
+
return results
|
| 55 |
+
|
| 56 |
+
@torch.no_grad()
|
| 57 |
+
def main():
|
| 58 |
+
ap = argparse.ArgumentParser()
|
| 59 |
+
ap.add_argument("--out", default="/root/v6cache/shards")
|
| 60 |
+
ap.add_argument("--tmp", default="/root/v6cache/tars")
|
| 61 |
+
ap.add_argument("--size", type=int, default=256)
|
| 62 |
+
ap.add_argument("--t5-len", type=int, default=32)
|
| 63 |
+
ap.add_argument("--clip-len", type=int, default=40)
|
| 64 |
+
ap.add_argument("--batch", type=int, default=128)
|
| 65 |
+
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
|
| 66 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 67 |
+
ap.add_argument("--t5", default="google/flan-t5-base")
|
| 68 |
+
ap.add_argument("--start", type=int, default=0)
|
| 69 |
+
ap.add_argument("--end", type=int, default=598)
|
| 70 |
+
ap.add_argument("--prefetch", type=int, default=2)
|
| 71 |
+
args = ap.parse_args()
|
| 72 |
+
os.makedirs(args.out, exist_ok=True)
|
| 73 |
+
os.makedirs(args.tmp, exist_ok=True)
|
| 74 |
+
dev = "cuda"
|
| 75 |
+
|
| 76 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 77 |
+
scale = vae.config.scaling_factor
|
| 78 |
+
print(f"[prep] vae={args.vae} scaling_factor={scale}", flush=True)
|
| 79 |
+
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 80 |
+
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
|
| 81 |
+
|
| 82 |
+
shard_names = [f"cc12m-coco-{i:04d}.tar" for i in range(args.start, args.end)]
|
| 83 |
+
|
| 84 |
+
def fetch(name):
|
| 85 |
+
return hf_hub_download(REPO, name, repo_type="dataset", local_dir=args.tmp)
|
| 86 |
+
|
| 87 |
+
fpool = ThreadPoolExecutor(max_workers=args.prefetch)
|
| 88 |
+
futures = {}
|
| 89 |
+
def ensure_fetch(idx):
|
| 90 |
+
if idx < len(shard_names) and idx not in futures:
|
| 91 |
+
futures[idx] = fpool.submit(fetch, shard_names[idx])
|
| 92 |
+
|
| 93 |
+
for k in range(args.prefetch):
|
| 94 |
+
ensure_fetch(k)
|
| 95 |
+
|
| 96 |
+
t0 = time.time()
|
| 97 |
+
total = 0
|
| 98 |
+
for i, name in enumerate(shard_names):
|
| 99 |
+
out_path = f"{args.out}/shard_{args.start+i:04d}.npz"
|
| 100 |
+
if os.path.exists(out_path):
|
| 101 |
+
total += np.load(out_path)["latents"].shape[0]
|
| 102 |
+
futures.pop(i, None)
|
| 103 |
+
ensure_fetch(i + args.prefetch)
|
| 104 |
+
continue
|
| 105 |
+
|
| 106 |
+
tar_path = futures.pop(i).result()
|
| 107 |
+
ensure_fetch(i + args.prefetch)
|
| 108 |
+
|
| 109 |
+
items = load_shard_items(tar_path, args.size)
|
| 110 |
+
os.remove(tar_path)
|
| 111 |
+
if not items:
|
| 112 |
+
print(f"[prep] shard {args.start+i:04d} EMPTY, skipping", flush=True)
|
| 113 |
+
continue
|
| 114 |
+
imgs = [a for a, c in items]
|
| 115 |
+
caps = [c for a, c in items]
|
| 116 |
+
|
| 117 |
+
lat_chunks = []
|
| 118 |
+
for j in range(0, len(imgs), args.batch):
|
| 119 |
+
chunk = np.stack(imgs[j:j + args.batch]).astype(np.float32) / 127.5 - 1.0
|
| 120 |
+
x = torch.from_numpy(chunk).permute(0, 3, 1, 2).to(dev).half()
|
| 121 |
+
z = vae.encode(x).latent_dist.mean * scale
|
| 122 |
+
lat_chunks.append(z.cpu().numpy().astype(np.float16))
|
| 123 |
+
latents = np.concatenate(lat_chunks)
|
| 124 |
+
|
| 125 |
+
t5o = t5_tok(caps, padding="max_length", max_length=args.t5_len, truncation=True, return_tensors="np")
|
| 126 |
+
clip_ids = clip_tok(caps, padding="max_length", max_length=args.clip_len, truncation=True,
|
| 127 |
+
return_tensors="np")["input_ids"]
|
| 128 |
+
|
| 129 |
+
np.savez(out_path, latents=latents,
|
| 130 |
+
t5_ids=t5o["input_ids"].astype(np.int32),
|
| 131 |
+
t5_mask=t5o["attention_mask"].astype(np.int8),
|
| 132 |
+
clip_ids=clip_ids.astype(np.int64))
|
| 133 |
+
total += len(imgs)
|
| 134 |
+
el = time.time() - t0
|
| 135 |
+
print(f"[prep] shard {args.start+i:04d} +{len(imgs)} total={total} "
|
| 136 |
+
f"({total/el:.1f} img/s, {el/3600:.2f}h elapsed)", flush=True)
|
| 137 |
+
|
| 138 |
+
print(f"[prep] DONE total={total}", flush=True)
|
| 139 |
+
|
| 140 |
+
if __name__ == "__main__":
|
| 141 |
+
main()
|
preview.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
from PIL import Image
|
| 7 |
+
from diffusers import AutoencoderKL
|
| 8 |
+
from transformers import CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
| 9 |
+
|
| 10 |
+
from dit_v6 import MMDiT
|
| 11 |
+
|
| 12 |
+
PROMPTS = [
|
| 13 |
+
"a bowl of ramen with a soft boiled egg",
|
| 14 |
+
"a red fox sitting in a snowy forest",
|
| 15 |
+
"a lighthouse on a cliff at sunset",
|
| 16 |
+
"a wooden cabin in the mountains",
|
| 17 |
+
"a cup of coffee on a wooden table",
|
| 18 |
+
"a golden retriever running on a beach",
|
| 19 |
+
"a city street at night with neon signs",
|
| 20 |
+
"a bowl of fresh strawberries",
|
| 21 |
+
"a sailboat on a calm lake",
|
| 22 |
+
]
|
| 23 |
+
|
| 24 |
+
@torch.no_grad()
|
| 25 |
+
def sample(model, seq, mask, pool, null_seq, null_mask, null_pool, steps, cfg, dev):
|
| 26 |
+
B = seq.shape[0]
|
| 27 |
+
x = torch.randn(B, 4, 32, 32, device=dev)
|
| 28 |
+
ns, nm, npo = null_seq.expand(B, -1, -1), null_mask.expand(B, -1), null_pool.expand(B, -1)
|
| 29 |
+
dt = 1.0 / steps
|
| 30 |
+
for i in range(steps):
|
| 31 |
+
t = torch.full((B,), i * dt, device=dev)
|
| 32 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 33 |
+
vc = model(x, t, seq, mask, pool)
|
| 34 |
+
vu = model(x, t, ns, nm, npo)
|
| 35 |
+
x = x + (vu + cfg * (vc - vu)).float() * dt
|
| 36 |
+
return x
|
| 37 |
+
|
| 38 |
+
@torch.no_grad()
|
| 39 |
+
def main():
|
| 40 |
+
ap = argparse.ArgumentParser()
|
| 41 |
+
ap.add_argument("--ckpt", default="/root/runs/pm6/best.pt")
|
| 42 |
+
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
|
| 43 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 44 |
+
ap.add_argument("--t5", default="google/flan-t5-base")
|
| 45 |
+
ap.add_argument("--steps", type=int, default=50)
|
| 46 |
+
ap.add_argument("--cfg", type=float, default=5.0)
|
| 47 |
+
ap.add_argument("--t5-len", type=int, default=32)
|
| 48 |
+
ap.add_argument("--clip-len", type=int, default=40)
|
| 49 |
+
ap.add_argument("--out", default="/root/preview.png")
|
| 50 |
+
args = ap.parse_args()
|
| 51 |
+
dev = "cuda"
|
| 52 |
+
|
| 53 |
+
ck = torch.load(args.ckpt, map_location=dev)
|
| 54 |
+
c = ck["cfg"]
|
| 55 |
+
model = MMDiT(dim=c["dim"], depth=c["depth"], heads=c["heads"], mlp_hidden=c["mlp_hidden"],
|
| 56 |
+
t5_len=c["t5_len"]).to(dev).eval()
|
| 57 |
+
model.load_state_dict(ck["ema"])
|
| 58 |
+
print(f"[preview] loaded {args.ckpt} step {ck['step']}", flush=True)
|
| 59 |
+
|
| 60 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 61 |
+
vae_scale = vae.config.scaling_factor
|
| 62 |
+
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
|
| 63 |
+
t5 = T5EncoderModel.from_pretrained(args.t5).to(dev).eval()
|
| 64 |
+
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 65 |
+
clip_txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 66 |
+
|
| 67 |
+
def enc(strings):
|
| 68 |
+
te = t5_tok(strings, padding="max_length", max_length=args.t5_len, truncation=True,
|
| 69 |
+
return_tensors="pt").to(dev)
|
| 70 |
+
seq = t5(input_ids=te["input_ids"], attention_mask=te["attention_mask"]).last_hidden_state.float()
|
| 71 |
+
ce = clip_tok(strings, padding="max_length", max_length=args.clip_len, truncation=True,
|
| 72 |
+
return_tensors="pt").to(dev)
|
| 73 |
+
pool = clip_txt(input_ids=ce["input_ids"]).pooler_output.float()
|
| 74 |
+
return seq, te["attention_mask"].float(), pool
|
| 75 |
+
|
| 76 |
+
null_seq, null_mask, null_pool = enc([""])
|
| 77 |
+
|
| 78 |
+
cell, pad, cols = 256, 8, 3
|
| 79 |
+
rows = (len(PROMPTS) + cols - 1) // cols
|
| 80 |
+
sheet = Image.new("RGB", (cols * cell + (cols + 1) * pad, rows * cell + (rows + 1) * pad), (245, 246, 248))
|
| 81 |
+
|
| 82 |
+
for i, prompt in enumerate(PROMPTS):
|
| 83 |
+
seq, mask, pool = enc([prompt])
|
| 84 |
+
z = sample(model, seq, mask, pool, null_seq, null_mask, null_pool, args.steps, args.cfg, dev)
|
| 85 |
+
img = vae.decode((z / vae_scale).half()).sample.float()
|
| 86 |
+
img = ((img.clamp(-1, 1) + 1) / 2)[0].permute(1, 2, 0).cpu().numpy()
|
| 87 |
+
a = (img * 255).round().astype(np.uint8)
|
| 88 |
+
r, cc = divmod(i, cols)
|
| 89 |
+
sheet.paste(Image.fromarray(a), (pad + cc * (cell + pad), pad + r * (cell + pad)))
|
| 90 |
+
print(f"[preview] {i+1}/{len(PROMPTS)}: {prompt}", flush=True)
|
| 91 |
+
|
| 92 |
+
sheet.save(args.out)
|
| 93 |
+
print(f"[preview] wrote {args.out}", flush=True)
|
| 94 |
+
|
| 95 |
+
if __name__ == "__main__":
|
| 96 |
+
main()
|
publish_v6.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from huggingface_hub import HfApi
|
| 3 |
+
|
| 4 |
+
tok = os.environ["HF_TOKEN"]
|
| 5 |
+
api = HfApi(token=tok)
|
| 6 |
+
url = api.upload_folder(
|
| 7 |
+
repo_id="bench-labs/PixelModel-v6",
|
| 8 |
+
repo_type="model",
|
| 9 |
+
folder_path="/root/pm6release",
|
| 10 |
+
ignore_patterns=["__pycache__/*", "*.pyc"],
|
| 11 |
+
commit_message="Publish PixelModel v6: MMDiT + REPA, 150k steps, FID 23.62 at cfg 3.0",
|
| 12 |
+
)
|
| 13 |
+
print("done:", url)
|
train_v6.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import copy
|
| 5 |
+
import glob
|
| 6 |
+
import json
|
| 7 |
+
import math
|
| 8 |
+
import os
|
| 9 |
+
import time
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
import torch.nn.functional as F
|
| 14 |
+
from diffusers import AutoencoderKL
|
| 15 |
+
from transformers import AutoModel, CLIPTextModel, CLIPTokenizer, T5EncoderModel, T5TokenizerFast
|
| 16 |
+
|
| 17 |
+
from dit_v6 import MMDiT
|
| 18 |
+
|
| 19 |
+
IMAGENET_MEAN = torch.tensor([0.485, 0.456, 0.406]).view(1, 3, 1, 1)
|
| 20 |
+
IMAGENET_STD = torch.tensor([0.229, 0.224, 0.225]).view(1, 3, 1, 1)
|
| 21 |
+
|
| 22 |
+
def build_cache(shards_dir, cache):
|
| 23 |
+
shards = sorted(glob.glob(f"{shards_dir}/shard_*.npz"))
|
| 24 |
+
if not shards:
|
| 25 |
+
raise SystemExit(f"no shards in {shards_dir}")
|
| 26 |
+
lat, t5i, t5m, ci = [], [], [], []
|
| 27 |
+
for i, s in enumerate(shards):
|
| 28 |
+
z = np.load(s)
|
| 29 |
+
lat.append(z["latents"]); t5i.append(z["t5_ids"]); t5m.append(z["t5_mask"]); ci.append(z["clip_ids"])
|
| 30 |
+
if (i + 1) % 50 == 0:
|
| 31 |
+
print(f" loaded {i+1}/{len(shards)} shards", flush=True)
|
| 32 |
+
lat = np.concatenate(lat); t5i = np.concatenate(t5i); t5m = np.concatenate(t5m); ci = np.concatenate(ci)
|
| 33 |
+
np.save(f"{cache}_lat.npy", lat)
|
| 34 |
+
np.save(f"{cache}_t5ids.npy", t5i)
|
| 35 |
+
np.save(f"{cache}_t5mask.npy", t5m)
|
| 36 |
+
np.save(f"{cache}_clipids.npy", ci)
|
| 37 |
+
return lat, t5i, t5m, ci
|
| 38 |
+
|
| 39 |
+
def repa_weight_at(step, total, warm_frac=0.40, zero_frac=0.70, peak=0.5):
|
| 40 |
+
p = step / total
|
| 41 |
+
if p < warm_frac:
|
| 42 |
+
return peak
|
| 43 |
+
if p < zero_frac:
|
| 44 |
+
return peak * (1 - (p - warm_frac) / (zero_frac - warm_frac))
|
| 45 |
+
return 0.0
|
| 46 |
+
|
| 47 |
+
def main():
|
| 48 |
+
ap = argparse.ArgumentParser()
|
| 49 |
+
ap.add_argument("--shards", default="/root/v6cache/shards")
|
| 50 |
+
ap.add_argument("--cache", default="/root/v6cache/cache")
|
| 51 |
+
ap.add_argument("--out", default="/root/runs/pm6")
|
| 52 |
+
ap.add_argument("--steps", type=int, default=150000)
|
| 53 |
+
ap.add_argument("--batch", type=int, default=192)
|
| 54 |
+
ap.add_argument("--lr", type=float, default=2e-4)
|
| 55 |
+
ap.add_argument("--warmup", type=int, default=1500)
|
| 56 |
+
ap.add_argument("--dim", type=int, default=512)
|
| 57 |
+
ap.add_argument("--depth", type=int, default=16)
|
| 58 |
+
ap.add_argument("--heads", type=int, default=8)
|
| 59 |
+
ap.add_argument("--mlp-hidden", type=int, default=1408)
|
| 60 |
+
ap.add_argument("--t5-len", type=int, default=32)
|
| 61 |
+
ap.add_argument("--repa-layer", type=int, default=8)
|
| 62 |
+
ap.add_argument("--repa-peak", type=float, default=0.5)
|
| 63 |
+
ap.add_argument("--repa-batch", type=int, default=48)
|
| 64 |
+
ap.add_argument("--cfg-dropout", type=float, default=0.1)
|
| 65 |
+
ap.add_argument("--ema", type=float, default=0.9999)
|
| 66 |
+
ap.add_argument("--val-size", type=int, default=4096)
|
| 67 |
+
ap.add_argument("--val-every", type=int, default=2000)
|
| 68 |
+
ap.add_argument("--log-every", type=int, default=200)
|
| 69 |
+
ap.add_argument("--save-every", type=int, default=5000)
|
| 70 |
+
ap.add_argument("--vae", default="madebyollin/sdxl-vae-fp16-fix")
|
| 71 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 72 |
+
ap.add_argument("--t5", default="google/flan-t5-base")
|
| 73 |
+
ap.add_argument("--dinov2", default="facebook/dinov2-small")
|
| 74 |
+
ap.add_argument("--resume", default="")
|
| 75 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 76 |
+
ap.add_argument("--grad-ckpt", action="store_true")
|
| 77 |
+
args = ap.parse_args()
|
| 78 |
+
|
| 79 |
+
dev = "cuda"
|
| 80 |
+
os.makedirs(args.out, exist_ok=True)
|
| 81 |
+
torch.manual_seed(args.seed)
|
| 82 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 83 |
+
torch.backends.cudnn.allow_tf32 = True
|
| 84 |
+
|
| 85 |
+
if os.path.exists(f"{args.cache}_lat.npy"):
|
| 86 |
+
lat = np.load(f"{args.cache}_lat.npy", mmap_mode="r")
|
| 87 |
+
t5i = np.load(f"{args.cache}_t5ids.npy")
|
| 88 |
+
t5m = np.load(f"{args.cache}_t5mask.npy")
|
| 89 |
+
ci = np.load(f"{args.cache}_clipids.npy")
|
| 90 |
+
else:
|
| 91 |
+
lat, t5i, t5m, ci = build_cache(args.shards, args.cache)
|
| 92 |
+
|
| 93 |
+
N = len(lat)
|
| 94 |
+
perm = np.random.RandomState(args.seed).permutation(N)
|
| 95 |
+
val_i = np.sort(perm[:args.val_size])
|
| 96 |
+
tr_i = perm[args.val_size:]
|
| 97 |
+
print(f"[data] {N} pairs, {len(tr_i)} train, {len(val_i)} val", flush=True)
|
| 98 |
+
|
| 99 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 100 |
+
vae_scale = vae.config.scaling_factor
|
| 101 |
+
for p in vae.parameters():
|
| 102 |
+
p.requires_grad_(False)
|
| 103 |
+
|
| 104 |
+
clip_txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 105 |
+
for p in clip_txt.parameters():
|
| 106 |
+
p.requires_grad_(False)
|
| 107 |
+
|
| 108 |
+
t5 = T5EncoderModel.from_pretrained(args.t5).to(dev).eval()
|
| 109 |
+
for p in t5.parameters():
|
| 110 |
+
p.requires_grad_(False)
|
| 111 |
+
|
| 112 |
+
dinov2 = AutoModel.from_pretrained(args.dinov2).to(dev).eval()
|
| 113 |
+
for p in dinov2.parameters():
|
| 114 |
+
p.requires_grad_(False)
|
| 115 |
+
imagenet_mean = IMAGENET_MEAN.to(dev)
|
| 116 |
+
imagenet_std = IMAGENET_STD.to(dev)
|
| 117 |
+
|
| 118 |
+
@torch.no_grad()
|
| 119 |
+
def encode_text(t5_ids, t5_mask, clip_ids):
|
| 120 |
+
t5_out = t5(input_ids=t5_ids, attention_mask=t5_mask).last_hidden_state.float()
|
| 121 |
+
clip_pool = clip_txt(input_ids=clip_ids).pooler_output.float()
|
| 122 |
+
return t5_out, clip_pool
|
| 123 |
+
|
| 124 |
+
@torch.no_grad()
|
| 125 |
+
def dino_features(x1_latent):
|
| 126 |
+
px = vae.decode((x1_latent / vae_scale).to(vae.dtype)).sample.float()
|
| 127 |
+
px = (px.clamp(-1, 1) + 1) / 2
|
| 128 |
+
px = F.interpolate(px, size=(224, 224), mode="bilinear", align_corners=False)
|
| 129 |
+
px = (px - imagenet_mean) / imagenet_std
|
| 130 |
+
out = dinov2(pixel_values=px.to(dinov2.dtype)).last_hidden_state
|
| 131 |
+
return out[:, 1:, :].float()
|
| 132 |
+
|
| 133 |
+
t5_tok = T5TokenizerFast.from_pretrained(args.t5)
|
| 134 |
+
clip_tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 135 |
+
null_t5_enc = t5_tok([""], padding="max_length", max_length=args.t5_len, truncation=True, return_tensors="pt")
|
| 136 |
+
null_t5_ids = null_t5_enc["input_ids"].to(dev)
|
| 137 |
+
null_t5_mask = null_t5_enc["attention_mask"].to(dev)
|
| 138 |
+
null_clip_ids = clip_tok([""], padding="max_length", max_length=ci.shape[1], truncation=True,
|
| 139 |
+
return_tensors="pt")["input_ids"].to(dev)
|
| 140 |
+
null_t5_seq, null_clip_pool = encode_text(null_t5_ids, null_t5_mask, null_clip_ids)
|
| 141 |
+
|
| 142 |
+
t5i_t = torch.from_numpy(t5i.astype(np.int64))
|
| 143 |
+
t5m_t = torch.from_numpy(t5m.astype(np.int64))
|
| 144 |
+
ci_t = torch.from_numpy(ci.astype(np.int64))
|
| 145 |
+
|
| 146 |
+
vlat = torch.from_numpy(np.asarray(lat[val_i])).float()
|
| 147 |
+
vg = torch.Generator(device=dev).manual_seed(1234)
|
| 148 |
+
vx1 = vlat.to(dev)
|
| 149 |
+
vx0 = torch.randn(vx1.shape, device=dev, generator=vg)
|
| 150 |
+
vt = torch.sigmoid(torch.randn(vx1.shape[0], device=dev, generator=vg))
|
| 151 |
+
with torch.no_grad():
|
| 152 |
+
vseq, vmask, vpool = [], [], []
|
| 153 |
+
for i in range(0, len(val_i), 256):
|
| 154 |
+
s, p = encode_text(t5i_t[val_i[i:i+256]].to(dev), t5m_t[val_i[i:i+256]].to(dev), ci_t[val_i[i:i+256]].to(dev))
|
| 155 |
+
vseq.append(s); vmask.append(t5m_t[val_i[i:i+256]].to(dev)); vpool.append(p)
|
| 156 |
+
vseq = torch.cat(vseq); vmask = torch.cat(vmask); vpool = torch.cat(vpool)
|
| 157 |
+
|
| 158 |
+
model = MMDiT(dim=args.dim, depth=args.depth, heads=args.heads, mlp_hidden=args.mlp_hidden,
|
| 159 |
+
t5_len=args.t5_len).to(dev)
|
| 160 |
+
ema = copy.deepcopy(model).eval()
|
| 161 |
+
for p in ema.parameters():
|
| 162 |
+
p.requires_grad_(False)
|
| 163 |
+
opt = torch.optim.AdamW(model.parameters(), lr=args.lr, betas=(0.9, 0.99), weight_decay=0.0)
|
| 164 |
+
print(f"[model] {model.num_params()/1e6:.2f}M trainable, {model.num_backbone_params()/1e6:.2f}M backbone", flush=True)
|
| 165 |
+
|
| 166 |
+
start, best = 0, float("inf")
|
| 167 |
+
if args.resume and os.path.exists(args.resume):
|
| 168 |
+
ck = torch.load(args.resume, map_location=dev)
|
| 169 |
+
model.load_state_dict(ck["model"]); ema.load_state_dict(ck["ema"])
|
| 170 |
+
opt.load_state_dict(ck["opt"]); start = ck["step"] + 1; best = ck.get("best", best)
|
| 171 |
+
print(f"[resume] from step {start}", flush=True)
|
| 172 |
+
|
| 173 |
+
def lr_at(s):
|
| 174 |
+
if s < args.warmup:
|
| 175 |
+
return args.lr * (s + 1) / args.warmup
|
| 176 |
+
p = (s - args.warmup) / max(1, args.steps - args.warmup)
|
| 177 |
+
return args.lr * (0.1 + 0.9 * 0.5 * (1 + math.cos(math.pi * min(1.0, p))))
|
| 178 |
+
|
| 179 |
+
@torch.no_grad()
|
| 180 |
+
def val_loss():
|
| 181 |
+
tot, n = 0.0, 0
|
| 182 |
+
for j in range(0, vx1.shape[0], args.batch):
|
| 183 |
+
sl = slice(j, j + args.batch)
|
| 184 |
+
m = vx1[sl].shape[0]
|
| 185 |
+
tb = vt[sl].view(-1, 1, 1, 1)
|
| 186 |
+
xt = (1 - tb) * vx0[sl] + tb * vx1[sl]
|
| 187 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 188 |
+
v = ema(xt, vt[sl], vseq[sl], vmask[sl], vpool[sl])
|
| 189 |
+
tot += F.mse_loss(v.float(), vx1[sl] - vx0[sl]).item() * m
|
| 190 |
+
n += m
|
| 191 |
+
return tot / n
|
| 192 |
+
|
| 193 |
+
logf = open(f"{args.out}/log.jsonl", "a")
|
| 194 |
+
gen = torch.Generator(device=dev).manual_seed(args.seed)
|
| 195 |
+
run, run_diff, run_repa = 0.0, 0.0, 0.0
|
| 196 |
+
t0 = time.time()
|
| 197 |
+
for step in range(start, args.steps):
|
| 198 |
+
i = tr_i[np.random.randint(0, len(tr_i), args.batch)]
|
| 199 |
+
i_sorted = np.sort(i)
|
| 200 |
+
x1 = torch.from_numpy(np.asarray(lat[i_sorted])).to(dev).float()
|
| 201 |
+
t5_ids_b = t5i_t[i_sorted].to(dev)
|
| 202 |
+
t5_mask_b = t5m_t[i_sorted].to(dev)
|
| 203 |
+
clip_ids_b = ci_t[i_sorted].to(dev)
|
| 204 |
+
seq, pool = encode_text(t5_ids_b, t5_mask_b, clip_ids_b)
|
| 205 |
+
mask = t5_mask_b
|
| 206 |
+
|
| 207 |
+
drop = torch.rand(x1.shape[0], device=dev, generator=gen) < args.cfg_dropout
|
| 208 |
+
seq = torch.where(drop[:, None, None], null_t5_seq, seq)
|
| 209 |
+
mask = torch.where(drop[:, None], null_t5_mask, mask)
|
| 210 |
+
pool = torch.where(drop[:, None], null_clip_pool, pool)
|
| 211 |
+
|
| 212 |
+
x0 = torch.randn(x1.shape, device=dev, generator=gen)
|
| 213 |
+
t = torch.sigmoid(torch.randn(x1.shape[0], device=dev, generator=gen))
|
| 214 |
+
tb = t.view(-1, 1, 1, 1)
|
| 215 |
+
xt = (1 - tb) * x0 + tb * x1
|
| 216 |
+
target = x1 - x0
|
| 217 |
+
|
| 218 |
+
rw = repa_weight_at(step, args.steps, peak=args.repa_peak)
|
| 219 |
+
|
| 220 |
+
for g in opt.param_groups:
|
| 221 |
+
g["lr"] = lr_at(step)
|
| 222 |
+
|
| 223 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 224 |
+
if rw > 0:
|
| 225 |
+
v, repa_pred = model(xt, t, seq, mask, pool, return_repa=True, use_checkpoint=args.grad_ckpt)
|
| 226 |
+
else:
|
| 227 |
+
v = model(xt, t, seq, mask, pool, use_checkpoint=args.grad_ckpt)
|
| 228 |
+
loss_diff = F.mse_loss(v.float(), target)
|
| 229 |
+
if rw > 0:
|
| 230 |
+
rb = min(args.repa_batch, x1.shape[0])
|
| 231 |
+
with torch.no_grad():
|
| 232 |
+
dino_tgt = dino_features(x1[:rb])
|
| 233 |
+
loss_repa = 1.0 - F.cosine_similarity(repa_pred[:rb].float(), dino_tgt, dim=-1).mean()
|
| 234 |
+
loss = loss_diff + rw * loss_repa
|
| 235 |
+
else:
|
| 236 |
+
loss_repa = torch.zeros((), device=dev)
|
| 237 |
+
loss = loss_diff
|
| 238 |
+
|
| 239 |
+
opt.zero_grad(set_to_none=True)
|
| 240 |
+
loss.backward()
|
| 241 |
+
gn = torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
|
| 242 |
+
opt.step()
|
| 243 |
+
d = args.ema if step > args.warmup else 0.0
|
| 244 |
+
with torch.no_grad():
|
| 245 |
+
for pe, pm in zip(ema.parameters(), model.parameters()):
|
| 246 |
+
pe.mul_(d).add_(pm.detach(), alpha=1 - d)
|
| 247 |
+
for be, bm in zip(ema.buffers(), model.buffers()):
|
| 248 |
+
be.copy_(bm)
|
| 249 |
+
|
| 250 |
+
run += loss.item(); run_diff += loss_diff.item(); run_repa += loss_repa.item()
|
| 251 |
+
if (step + 1) % args.log_every == 0:
|
| 252 |
+
el = time.time() - t0
|
| 253 |
+
sps = args.log_every / el
|
| 254 |
+
print(f"[s{step+1:06d}] loss={run/args.log_every:.4f} diff={run_diff/args.log_every:.4f} "
|
| 255 |
+
f"repa={run_repa/args.log_every:.4f} rw={rw:.3f} lr={lr_at(step):.2e} gnorm={gn:.2f} "
|
| 256 |
+
f"{sps:.2f} steps/s eta={(args.steps-step-1)/sps/3600:.1f}h", flush=True)
|
| 257 |
+
logf.write(json.dumps({"step": step + 1, "loss": run/args.log_every, "loss_diff": run_diff/args.log_every,
|
| 258 |
+
"loss_repa": run_repa/args.log_every, "repa_weight": rw,
|
| 259 |
+
"steps_per_s": sps}) + "\n"); logf.flush()
|
| 260 |
+
run, run_diff, run_repa, t0 = 0.0, 0.0, 0.0, time.time()
|
| 261 |
+
|
| 262 |
+
if (step + 1) % args.val_every == 0 or step + 1 == args.steps:
|
| 263 |
+
vl = val_loss()
|
| 264 |
+
tag = ""
|
| 265 |
+
if vl < best:
|
| 266 |
+
best = vl
|
| 267 |
+
torch.save({"ema": ema.state_dict(), "step": step, "val": vl,
|
| 268 |
+
"cfg": {"dim": args.dim, "depth": args.depth, "heads": args.heads,
|
| 269 |
+
"mlp_hidden": args.mlp_hidden, "t5_len": args.t5_len}},
|
| 270 |
+
f"{args.out}/best.pt")
|
| 271 |
+
tag = " *best*"
|
| 272 |
+
print(f"[s{step+1:06d}] val_loss={vl:.5f}{tag}", flush=True)
|
| 273 |
+
logf.write(json.dumps({"step": step + 1, "val_loss": vl}) + "\n"); logf.flush()
|
| 274 |
+
t0 = time.time()
|
| 275 |
+
|
| 276 |
+
if (step + 1) % args.save_every == 0 or step + 1 == args.steps:
|
| 277 |
+
torch.save({"model": model.state_dict(), "ema": ema.state_dict(), "opt": opt.state_dict(),
|
| 278 |
+
"step": step, "best": best,
|
| 279 |
+
"cfg": {"dim": args.dim, "depth": args.depth, "heads": args.heads,
|
| 280 |
+
"mlp_hidden": args.mlp_hidden, "t5_len": args.t5_len}},
|
| 281 |
+
f"{args.out}/latest.pt")
|
| 282 |
+
|
| 283 |
+
print("TRAINDONE best_val", best, flush=True)
|
| 284 |
+
|
| 285 |
+
if __name__ == "__main__":
|
| 286 |
+
main()
|