PixelModel v5: same architecture, 36x the data
Browse files- .gitattributes +2 -0
- README.md +179 -0
- __pycache__/dit.cpython-312.pyc +0 -0
- config.json +52 -0
- dit.py +133 -0
- eval_v5.py +108 -0
- examples.png +3 -0
- main.py +89 -0
- model.png +3 -0
- model.safetensors +3 -0
- model_png.json +1 -0
- pixelmodel-v5-data.png +0 -0
- pixelmodel-v5-loss.png +0 -0
- pixelmodel-v5-val.png +0 -0
- png_codec.py +85 -0
- prep_v5.py +111 -0
- train_v5.py +193 -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,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
- dit
|
| 11 |
+
- tiny
|
| 12 |
+
- custom-code
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# PixelModel v5 🖼️
|
| 16 |
+
|
| 17 |
+
<img src="examples.png" alt="Nine 256px images generated by PixelModel v5" style="width: 100%; max-width: 860px;">
|
| 18 |
+
|
| 19 |
+
PixelModel v5 is a 40,013,980 parameter text-to-image diffusion transformer. It generates 256x256
|
| 20 |
+
images in 50 sampling steps and it trained in about 7 hours on one A100.
|
| 21 |
+
|
| 22 |
+
The architecture is identical to [v4](https://huggingface.co/bench-labs/PixelModel-v4). Same DiT,
|
| 23 |
+
same width, same depth, same VAE, same text encoder, same objective. Nothing in the model changed.
|
| 24 |
+
The only difference is that v5 saw 36 times more data.
|
| 25 |
+
|
| 26 |
+
That was the whole experiment, and it is worth being blunt about why.
|
| 27 |
+
|
| 28 |
+
## v4 was starving, not undersized
|
| 29 |
+
|
| 30 |
+
v4 trained on MS-COCO, which is about 83,000 images. At batch 256 for 80,000 steps that works out to
|
| 31 |
+
roughly 247 passes over the same photographs. A model that sees the same 83,000 images 247 times is
|
| 32 |
+
not learning what the world looks like, it is memorising a small album.
|
| 33 |
+
|
| 34 |
+
We spent a while looking at architecture changes first. Linear attention, deeper stacks, a
|
| 35 |
+
higher compression autoencoder, representation alignment. All of them are real techniques and none
|
| 36 |
+
of them address the actual problem, because the bottleneck was never the shape of the network.
|
| 37 |
+
|
| 38 |
+
<img src="pixelmodel-v5-data.png" alt="Training set size, v4 at 83k images versus v5 at 2.99M" style="width: 100%; max-width: 780px;">
|
| 39 |
+
|
| 40 |
+
v5 trains on 2,986,571 image and caption pairs, which is about 10 epochs instead of 247.
|
| 41 |
+
|
| 42 |
+
## The captions matter as much as the count
|
| 43 |
+
|
| 44 |
+
The images come from CC12M. Raw CC12M alt text is close to unusable for this, because it is scraped
|
| 45 |
+
SEO copy. A typical caption reads like "This is the best recipe I have ever tried for Cuban bread.
|
| 46 |
+
Cuban Recipes, Bread Recipes, Cooking Recipes, Pan Cubano".
|
| 47 |
+
|
| 48 |
+
v5 uses a recaptioned version where a vision model rewrote every caption in COCO style:
|
| 49 |
+
|
| 50 |
+
> A purple-lit subway train sits at a station platform.
|
| 51 |
+
>
|
| 52 |
+
> An old red tractor with gold fenders and red wheels stands in a snowy field.
|
| 53 |
+
>
|
| 54 |
+
> A compact kitchenette in a studio apartment features a stainless steel refrigerator, a microwave,
|
| 55 |
+
> and a sink with a glass faucet.
|
| 56 |
+
|
| 57 |
+
Those describe what is in the frame, which is what a text-to-image model needs. They also match the
|
| 58 |
+
caption distribution that FID and CLIP score are computed against, so the training signal and the
|
| 59 |
+
evaluation are speaking the same language.
|
| 60 |
+
|
| 61 |
+
## Training
|
| 62 |
+
|
| 63 |
+
<img src="pixelmodel-v5-loss.png" alt="Training and held-out loss over 120,000 steps" style="width: 100%; max-width: 860px;">
|
| 64 |
+
|
| 65 |
+
120,000 steps at batch 256. AdamW at 2e-4 with betas (0.9, 0.99), no weight decay, gradient clipping
|
| 66 |
+
at 1.0, cosine decay to a tenth of peak after a 1,000 step warmup, EMA at 0.9999 starting after
|
| 67 |
+
warmup, and 10% caption dropout for classifier free guidance. It held 4.6 steps per second at
|
| 68 |
+
44.2 GiB the whole way.
|
| 69 |
+
|
| 70 |
+
The held-out curve climbs for the first 10,000 steps or so, which looks alarming and is not. EMA at
|
| 71 |
+
0.9999 has a time constant of roughly 10,000 steps, so early on those weights are still mostly
|
| 72 |
+
initialisation. The number only becomes meaningful once EMA has caught up, and from there it falls
|
| 73 |
+
without interruption.
|
| 74 |
+
|
| 75 |
+
<img src="pixelmodel-v5-val.png" alt="Held-out loss falling monotonically with no turn-up" style="width: 100%; max-width: 860px;">
|
| 76 |
+
|
| 77 |
+
**v4 had no validation split at all**, so it shipped whichever weights the last step happened to
|
| 78 |
+
produce. v5 holds out 4,096 pairs, evaluates every 2,000 steps, and writes the best checkpoint to a
|
| 79 |
+
separate file. Across the whole run the held-out loss improved at every single check and never once
|
| 80 |
+
turned upward, which is the clearest evidence that the data change worked. Our sibling model
|
| 81 |
+
[VoxelModel v1](https://huggingface.co/bench-labs/VoxelModel-v1), trained on 28,415 meshes for 811
|
| 82 |
+
epochs, peaked at step 64,000 and got 3.08% worse by the end. Same recipe, same team, different data
|
| 83 |
+
regime, opposite outcome.
|
| 84 |
+
|
| 85 |
+
## Results
|
| 86 |
+
|
| 87 |
+
Measured on 5,000 MS-COCO val2014 images at 256 center crop, using `torchmetrics` FID at 2048
|
| 88 |
+
features and `torchmetrics` CLIPScore with `openai/clip-vit-base-patch32`. This is v4's protocol.
|
| 89 |
+
|
| 90 |
+
| | FID ↓ | CLIP ↑ |
|
| 91 |
+
|---|---|---|
|
| 92 |
+
| PixelModel v4 | 39.54 | 28.04 |
|
| 93 |
+
| **PixelModel v5, cfg 5.0** | **34.06** | **29.27** |
|
| 94 |
+
| PixelModel v5, cfg 3.0 | 35.03 | 28.59 |
|
| 95 |
+
| PixelModel v5, cfg 6.0 | 35.18 | 29.28 |
|
| 96 |
+
| real photographs | n/a | 30.05 |
|
| 97 |
+
|
| 98 |
+
FID is 13.9% lower and CLIP score is 1.23 higher, at an identical parameter count. Nothing in the
|
| 99 |
+
network changed between v4 and v5, so the entire difference is the training data.
|
| 100 |
+
|
| 101 |
+
The last row is there because a metric without a reference point is hard to read. Feeding the real
|
| 102 |
+
COCO photographs and their own captions through the same CLIPScore gives 30.05, so v5 at 29.27 is
|
| 103 |
+
within 0.78 of the ceiling this metric can award. That number also served as a sanity check on the
|
| 104 |
+
harness, since `torchmetrics` CLIPScore is incompatible with transformers 5.x and needed patching
|
| 105 |
+
before it would run at all.
|
| 106 |
+
|
| 107 |
+
Guidance scale was swept rather than assumed. FID bottoms out at cfg 5.0 and CLIP keeps climbing
|
| 108 |
+
slightly to cfg 6.0, which is the usual tension between the two. Anyone reproducing this should
|
| 109 |
+
also know that FID is heavily biased at small sample sizes. The same checkpoint at cfg 5.0 scores
|
| 110 |
+
74.35 on 1,000 images and 34.06 on 5,000, so sample count has to match before two FID numbers can be
|
| 111 |
+
compared at all.
|
| 112 |
+
|
| 113 |
+
One caveat worth stating plainly. v4's cached evaluation set is not published in its repository, so
|
| 114 |
+
the reference images here were rebuilt from COCO val2014 with a fixed seed. The protocol is the same
|
| 115 |
+
but the exact 5,000 photographs may not be. CLIP score is unaffected by this since it compares each
|
| 116 |
+
generated image against its own caption, but the FID comparison carries that asterisk.
|
| 117 |
+
|
| 118 |
+
## Specification
|
| 119 |
+
|
| 120 |
+
| | |
|
| 121 |
+
|---|---|
|
| 122 |
+
| trainable parameters | 40,013,980 |
|
| 123 |
+
| frozen VAE, `sd-vae-ft-mse` | 83,653,863 |
|
| 124 |
+
| frozen text encoder, CLIP ViT-B/32 | 63,165,952 |
|
| 125 |
+
| **combined total** | **186,833,795** |
|
| 126 |
+
| architecture | DiT, dim 384, depth 12, heads 6, patch 2 |
|
| 127 |
+
| tokens | 256, over a 32x32x4 latent |
|
| 128 |
+
| objective | rectified flow, target `x1 - x0`, logit-normal timesteps |
|
| 129 |
+
| conditioning | cross attention on 40 CLIP text tokens, plus adaLN-zero |
|
| 130 |
+
| resolution | 256x256 |
|
| 131 |
+
| sampling | 50 steps, cfg 5.0 for best FID, cfg 6.0 for best CLIP |
|
| 132 |
+
|
| 133 |
+
A note on that combined number, because it is higher than what v4 published. v4's card reports
|
| 134 |
+
161,500,000 total. That figure counts the CLIP text transformer but leaves out its 49,408 by 512
|
| 135 |
+
token embedding table, which is another 25.3M parameters. The encoder does not run without it, so it
|
| 136 |
+
counts. The correct total for both v4 and v5 is 186,833,795.
|
| 137 |
+
|
| 138 |
+
## What it does well and what it does not
|
| 139 |
+
|
| 140 |
+
After a few hundred samples the boundary is consistent.
|
| 141 |
+
|
| 142 |
+
It is good at material and light. Food, landscapes, skies, water, snow, foliage, stone, interiors,
|
| 143 |
+
depth of field. A bowl of ramen, a wet cobblestone street, a wheat field under storm light, a library
|
| 144 |
+
of wooden shelves. These come back looking like photographs.
|
| 145 |
+
|
| 146 |
+
It is bad at structure. Faces and animal heads deform. Limbs merge. Wings on aircraft are stubby or
|
| 147 |
+
fused to the fuselage. Any text it renders, on a shop sign or an airliner livery, is convincing
|
| 148 |
+
looking gibberish. Prompts asking for one isolated object in an empty scene often return the scene
|
| 149 |
+
without the object, so "a lighthouse on a cliff at sunset" gives a very nice sunset over a cliff and
|
| 150 |
+
no lighthouse.
|
| 151 |
+
|
| 152 |
+
Frequency in the training data matters more than complexity. Aircraft are structurally complicated
|
| 153 |
+
and come out fine because CC12M is full of them. Hot air balloons are simpler and fail, because they
|
| 154 |
+
are rare.
|
| 155 |
+
|
| 156 |
+
That failure profile is what a 40M model looks like once data is no longer the constraint. It has
|
| 157 |
+
learned appearance thoroughly and topology poorly, and topology is what capacity buys. v6 is where
|
| 158 |
+
that gets spent.
|
| 159 |
+
|
| 160 |
+
## Usage
|
| 161 |
+
|
| 162 |
+
```bash
|
| 163 |
+
python main.py "a bowl of ramen with a soft boiled egg" --out ramen.png --cfg 6.0 --steps 50
|
| 164 |
+
```
|
| 165 |
+
|
| 166 |
+
As with every model in this line the weights are also stored as a PNG. `model.png` is not a picture
|
| 167 |
+
of the network, it is the network, with each parameter packed across the red and green channels of
|
| 168 |
+
one pixel.
|
| 169 |
+
|
| 170 |
+
## Files
|
| 171 |
+
|
| 172 |
+
| file | contents |
|
| 173 |
+
|---|---|
|
| 174 |
+
| `model.safetensors` | combined weights, backbone and VAE and text encoder |
|
| 175 |
+
| `model.png` | the same backbone weights as an image |
|
| 176 |
+
| `dit.py` | the model |
|
| 177 |
+
| `train_v5.py` | training loop with the held-out split |
|
| 178 |
+
| `prep_v5.py` | streams the dataset, encodes latents, caches captions |
|
| 179 |
+
| `main.py` | inference |
|
__pycache__/dit.cpython-312.pyc
ADDED
|
Binary file (12.7 kB). View file
|
|
|
config.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architecture": "latent-diffusion-dit",
|
| 3 |
+
"objective": "rectified-flow",
|
| 4 |
+
"dit": {
|
| 5 |
+
"dim": 384,
|
| 6 |
+
"depth": 12,
|
| 7 |
+
"heads": 6,
|
| 8 |
+
"patch": 2,
|
| 9 |
+
"latent_ch": 4,
|
| 10 |
+
"latent_size": 32,
|
| 11 |
+
"text_dim": 512,
|
| 12 |
+
"mlp_ratio": 4.0
|
| 13 |
+
},
|
| 14 |
+
"vae": "stabilityai/sd-vae-ft-mse",
|
| 15 |
+
"text_encoder": "openai/clip-vit-base-patch32",
|
| 16 |
+
"max_tokens": 40,
|
| 17 |
+
"resolution": 256,
|
| 18 |
+
"trainable_parameters": 40013980,
|
| 19 |
+
"vae_parameters": 83653863,
|
| 20 |
+
"text_encoder_parameters": 63165952,
|
| 21 |
+
"total_parameters_incl_frozen": 186833795,
|
| 22 |
+
"training": {
|
| 23 |
+
"steps": 120000,
|
| 24 |
+
"batch_size": 256,
|
| 25 |
+
"pairs": 2986571,
|
| 26 |
+
"val_pairs": 4096,
|
| 27 |
+
"optimizer": "adamw",
|
| 28 |
+
"lr": 0.0002,
|
| 29 |
+
"betas": [
|
| 30 |
+
0.9,
|
| 31 |
+
0.99
|
| 32 |
+
],
|
| 33 |
+
"warmup": 1000,
|
| 34 |
+
"ema": 0.9999,
|
| 35 |
+
"cfg_dropout": 0.1,
|
| 36 |
+
"best_val_loss": 0.7852968573570251,
|
| 37 |
+
"dataset": "undefined443/cc12m-wds-coco-recaptioned"
|
| 38 |
+
},
|
| 39 |
+
"sampling": {
|
| 40 |
+
"steps": 50,
|
| 41 |
+
"cfg": 5.0
|
| 42 |
+
},
|
| 43 |
+
"eval": {
|
| 44 |
+
"fid": 34.06,
|
| 45 |
+
"clip_score": 29.27,
|
| 46 |
+
"n": 5000,
|
| 47 |
+
"cfg": 5.0,
|
| 48 |
+
"dataset": "MS-COCO val2014, 256 center crop",
|
| 49 |
+
"protocol": "torchmetrics FrechetInceptionDistance + CLIPScore (openai/clip-vit-base-patch32)",
|
| 50 |
+
"real_image_clip_score": 30.05
|
| 51 |
+
}
|
| 52 |
+
}
|
dit.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import math
|
| 4 |
+
import numpy as np
|
| 5 |
+
import torch
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.nn.functional as F
|
| 8 |
+
|
| 9 |
+
def modulate(x, shift, scale):
|
| 10 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 11 |
+
|
| 12 |
+
def timestep_embedding(t, dim, max_period=10000):
|
| 13 |
+
half = dim // 2
|
| 14 |
+
freqs = torch.exp(-math.log(max_period) * torch.arange(half, device=t.device) / half)
|
| 15 |
+
args = t[:, None].float() * freqs[None]
|
| 16 |
+
emb = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
|
| 17 |
+
if dim % 2:
|
| 18 |
+
emb = torch.cat([emb, torch.zeros_like(emb[:, :1])], dim=-1)
|
| 19 |
+
return emb
|
| 20 |
+
|
| 21 |
+
def sincos_2d(dim, grid_size):
|
| 22 |
+
g = np.arange(grid_size, dtype=np.float32)
|
| 23 |
+
gx, gy = np.meshgrid(g, g, indexing="xy")
|
| 24 |
+
assert dim % 4 == 0
|
| 25 |
+
d4 = dim // 4
|
| 26 |
+
omega = 1.0 / (10000 ** (np.arange(d4, dtype=np.float32) / d4))
|
| 27 |
+
def emb1(p):
|
| 28 |
+
out = p.reshape(-1)[:, None] * omega[None]
|
| 29 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 30 |
+
pe = np.concatenate([emb1(gx), emb1(gy)], axis=1)
|
| 31 |
+
return torch.from_numpy(pe).float()
|
| 32 |
+
|
| 33 |
+
class Attention(nn.Module):
|
| 34 |
+
def __init__(self, dim, heads):
|
| 35 |
+
super().__init__()
|
| 36 |
+
self.heads = heads
|
| 37 |
+
self.q = nn.Linear(dim, dim)
|
| 38 |
+
self.kv = nn.Linear(dim, dim * 2)
|
| 39 |
+
self.proj = nn.Linear(dim, dim)
|
| 40 |
+
|
| 41 |
+
def forward(self, x, ctx=None):
|
| 42 |
+
ctx = x if ctx is None else ctx
|
| 43 |
+
B, N, C = x.shape
|
| 44 |
+
M = ctx.shape[1]
|
| 45 |
+
h = self.heads
|
| 46 |
+
q = self.q(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 47 |
+
kv = self.kv(ctx).reshape(B, M, 2, h, C // h).permute(2, 0, 3, 1, 4)
|
| 48 |
+
k, v = kv[0], kv[1]
|
| 49 |
+
o = F.scaled_dot_product_attention(q, k, v)
|
| 50 |
+
o = o.transpose(1, 2).reshape(B, N, C)
|
| 51 |
+
return self.proj(o)
|
| 52 |
+
|
| 53 |
+
class Block(nn.Module):
|
| 54 |
+
def __init__(self, dim, heads, mlp_ratio=4.0):
|
| 55 |
+
super().__init__()
|
| 56 |
+
self.norm1 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 57 |
+
self.attn = Attention(dim, heads)
|
| 58 |
+
self.norm_ca = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 59 |
+
self.cross = Attention(dim, heads)
|
| 60 |
+
self.norm2 = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 61 |
+
hidden = int(dim * mlp_ratio)
|
| 62 |
+
self.mlp = nn.Sequential(nn.Linear(dim, hidden), nn.GELU(approximate="tanh"),
|
| 63 |
+
nn.Linear(hidden, dim))
|
| 64 |
+
self.ada = nn.Sequential(nn.SiLU(), nn.Linear(dim, 6 * dim))
|
| 65 |
+
self.cross_gate = nn.Parameter(torch.zeros(1))
|
| 66 |
+
|
| 67 |
+
def forward(self, x, c, text):
|
| 68 |
+
shift1, scale1, gate1, shift2, scale2, gate2 = self.ada(c).chunk(6, dim=1)
|
| 69 |
+
x = x + gate1.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift1, scale1))
|
| 70 |
+
x = x + self.cross_gate * self.cross(self.norm_ca(x), text)
|
| 71 |
+
x = x + gate2.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift2, scale2))
|
| 72 |
+
return x
|
| 73 |
+
|
| 74 |
+
class DiT(nn.Module):
|
| 75 |
+
def __init__(self, latent_ch=4, latent_size=32, patch=2, dim=384, depth=12,
|
| 76 |
+
heads=6, text_dim=512, mlp_ratio=4.0):
|
| 77 |
+
super().__init__()
|
| 78 |
+
self.latent_ch = latent_ch
|
| 79 |
+
self.latent_size = latent_size
|
| 80 |
+
self.patch = patch
|
| 81 |
+
self.grid = latent_size // patch
|
| 82 |
+
self.patch_dim = latent_ch * patch * patch
|
| 83 |
+
self.x_embed = nn.Linear(self.patch_dim, dim)
|
| 84 |
+
self.register_buffer("pos", sincos_2d(dim, self.grid).unsqueeze(0))
|
| 85 |
+
self.t_mlp = nn.Sequential(nn.Linear(dim, dim), nn.SiLU(), nn.Linear(dim, dim))
|
| 86 |
+
self.text_proj = nn.Linear(text_dim, dim)
|
| 87 |
+
self.text_pool = nn.Linear(text_dim, dim)
|
| 88 |
+
self.blocks = nn.ModuleList([Block(dim, heads, mlp_ratio) for _ in range(depth)])
|
| 89 |
+
self.norm_out = nn.LayerNorm(dim, elementwise_affine=False, eps=1e-6)
|
| 90 |
+
self.ada_out = nn.Sequential(nn.SiLU(), nn.Linear(dim, 2 * dim))
|
| 91 |
+
self.head = nn.Linear(dim, self.patch_dim)
|
| 92 |
+
self.dim = dim
|
| 93 |
+
self._init()
|
| 94 |
+
|
| 95 |
+
def _init(self):
|
| 96 |
+
for m in self.modules():
|
| 97 |
+
if isinstance(m, nn.Linear):
|
| 98 |
+
nn.init.xavier_uniform_(m.weight)
|
| 99 |
+
if m.bias is not None:
|
| 100 |
+
nn.init.zeros_(m.bias)
|
| 101 |
+
for b in self.blocks:
|
| 102 |
+
nn.init.zeros_(b.ada[-1].weight); nn.init.zeros_(b.ada[-1].bias)
|
| 103 |
+
nn.init.zeros_(self.ada_out[-1].weight); nn.init.zeros_(self.ada_out[-1].bias)
|
| 104 |
+
nn.init.zeros_(self.head.weight); nn.init.zeros_(self.head.bias)
|
| 105 |
+
|
| 106 |
+
def patchify(self, x):
|
| 107 |
+
B, C, H, W = x.shape
|
| 108 |
+
p = self.patch
|
| 109 |
+
x = x.reshape(B, C, H // p, p, W // p, p)
|
| 110 |
+
x = x.permute(0, 2, 4, 1, 3, 5).reshape(B, (H // p) * (W // p), C * p * p)
|
| 111 |
+
return x
|
| 112 |
+
|
| 113 |
+
def unpatchify(self, x):
|
| 114 |
+
B, N, _ = x.shape
|
| 115 |
+
p = self.patch
|
| 116 |
+
g = self.grid
|
| 117 |
+
C = self.latent_ch
|
| 118 |
+
x = x.reshape(B, g, g, C, p, p).permute(0, 3, 1, 4, 2, 5)
|
| 119 |
+
return x.reshape(B, C, g * p, g * p)
|
| 120 |
+
|
| 121 |
+
def forward(self, x, t, text_seq, text_pool):
|
| 122 |
+
x = self.x_embed(self.patchify(x)) + self.pos
|
| 123 |
+
c = self.t_mlp(timestep_embedding(t, self.dim)) + self.text_pool(text_pool)
|
| 124 |
+
text = self.text_proj(text_seq)
|
| 125 |
+
for blk in self.blocks:
|
| 126 |
+
x = blk(x, c, text)
|
| 127 |
+
shift, scale = self.ada_out(c).chunk(2, dim=1)
|
| 128 |
+
x = modulate(self.norm_out(x), shift, scale)
|
| 129 |
+
x = self.head(x)
|
| 130 |
+
return self.unpatchify(x)
|
| 131 |
+
|
| 132 |
+
def num_params(self):
|
| 133 |
+
return sum(p.numel() for p in self.parameters())
|
eval_v5.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse, json, os, sys, numpy as np, torch
|
| 2 |
+
from diffusers import AutoencoderKL
|
| 3 |
+
from transformers import CLIPTextModel, CLIPTokenizer, CLIPModel
|
| 4 |
+
sys.path.insert(0, '/root')
|
| 5 |
+
from dit import DiT
|
| 6 |
+
|
| 7 |
+
SCALE = 0.18215
|
| 8 |
+
|
| 9 |
+
def _img_feats(self, pixel_values=None, **kw):
|
| 10 |
+
return self.visual_projection(self.vision_model(pixel_values=pixel_values).pooler_output)
|
| 11 |
+
|
| 12 |
+
def _txt_feats(self, input_ids=None, attention_mask=None, **kw):
|
| 13 |
+
return self.text_projection(self.text_model(input_ids=input_ids,
|
| 14 |
+
attention_mask=attention_mask).pooler_output)
|
| 15 |
+
|
| 16 |
+
CLIPModel.get_image_features = _img_feats
|
| 17 |
+
CLIPModel.get_text_features = _txt_feats
|
| 18 |
+
|
| 19 |
+
@torch.no_grad()
|
| 20 |
+
def sample(model, seq, pool, ns, npool, steps, cfg, dev):
|
| 21 |
+
B = seq.shape[0]
|
| 22 |
+
x = torch.randn(B, 4, 32, 32, device=dev)
|
| 23 |
+
a, b = ns.expand(B, -1, -1), npool.expand(B, -1)
|
| 24 |
+
dt = 1.0 / steps
|
| 25 |
+
for i in range(steps):
|
| 26 |
+
t = torch.full((B,), i * dt, device=dev)
|
| 27 |
+
with torch.autocast('cuda', dtype=torch.bfloat16):
|
| 28 |
+
vc = model(x, t, seq, pool)
|
| 29 |
+
vu = model(x, t, a, b)
|
| 30 |
+
x = x + (vu + cfg * (vc - vu)).float() * dt
|
| 31 |
+
return x
|
| 32 |
+
|
| 33 |
+
@torch.no_grad()
|
| 34 |
+
def main():
|
| 35 |
+
ap = argparse.ArgumentParser()
|
| 36 |
+
ap.add_argument('--ckpt', default='/root/runs/pm5/best.pt')
|
| 37 |
+
ap.add_argument('--data', default='/root/pm5eval/eval_256.npz')
|
| 38 |
+
ap.add_argument('--n', type=int, default=5000)
|
| 39 |
+
ap.add_argument('--batch', type=int, default=100)
|
| 40 |
+
ap.add_argument('--steps', type=int, default=50)
|
| 41 |
+
ap.add_argument('--cfgs', default='2,3,4,5,6')
|
| 42 |
+
ap.add_argument('--out', default='/root/pm5_eval.json')
|
| 43 |
+
args = ap.parse_args()
|
| 44 |
+
dev = 'cuda'
|
| 45 |
+
|
| 46 |
+
ck = torch.load(args.ckpt, map_location=dev)
|
| 47 |
+
model = DiT(dim=384, depth=12, heads=6).to(dev).eval()
|
| 48 |
+
model.load_state_dict(ck['ema'])
|
| 49 |
+
print(f"[eval] ckpt step {ck.get('step')} val {ck.get('val')}", flush=True)
|
| 50 |
+
|
| 51 |
+
vae = AutoencoderKL.from_pretrained('stabilityai/sd-vae-ft-mse').to(dev).half().eval()
|
| 52 |
+
tok = CLIPTokenizer.from_pretrained('openai/clip-vit-base-patch32')
|
| 53 |
+
txt = CLIPTextModel.from_pretrained('openai/clip-vit-base-patch32').to(dev).half().eval()
|
| 54 |
+
e = tok([''], padding='max_length', max_length=40, truncation=True, return_tensors='pt').to(dev)
|
| 55 |
+
o = txt(**e)
|
| 56 |
+
ns, npool = o.last_hidden_state.float(), o.pooler_output.float()
|
| 57 |
+
|
| 58 |
+
d = np.load(args.data, allow_pickle=True)
|
| 59 |
+
real = d['images'][:args.n]
|
| 60 |
+
caps = [str(x) for x in d['captions'][:args.n]]
|
| 61 |
+
n = len(caps)
|
| 62 |
+
print(f'[eval] {n} real images and captions', flush=True)
|
| 63 |
+
|
| 64 |
+
from torchmetrics.image.fid import FrechetInceptionDistance
|
| 65 |
+
from torchmetrics.multimodal.clip_score import CLIPScore
|
| 66 |
+
|
| 67 |
+
ref = CLIPScore(model_name_or_path='openai/clip-vit-base-patch32').to(dev)
|
| 68 |
+
for i in range(0, n, args.batch):
|
| 69 |
+
rb = torch.from_numpy(real[i:i + args.batch]).permute(0, 3, 1, 2).to(dev)
|
| 70 |
+
ref.update(rb, caps[i:i + args.batch])
|
| 71 |
+
real_clip = float(ref.compute().item())
|
| 72 |
+
print(f'[eval] REAL images CLIP score {real_clip:.2f} (metric sanity check / ceiling)', flush=True)
|
| 73 |
+
del ref
|
| 74 |
+
torch.cuda.empty_cache()
|
| 75 |
+
|
| 76 |
+
results = []
|
| 77 |
+
for cfg in [float(x) for x in args.cfgs.split(',')]:
|
| 78 |
+
fid = FrechetInceptionDistance(feature=2048, normalize=True).to(dev)
|
| 79 |
+
clip = CLIPScore(model_name_or_path='openai/clip-vit-base-patch32').to(dev)
|
| 80 |
+
for i in range(0, n, args.batch):
|
| 81 |
+
rb = torch.from_numpy(real[i:i + args.batch].astype(np.float32) / 255.0).permute(0, 3, 1, 2).to(dev)
|
| 82 |
+
fid.update(rb, real=True)
|
| 83 |
+
for i in range(0, n, args.batch):
|
| 84 |
+
cb = caps[i:i + args.batch]
|
| 85 |
+
t = tok(cb, padding='max_length', max_length=40, truncation=True, return_tensors='pt').to(dev)
|
| 86 |
+
oo = txt(**t)
|
| 87 |
+
z = sample(model, oo.last_hidden_state.float(), oo.pooler_output.float(),
|
| 88 |
+
ns, npool, args.steps, cfg, dev)
|
| 89 |
+
img = vae.decode((z / SCALE).half()).sample.float()
|
| 90 |
+
img = (img.clamp(-1, 1) + 1) / 2
|
| 91 |
+
fid.update(img, real=False)
|
| 92 |
+
clip.update((img * 255).to(torch.uint8), cb)
|
| 93 |
+
f = float(fid.compute().item()); c = float(clip.compute().item())
|
| 94 |
+
results.append({'cfg': cfg, 'fid': round(f, 2), 'clip_score': round(c, 2),
|
| 95 |
+
'n': n, 'steps': args.steps})
|
| 96 |
+
print(f'[eval] cfg {cfg}: FID {f:.2f} CLIP {c:.2f}', flush=True)
|
| 97 |
+
del fid, clip
|
| 98 |
+
torch.cuda.empty_cache()
|
| 99 |
+
|
| 100 |
+
best = min(results, key=lambda r: r['fid'])
|
| 101 |
+
json.dump({'ckpt_step': ck.get('step'), 'val_loss': ck.get('val'),
|
| 102 |
+
'real_image_clip_score': round(real_clip, 2),
|
| 103 |
+
'results': results, 'best_fid': best}, open(args.out, 'w'), indent=2)
|
| 104 |
+
print(f"[eval] BEST FID {best['fid']} at cfg {best['cfg']} (CLIP {best['clip_score']})", flush=True)
|
| 105 |
+
print('EVALDONE', flush=True)
|
| 106 |
+
|
| 107 |
+
if __name__ == '__main__':
|
| 108 |
+
main()
|
examples.png
ADDED
|
|
Git LFS Details
|
main.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 13 |
+
|
| 14 |
+
from dit import DiT
|
| 15 |
+
|
| 16 |
+
SCALE = 0.18215
|
| 17 |
+
|
| 18 |
+
@torch.no_grad()
|
| 19 |
+
def sample(model, seq, pool, null_seq, null_pool, steps, cfg, dev, seed=None):
|
| 20 |
+
B = seq.shape[0]
|
| 21 |
+
g = None
|
| 22 |
+
if seed is not None:
|
| 23 |
+
g = torch.Generator(device=dev).manual_seed(seed)
|
| 24 |
+
x = torch.randn(B, 4, 32, 32, device=dev, generator=g)
|
| 25 |
+
ns, npool = null_seq.expand(B, -1, -1), null_pool.expand(B, -1)
|
| 26 |
+
dt = 1.0 / steps
|
| 27 |
+
for i in range(steps):
|
| 28 |
+
t = torch.full((B,), i * dt, device=dev)
|
| 29 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 30 |
+
vc = model(x, t, seq, pool)
|
| 31 |
+
vu = model(x, t, ns, npool)
|
| 32 |
+
x = x + (vu + cfg * (vc - vu)).float() * dt
|
| 33 |
+
return x
|
| 34 |
+
|
| 35 |
+
@torch.no_grad()
|
| 36 |
+
def main():
|
| 37 |
+
ap = argparse.ArgumentParser()
|
| 38 |
+
ap.add_argument("prompts", nargs="+")
|
| 39 |
+
ap.add_argument("--out", default="out.png")
|
| 40 |
+
ap.add_argument("--cfg", type=float, default=5.0)
|
| 41 |
+
ap.add_argument("--steps", type=int, default=50)
|
| 42 |
+
ap.add_argument("--seed", type=int, default=None)
|
| 43 |
+
ap.add_argument("--device", default="cuda")
|
| 44 |
+
ap.add_argument("--weights", default="model.safetensors")
|
| 45 |
+
ap.add_argument("--config", default="config.json")
|
| 46 |
+
ap.add_argument("--vae", default="stabilityai/sd-vae-ft-mse")
|
| 47 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 48 |
+
ap.add_argument("--max-tokens", type=int, default=40)
|
| 49 |
+
args = ap.parse_args()
|
| 50 |
+
dev = args.device
|
| 51 |
+
|
| 52 |
+
d = json.load(open(args.config))["dit"] if os.path.exists(args.config) else {
|
| 53 |
+
"dim": 384, "depth": 12, "heads": 6}
|
| 54 |
+
model = DiT(dim=d["dim"], depth=d["depth"], heads=d["heads"]).to(dev).eval()
|
| 55 |
+
sd = load_file(args.weights)
|
| 56 |
+
model.load_state_dict({k[len("dit."):]: v for k, v in sd.items() if k.startswith("dit.")})
|
| 57 |
+
|
| 58 |
+
vae = AutoencoderKL.from_pretrained(args.vae).to(dev).half().eval()
|
| 59 |
+
tok = CLIPTokenizer.from_pretrained(args.clip)
|
| 60 |
+
txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 61 |
+
|
| 62 |
+
def enc(strings):
|
| 63 |
+
t = tok(strings, padding="max_length", max_length=args.max_tokens,
|
| 64 |
+
truncation=True, return_tensors="pt").to(dev)
|
| 65 |
+
o = txt(**t)
|
| 66 |
+
return o.last_hidden_state.float(), o.pooler_output.float()
|
| 67 |
+
|
| 68 |
+
seq, pool = enc(args.prompts)
|
| 69 |
+
null_seq, null_pool = enc([""])
|
| 70 |
+
z = sample(model, seq, pool, null_seq, null_pool, args.steps, args.cfg, dev, args.seed)
|
| 71 |
+
img = vae.decode((z / SCALE).half()).sample.float()
|
| 72 |
+
img = ((img.clamp(-1, 1) + 1) / 2).permute(0, 2, 3, 1).cpu().numpy()
|
| 73 |
+
|
| 74 |
+
n = len(args.prompts)
|
| 75 |
+
if n == 1:
|
| 76 |
+
Image.fromarray((img[0] * 255).round().astype(np.uint8)).save(args.out)
|
| 77 |
+
paths = [args.out]
|
| 78 |
+
else:
|
| 79 |
+
root, ext = os.path.splitext(args.out)
|
| 80 |
+
paths = []
|
| 81 |
+
for i in range(n):
|
| 82 |
+
p = f"{root}_{i}{ext}"
|
| 83 |
+
Image.fromarray((img[i] * 255).round().astype(np.uint8)).save(p)
|
| 84 |
+
paths.append(p)
|
| 85 |
+
for p, s in zip(paths, args.prompts):
|
| 86 |
+
print(f'[pixelmodel] "{s}" -> {p} (cfg {args.cfg}, {args.steps} steps)')
|
| 87 |
+
|
| 88 |
+
if __name__ == "__main__":
|
| 89 |
+
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:927864ec43cc1534849ed27c9be86d6f5a59b4fe13fd451806df4b7a66939178
|
| 3 |
+
size 747804492
|
model_png.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cfg": {"dim": 384, "depth": 12, "heads": 6}, "params": [{"name": "x_embed.weight", "shape": [384, 16], "numel": 6144}, {"name": "x_embed.bias", "shape": [384], "numel": 384}, {"name": "t_mlp.0.weight", "shape": [384, 384], "numel": 147456}, {"name": "t_mlp.0.bias", "shape": [384], "numel": 384}, {"name": "t_mlp.2.weight", "shape": [384, 384], "numel": 147456}, {"name": "t_mlp.2.bias", "shape": [384], "numel": 384}, {"name": "text_proj.weight", "shape": [384, 512], "numel": 196608}, {"name": "text_proj.bias", "shape": [384], "numel": 384}, {"name": "text_pool.weight", "shape": [384, 512], "numel": 196608}, {"name": "text_pool.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.0.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.0.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.0.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.0.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.0.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.0.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.0.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.0.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.0.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.0.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.0.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.0.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.0.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.0.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.1.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.1.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.1.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.1.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.1.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.1.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.1.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.1.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.1.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.1.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.1.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.1.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.1.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.1.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.1.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.1.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.1.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.1.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.1.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.2.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.2.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.2.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.2.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.2.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.2.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.2.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.2.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.2.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.2.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.2.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.2.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.2.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.2.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.2.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.2.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.2.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.2.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.2.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.3.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.3.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.3.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.3.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.3.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.3.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.3.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.3.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.3.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.3.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.3.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.3.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.3.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.3.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.3.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.3.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.3.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.3.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.3.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.4.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.4.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.4.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.4.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.4.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.4.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.4.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.4.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.4.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.4.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.4.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.4.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.4.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.4.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.4.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.4.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.4.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.4.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.4.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.5.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.5.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.5.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.5.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.5.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.5.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.5.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.5.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.5.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.5.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.5.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.5.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.5.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.5.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.5.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.5.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.5.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.5.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.5.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.6.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.6.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.6.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.6.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.6.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.6.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.6.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.6.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.6.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.6.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.6.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.6.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.6.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.6.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.6.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.6.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.6.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.6.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.6.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.7.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.7.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.7.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.7.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.7.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.7.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.7.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.7.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.7.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.7.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.7.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.7.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.7.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.7.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.7.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.7.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.7.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.7.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.7.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.8.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.8.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.8.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.8.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.8.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.8.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.8.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.8.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.8.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.8.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.8.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.8.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.8.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.8.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.8.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.8.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.8.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.8.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.8.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.9.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.9.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.9.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.9.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.9.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.9.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.9.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.9.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.9.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.9.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.9.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.9.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.9.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.9.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.9.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.9.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.9.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.9.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.9.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.10.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.10.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.10.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.10.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.10.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.10.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.10.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.10.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.10.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.10.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.10.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.10.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.10.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.10.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.10.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.10.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.10.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.10.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.10.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "blocks.11.cross_gate", "shape": [1], "numel": 1}, {"name": "blocks.11.attn.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.11.attn.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.11.attn.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.11.attn.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.11.attn.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.11.attn.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.11.cross.q.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.11.cross.q.bias", "shape": [384], "numel": 384}, {"name": "blocks.11.cross.kv.weight", "shape": [768, 384], "numel": 294912}, {"name": "blocks.11.cross.kv.bias", "shape": [768], "numel": 768}, {"name": "blocks.11.cross.proj.weight", "shape": [384, 384], "numel": 147456}, {"name": "blocks.11.cross.proj.bias", "shape": [384], "numel": 384}, {"name": "blocks.11.mlp.0.weight", "shape": [1536, 384], "numel": 589824}, {"name": "blocks.11.mlp.0.bias", "shape": [1536], "numel": 1536}, {"name": "blocks.11.mlp.2.weight", "shape": [384, 1536], "numel": 589824}, {"name": "blocks.11.mlp.2.bias", "shape": [384], "numel": 384}, {"name": "blocks.11.ada.1.weight", "shape": [2304, 384], "numel": 884736}, {"name": "blocks.11.ada.1.bias", "shape": [2304], "numel": 2304}, {"name": "ada_out.1.weight", "shape": [768, 384], "numel": 294912}, {"name": "ada_out.1.bias", "shape": [768], "numel": 768}, {"name": "head.weight", "shape": [16, 384], "numel": 6144}, {"name": "head.bias", "shape": [16], "numel": 16}], "total_parameters": 40013980, "side": 6326, "dtype": "float16", "channels": "R=hi,G=lo,B=unused", "step": 119999, "val_loss": 0.7852968573570251}
|
pixelmodel-v5-data.png
ADDED
|
|
pixelmodel-v5-loss.png
ADDED
|
|
pixelmodel-v5-val.png
ADDED
|
|
png_codec.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import argparse
|
| 4 |
+
import json
|
| 5 |
+
import math
|
| 6 |
+
import os
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
from PIL import Image
|
| 11 |
+
|
| 12 |
+
from dit import DiT
|
| 13 |
+
|
| 14 |
+
Image.MAX_IMAGE_PIXELS = None
|
| 15 |
+
|
| 16 |
+
def build(cfg):
|
| 17 |
+
return DiT(dim=cfg["dim"], depth=cfg["depth"], heads=cfg["heads"])
|
| 18 |
+
|
| 19 |
+
def encode(ckpt, png_path, cfg_path, dim=384, depth=12, heads=6, which="ema"):
|
| 20 |
+
ck = torch.load(ckpt, map_location="cpu")
|
| 21 |
+
cfg = {"dim": dim, "depth": depth, "heads": heads}
|
| 22 |
+
model = build(cfg)
|
| 23 |
+
model.load_state_dict(ck[which])
|
| 24 |
+
parts, manifest = [], []
|
| 25 |
+
for name, p in model.named_parameters():
|
| 26 |
+
a = p.detach().to(torch.float16).contiguous().view(-1).numpy()
|
| 27 |
+
parts.append(a)
|
| 28 |
+
manifest.append({"name": name, "shape": list(p.shape), "numel": int(a.size)})
|
| 29 |
+
flat = np.concatenate(parts)
|
| 30 |
+
N = flat.size
|
| 31 |
+
side = math.ceil(math.sqrt(N))
|
| 32 |
+
u16 = flat.view(np.uint16)
|
| 33 |
+
img = np.zeros((side * side, 3), dtype=np.uint8)
|
| 34 |
+
img[:N, 0] = (u16 >> 8).astype(np.uint8)
|
| 35 |
+
img[:N, 1] = (u16 & 0xFF).astype(np.uint8)
|
| 36 |
+
Image.fromarray(img.reshape(side, side, 3), "RGB").save(png_path)
|
| 37 |
+
json.dump({"cfg": cfg, "params": manifest, "total_parameters": int(N),
|
| 38 |
+
"side": side, "dtype": "float16", "channels": "R=hi,G=lo,B=unused",
|
| 39 |
+
"step": ck.get("step"), "val_loss": ck.get("val")},
|
| 40 |
+
open(cfg_path, "w"))
|
| 41 |
+
print(f"[png] encoded {N:,} params into a {side}x{side} PNG "
|
| 42 |
+
f"({os.path.getsize(png_path)/1e6:.1f} MB)")
|
| 43 |
+
return N, side
|
| 44 |
+
|
| 45 |
+
def load_model_png(png_path, cfg_path, device="cpu"):
|
| 46 |
+
meta = json.load(open(cfg_path))
|
| 47 |
+
model = build(meta["cfg"])
|
| 48 |
+
arr = np.asarray(Image.open(png_path).convert("RGB")).reshape(-1, 3)
|
| 49 |
+
total = meta["total_parameters"]
|
| 50 |
+
hi = arr[:total, 0].astype(np.uint16)
|
| 51 |
+
lo = arr[:total, 1].astype(np.uint16)
|
| 52 |
+
flat = ((hi << 8) | lo).astype(np.uint16).view(np.float16)
|
| 53 |
+
sd = dict(model.named_parameters())
|
| 54 |
+
off = 0
|
| 55 |
+
with torch.no_grad():
|
| 56 |
+
for m in meta["params"]:
|
| 57 |
+
n = m["numel"]
|
| 58 |
+
chunk = flat[off:off + n].astype(np.float16)
|
| 59 |
+
sd[m["name"]].copy_(torch.from_numpy(chunk.copy()).view(*m["shape"]).to(torch.float32))
|
| 60 |
+
off += n
|
| 61 |
+
return model.to(device).eval()
|
| 62 |
+
|
| 63 |
+
def verify(ckpt, png_path, cfg_path, which="ema"):
|
| 64 |
+
model = load_model_png(png_path, cfg_path)
|
| 65 |
+
ref = torch.load(ckpt, map_location="cpu")[which]
|
| 66 |
+
worst, name = 0.0, ""
|
| 67 |
+
for k, p in model.named_parameters():
|
| 68 |
+
d = (p.detach() - ref[k].float()).abs().max().item()
|
| 69 |
+
if d > worst:
|
| 70 |
+
worst, name = d, k
|
| 71 |
+
scale = max(1e-12, ref[name].float().abs().max().item())
|
| 72 |
+
print(f"[png] round-trip max abs error {worst:.3e} on {name} (relative {worst/scale:.2e})")
|
| 73 |
+
return worst
|
| 74 |
+
|
| 75 |
+
def main():
|
| 76 |
+
ap = argparse.ArgumentParser()
|
| 77 |
+
ap.add_argument("--ckpt", default="/root/runs/pm5/best.pt")
|
| 78 |
+
ap.add_argument("--png", default="model.png")
|
| 79 |
+
ap.add_argument("--manifest", default="model_png.json")
|
| 80 |
+
args = ap.parse_args()
|
| 81 |
+
encode(args.ckpt, args.png, args.manifest)
|
| 82 |
+
verify(args.ckpt, args.png, args.manifest)
|
| 83 |
+
|
| 84 |
+
if __name__ == "__main__":
|
| 85 |
+
main()
|
prep_v5.py
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, sys, io, gc, time, tarfile, argparse, numpy as np, torch
|
| 2 |
+
from concurrent.futures import ThreadPoolExecutor
|
| 3 |
+
from PIL import Image
|
| 4 |
+
from huggingface_hub import hf_hub_download
|
| 5 |
+
from diffusers import AutoencoderKL
|
| 6 |
+
from transformers import CLIPTokenizer
|
| 7 |
+
|
| 8 |
+
REPO = 'undefined443/cc12m-wds-coco-recaptioned'
|
| 9 |
+
OUT = '/root/v5data'
|
| 10 |
+
TMP = '/root/v5tmp'
|
| 11 |
+
SCALE = 0.18215
|
| 12 |
+
RES = 256
|
| 13 |
+
MAXTOK = 40
|
| 14 |
+
|
| 15 |
+
ap = argparse.ArgumentParser()
|
| 16 |
+
ap.add_argument('--start', type=int, default=0)
|
| 17 |
+
ap.add_argument('--end', type=int, default=598)
|
| 18 |
+
ap.add_argument('--batch', type=int, default=64)
|
| 19 |
+
args = ap.parse_args()
|
| 20 |
+
|
| 21 |
+
os.makedirs(OUT, exist_ok=True)
|
| 22 |
+
os.makedirs(TMP, exist_ok=True)
|
| 23 |
+
dev = 'cuda'
|
| 24 |
+
vae = AutoencoderKL.from_pretrained('stabilityai/sd-vae-ft-mse').to(dev).half().eval()
|
| 25 |
+
for p in vae.parameters():
|
| 26 |
+
p.requires_grad_(False)
|
| 27 |
+
tok = CLIPTokenizer.from_pretrained('openai/clip-vit-base-patch32')
|
| 28 |
+
|
| 29 |
+
def prep_img(raw):
|
| 30 |
+
try:
|
| 31 |
+
im = Image.open(io.BytesIO(raw)).convert('RGB')
|
| 32 |
+
except Exception:
|
| 33 |
+
return None
|
| 34 |
+
w, h = im.size
|
| 35 |
+
s = RES / min(w, h)
|
| 36 |
+
im = im.resize((max(RES, int(w * s + 0.5)), max(RES, int(h * s + 0.5))), Image.BICUBIC)
|
| 37 |
+
w, h = im.size
|
| 38 |
+
l, t = (w - RES) // 2, (h - RES) // 2
|
| 39 |
+
return np.asarray(im.crop((l, t, l + RES, t + RES)), dtype=np.uint8)
|
| 40 |
+
|
| 41 |
+
pool = ThreadPoolExecutor(16)
|
| 42 |
+
t_start = time.time()
|
| 43 |
+
done_total = 0
|
| 44 |
+
|
| 45 |
+
def fetch(si):
|
| 46 |
+
return hf_hub_download(REPO, f'cc12m-coco-{si:04d}.tar', repo_type='dataset', local_dir=TMP)
|
| 47 |
+
|
| 48 |
+
todo = [i for i in range(args.start, args.end) if not os.path.exists(f'{OUT}/shard_{i:04d}.npz')]
|
| 49 |
+
print(f'{len(todo)} shards to process', flush=True)
|
| 50 |
+
dl = ThreadPoolExecutor(2)
|
| 51 |
+
nxt = dl.submit(fetch, todo[0]) if todo else None
|
| 52 |
+
|
| 53 |
+
for k, si in enumerate(todo):
|
| 54 |
+
dst = f'{OUT}/shard_{si:04d}.npz'
|
| 55 |
+
try:
|
| 56 |
+
p = nxt.result()
|
| 57 |
+
except Exception as e:
|
| 58 |
+
print(f' shard {si} download failed: {type(e).__name__}', flush=True)
|
| 59 |
+
nxt = dl.submit(fetch, todo[k + 1]) if k + 1 < len(todo) else None
|
| 60 |
+
continue
|
| 61 |
+
nxt = dl.submit(fetch, todo[k + 1]) if k + 1 < len(todo) else None
|
| 62 |
+
|
| 63 |
+
pairs = {}
|
| 64 |
+
try:
|
| 65 |
+
with tarfile.open(p) as tf:
|
| 66 |
+
for m in tf:
|
| 67 |
+
if not m.isfile():
|
| 68 |
+
continue
|
| 69 |
+
key, _, ext = m.name.partition('.')
|
| 70 |
+
if ext == 'jpg':
|
| 71 |
+
pairs.setdefault(key, {})['img'] = tf.extractfile(m).read()
|
| 72 |
+
elif ext == 'txt':
|
| 73 |
+
pairs.setdefault(key, {})['cap'] = tf.extractfile(m).read().decode('utf-8', 'ignore').strip()
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f' shard {si} tar failed: {type(e).__name__}', flush=True)
|
| 76 |
+
os.remove(p); continue
|
| 77 |
+
os.remove(p)
|
| 78 |
+
|
| 79 |
+
items = [(v['img'], v['cap']) for v in pairs.values() if 'img' in v and 'cap' in v and v['cap']]
|
| 80 |
+
del pairs
|
| 81 |
+
if not items:
|
| 82 |
+
continue
|
| 83 |
+
|
| 84 |
+
lat_all, tok_all = [], []
|
| 85 |
+
for i in range(0, len(items), args.batch):
|
| 86 |
+
chunk = items[i:i + args.batch]
|
| 87 |
+
arrs = list(pool.map(prep_img, [c[0] for c in chunk]))
|
| 88 |
+
keep = [j for j, a in enumerate(arrs) if a is not None]
|
| 89 |
+
if not keep:
|
| 90 |
+
continue
|
| 91 |
+
x = np.stack([arrs[j] for j in keep])
|
| 92 |
+
t = torch.from_numpy(x).to(dev).half().permute(0, 3, 1, 2).div_(127.5).sub_(1.0)
|
| 93 |
+
with torch.no_grad():
|
| 94 |
+
lat = vae.encode(t).latent_dist.sample() * SCALE
|
| 95 |
+
lat_all.append(lat.cpu().numpy().astype(np.float16))
|
| 96 |
+
ids = tok([chunk[j][1] for j in keep], padding='max_length', max_length=MAXTOK,
|
| 97 |
+
truncation=True, return_tensors='np')['input_ids']
|
| 98 |
+
tok_all.append(ids.astype(np.int32))
|
| 99 |
+
|
| 100 |
+
if not lat_all:
|
| 101 |
+
continue
|
| 102 |
+
lat = np.concatenate(lat_all); ids = np.concatenate(tok_all)
|
| 103 |
+
np.savez(dst, latents=lat, tokens=ids)
|
| 104 |
+
done_total += len(lat)
|
| 105 |
+
el = time.time() - t_start
|
| 106 |
+
print(f' shard {si:04d}: {len(lat)} imgs total {done_total} {done_total/el:.0f} img/s '
|
| 107 |
+
f'{el/60:.1f} min elapsed', flush=True)
|
| 108 |
+
del lat_all, tok_all, lat, ids, items
|
| 109 |
+
gc.collect()
|
| 110 |
+
|
| 111 |
+
print('PREPDONE', done_total, flush=True)
|
train_v5.py
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 transformers import CLIPTextModel
|
| 15 |
+
|
| 16 |
+
from dit import DiT
|
| 17 |
+
|
| 18 |
+
def build_cache(data, cache):
|
| 19 |
+
shards = sorted(glob.glob(f"{data}/shard_*.npz"))
|
| 20 |
+
if not shards:
|
| 21 |
+
raise SystemExit(f"no shards in {data}")
|
| 22 |
+
lat, tok = [], []
|
| 23 |
+
for i, s in enumerate(shards):
|
| 24 |
+
z = np.load(s)
|
| 25 |
+
lat.append(z["latents"]); tok.append(z["tokens"])
|
| 26 |
+
if (i + 1) % 50 == 0:
|
| 27 |
+
print(f" loaded {i+1}/{len(shards)} shards", flush=True)
|
| 28 |
+
lat = np.concatenate(lat); tok = np.concatenate(tok)
|
| 29 |
+
np.save(f"{cache}_lat.npy", lat); np.save(f"{cache}_tok.npy", tok)
|
| 30 |
+
return lat, tok
|
| 31 |
+
|
| 32 |
+
def main():
|
| 33 |
+
ap = argparse.ArgumentParser()
|
| 34 |
+
ap.add_argument("--data", default="/root/v5data")
|
| 35 |
+
ap.add_argument("--cache", default="/root/v5cache")
|
| 36 |
+
ap.add_argument("--out", default="/root/runs/pm5")
|
| 37 |
+
ap.add_argument("--steps", type=int, default=120000)
|
| 38 |
+
ap.add_argument("--batch", type=int, default=256)
|
| 39 |
+
ap.add_argument("--lr", type=float, default=2e-4)
|
| 40 |
+
ap.add_argument("--warmup", type=int, default=1000)
|
| 41 |
+
ap.add_argument("--dim", type=int, default=384)
|
| 42 |
+
ap.add_argument("--depth", type=int, default=12)
|
| 43 |
+
ap.add_argument("--heads", type=int, default=6)
|
| 44 |
+
ap.add_argument("--cfg-dropout", type=float, default=0.1)
|
| 45 |
+
ap.add_argument("--ema", type=float, default=0.9999)
|
| 46 |
+
ap.add_argument("--val-size", type=int, default=4096)
|
| 47 |
+
ap.add_argument("--val-every", type=int, default=2000)
|
| 48 |
+
ap.add_argument("--log-every", type=int, default=200)
|
| 49 |
+
ap.add_argument("--save-every", type=int, default=5000)
|
| 50 |
+
ap.add_argument("--clip", default="openai/clip-vit-base-patch32")
|
| 51 |
+
ap.add_argument("--resume", default="")
|
| 52 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 53 |
+
args = ap.parse_args()
|
| 54 |
+
|
| 55 |
+
dev = "cuda"
|
| 56 |
+
os.makedirs(args.out, exist_ok=True)
|
| 57 |
+
torch.manual_seed(args.seed)
|
| 58 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 59 |
+
torch.backends.cudnn.allow_tf32 = True
|
| 60 |
+
|
| 61 |
+
if os.path.exists(f"{args.cache}_lat.npy"):
|
| 62 |
+
lat = np.load(f"{args.cache}_lat.npy", mmap_mode="r")
|
| 63 |
+
tok = np.load(f"{args.cache}_tok.npy")
|
| 64 |
+
else:
|
| 65 |
+
lat, tok = build_cache(args.data, args.cache)
|
| 66 |
+
|
| 67 |
+
N = len(lat)
|
| 68 |
+
perm = np.random.RandomState(args.seed).permutation(N)
|
| 69 |
+
val_i = np.sort(perm[:args.val_size])
|
| 70 |
+
tr_i = perm[args.val_size:]
|
| 71 |
+
print(f"[data] {N} pairs, {len(tr_i)} train, {len(val_i)} val", flush=True)
|
| 72 |
+
|
| 73 |
+
txt = CLIPTextModel.from_pretrained(args.clip).to(dev).eval()
|
| 74 |
+
for p in txt.parameters():
|
| 75 |
+
p.requires_grad_(False)
|
| 76 |
+
|
| 77 |
+
@torch.no_grad()
|
| 78 |
+
def encode(ids):
|
| 79 |
+
o = txt(input_ids=ids)
|
| 80 |
+
return o.last_hidden_state.float(), o.pooler_output.float()
|
| 81 |
+
|
| 82 |
+
null_ids = torch.full((1, tok.shape[1]), 0, dtype=torch.long, device=dev)
|
| 83 |
+
null_ids[0, 0] = 49406; null_ids[0, 1:] = 49407
|
| 84 |
+
null_seq, null_pool = encode(null_ids)
|
| 85 |
+
|
| 86 |
+
tok_t = torch.from_numpy(tok.astype(np.int64))
|
| 87 |
+
vlat = torch.from_numpy(np.asarray(lat[val_i])).float()
|
| 88 |
+
vseq, vpool = [], []
|
| 89 |
+
with torch.no_grad():
|
| 90 |
+
for i in range(0, len(val_i), 512):
|
| 91 |
+
s, p = encode(tok_t[val_i[i:i+512]].to(dev))
|
| 92 |
+
vseq.append(s); vpool.append(p)
|
| 93 |
+
vseq = torch.cat(vseq); vpool = torch.cat(vpool)
|
| 94 |
+
vg = torch.Generator(device=dev).manual_seed(1234)
|
| 95 |
+
vx1 = vlat.to(dev)
|
| 96 |
+
vx0 = torch.randn(vx1.shape, device=dev, generator=vg)
|
| 97 |
+
vt = torch.sigmoid(torch.randn(vx1.shape[0], device=dev, generator=vg))
|
| 98 |
+
|
| 99 |
+
model = DiT(dim=args.dim, depth=args.depth, heads=args.heads).to(dev)
|
| 100 |
+
ema = copy.deepcopy(model).eval()
|
| 101 |
+
for p in ema.parameters():
|
| 102 |
+
p.requires_grad_(False)
|
| 103 |
+
opt = torch.optim.AdamW(model.parameters(), lr=args.lr, betas=(0.9, 0.99), weight_decay=0.0)
|
| 104 |
+
print(f"[model] {sum(p.numel() for p in model.parameters())/1e6:.2f}M trainable", flush=True)
|
| 105 |
+
|
| 106 |
+
start, best = 0, float("inf")
|
| 107 |
+
if args.resume and os.path.exists(args.resume):
|
| 108 |
+
ck = torch.load(args.resume, map_location=dev)
|
| 109 |
+
model.load_state_dict(ck["model"]); ema.load_state_dict(ck["ema"])
|
| 110 |
+
opt.load_state_dict(ck["opt"]); start = ck["step"] + 1; best = ck.get("best", best)
|
| 111 |
+
|
| 112 |
+
def lr_at(s):
|
| 113 |
+
if s < args.warmup:
|
| 114 |
+
return args.lr * (s + 1) / args.warmup
|
| 115 |
+
p = (s - args.warmup) / max(1, args.steps - args.warmup)
|
| 116 |
+
return args.lr * (0.1 + 0.9 * 0.5 * (1 + math.cos(math.pi * min(1.0, p))))
|
| 117 |
+
|
| 118 |
+
@torch.no_grad()
|
| 119 |
+
def val_loss():
|
| 120 |
+
tot, n = 0.0, 0
|
| 121 |
+
for j in range(0, vx1.shape[0], args.batch):
|
| 122 |
+
sl = slice(j, j + args.batch)
|
| 123 |
+
m = vx1[sl].shape[0]
|
| 124 |
+
tb = vt[sl].view(-1, 1, 1, 1)
|
| 125 |
+
xt = (1 - tb) * vx0[sl] + tb * vx1[sl]
|
| 126 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 127 |
+
v = ema(xt, vt[sl], vseq[sl], vpool[sl])
|
| 128 |
+
tot += F.mse_loss(v.float(), vx1[sl] - vx0[sl]).item() * m
|
| 129 |
+
n += m
|
| 130 |
+
return tot / n
|
| 131 |
+
|
| 132 |
+
logf = open(f"{args.out}/log.jsonl", "a")
|
| 133 |
+
gen = torch.Generator(device=dev).manual_seed(args.seed)
|
| 134 |
+
run, t0 = 0.0, time.time()
|
| 135 |
+
for step in range(start, args.steps):
|
| 136 |
+
i = tr_i[np.random.randint(0, len(tr_i), args.batch)]
|
| 137 |
+
x1 = torch.from_numpy(np.asarray(lat[np.sort(i)])).to(dev).float()
|
| 138 |
+
seq, pool = encode(tok_t[np.sort(i)].to(dev))
|
| 139 |
+
drop = torch.rand(x1.shape[0], device=dev, generator=gen) < args.cfg_dropout
|
| 140 |
+
seq = torch.where(drop[:, None, None], null_seq, seq)
|
| 141 |
+
pool = torch.where(drop[:, None], null_pool, pool)
|
| 142 |
+
|
| 143 |
+
x0 = torch.randn(x1.shape, device=dev, generator=gen)
|
| 144 |
+
t = torch.sigmoid(torch.randn(x1.shape[0], device=dev, generator=gen))
|
| 145 |
+
tb = t.view(-1, 1, 1, 1)
|
| 146 |
+
xt = (1 - tb) * x0 + tb * x1
|
| 147 |
+
target = x1 - x0
|
| 148 |
+
|
| 149 |
+
for g in opt.param_groups:
|
| 150 |
+
g["lr"] = lr_at(step)
|
| 151 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 152 |
+
v = model(xt, t, seq, pool)
|
| 153 |
+
loss = F.mse_loss(v.float(), target)
|
| 154 |
+
opt.zero_grad(set_to_none=True)
|
| 155 |
+
loss.backward()
|
| 156 |
+
gn = torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
|
| 157 |
+
opt.step()
|
| 158 |
+
d = args.ema if step > args.warmup else 0.0
|
| 159 |
+
with torch.no_grad():
|
| 160 |
+
for pe, pm in zip(ema.parameters(), model.parameters()):
|
| 161 |
+
pe.mul_(d).add_(pm.detach(), alpha=1 - d)
|
| 162 |
+
for be, bm in zip(ema.buffers(), model.buffers()):
|
| 163 |
+
be.copy_(bm)
|
| 164 |
+
|
| 165 |
+
run += loss.item()
|
| 166 |
+
if (step + 1) % args.log_every == 0:
|
| 167 |
+
el = time.time() - t0
|
| 168 |
+
sps = args.log_every / el
|
| 169 |
+
print(f"[s{step+1:06d}] loss={run/args.log_every:.4f} lr={lr_at(step):.2e} "
|
| 170 |
+
f"gnorm={gn:.2f} {sps:.2f} steps/s eta={(args.steps-step-1)/sps/3600:.1f}h", flush=True)
|
| 171 |
+
logf.write(json.dumps({"step": step + 1, "loss": run / args.log_every,
|
| 172 |
+
"steps_per_s": sps}) + "\n"); logf.flush()
|
| 173 |
+
run, t0 = 0.0, time.time()
|
| 174 |
+
|
| 175 |
+
if (step + 1) % args.val_every == 0 or step + 1 == args.steps:
|
| 176 |
+
vl = val_loss()
|
| 177 |
+
tag = ""
|
| 178 |
+
if vl < best:
|
| 179 |
+
best = vl
|
| 180 |
+
torch.save({"ema": ema.state_dict(), "step": step, "val": vl}, f"{args.out}/best.pt")
|
| 181 |
+
tag = " *best*"
|
| 182 |
+
print(f"[s{step+1:06d}] val_loss={vl:.5f}{tag}", flush=True)
|
| 183 |
+
logf.write(json.dumps({"step": step + 1, "val_loss": vl}) + "\n"); logf.flush()
|
| 184 |
+
t0 = time.time()
|
| 185 |
+
|
| 186 |
+
if (step + 1) % args.save_every == 0 or step + 1 == args.steps:
|
| 187 |
+
torch.save({"model": model.state_dict(), "ema": ema.state_dict(), "opt": opt.state_dict(),
|
| 188 |
+
"step": step, "best": best}, f"{args.out}/latest.pt")
|
| 189 |
+
|
| 190 |
+
print("TRAINDONE best_val", best, flush=True)
|
| 191 |
+
|
| 192 |
+
if __name__ == "__main__":
|
| 193 |
+
main()
|