Views
No views yet
|
🏆 BenchLabs Leaderboard •
🌍 Tiny-T2I Leaderboard •
📝 Blog Post
|

model.png is not a picture of the model, it is the model. Every pixel encodes a
weight. At inference the PNG is decoded back into weight matrices, the prompt is
embedded, and a coordinate network paints an image at any resolution.train.py prints the
per layer activation statistics in the first few steps as a check.
| Metric | v1 | v2 | v3 |
|---|---|---|---|
| Parameters | 23,747 | ~200,000 | 919,427 |
| FID, published | 439.46 | not published | see below |
| CLIP, published | 20.02 | not published | see below |
| FID, this pipeline (lower better) | 420.75 | 390.68 | 383.91 |
| CLIP, this pipeline (higher better) | 20.10 | 20.48 | 20.73 |
model.png | 160x149 | scaled | 959x959 (1.78 MB) |
| Native resolution | 64 | 64 | 128 |
torchmetrics (FrechetInceptionDistance and CLIPScore with
openai/clip-vit-base-patch32), same eval subset and same library versions. The
eval images are hash checked to be disjoint from training.
1prompt string
2 lowercase / whitespace tokenize -> token ids (up to 20)
3 learned embedding table (3923 x 64), mean pool over real tokens [251,072]
4 Linear(64 -> 256) -> sin
5 Linear(256 -> 192) = latent z (192)
6
7FiLM generator (zero init, so scale=1 / shift=0 at start):
8 z -> Linear(192 -> 2 x 256 per sine layer) = (scale, shift) x4 [395,264]
9
10for every pixel (x, y), decoded as one batched tensor (no python loop):
11 Fourier features of (x, y): [x, y] plus sin/cos over 8 octaves = 34 dims
12 SineLayer 0: Linear(34 -> 256) -> FiLM -> sin(30 * .) (SIREN first layer)
13 SineLayer 1: Linear(256 -> 256) -> FiLM -> sin(30 * .)
14 SineLayer 2: Linear(256 -> 256) -> FiLM -> sin(30 * .)
15 SineLayer 3: Linear(256 -> 256) -> FiLM -> sin(30 * .)
16 head: Linear(256 -> 3) -> sigmoid = RGB--res 256 runs the same 919,427 weights as --res 64.| block | tensors | parameters |
|---|---|---|
| embedding table | embed.weight | 251,072 |
| text encoder | text_fc1, text_fc2 | 65,984 |
| FiLM generator | film | 395,264 |
| SIREN decoder | sine_layers.0..3 | 206,336 |
| RGB head | head | 771 |
| total | 919,427 |
model.safetensors holds the identical
weights in standard format with the full parameter breakdown in its header.1# build the train and eval data plus the vocabulary from COCO
2python fetch_coco_subset.py --out ../pm-work
3
4# train (writes model.png and config.json every epoch)
5python train.py --data ../pm-work/coco_train.npz --vocab ../pm-work/vocab.json \
6 --crop 128 --batch-size 32
7
8# inference from model.png (the canonical model)
9python main.py "a red double decker bus" --out bus.png
10
11# standalone inference from model.safetensors (needs only that file plus torch)
12python convert_to_safetensors.py
13python INFERENCE.py "a red double decker bus" --out bus.png
14
15# any resolution from the same weights
16python main.py "a beach with palm trees" --res 256
17
18# eval: FID and CLIP
19python eval/run_eval.py --arch v3 --work ../pm-work --n 5000
20
21# regression: re score v1 or v2 through the identical pipeline for a fair comparison
22python eval/run_eval.py --arch precomputed --work ../pm-work \
23 --images-dir v1_render/ --n 5000main.py (from model.png) and INFERENCE.py (from model.safetensors) produce
byte identical output for the same prompt and resolution.eval/run_eval.py rather than asserted.1model.png THE MODEL (959x959), produced by train.py
2model.safetensors same weights, standard format plus param metadata
3config.json architecture and parameter count metadata
4vocab.json word level tokenizer vocabulary, from fetch
5main.py inference, loads model.png
6INFERENCE.py inference, loads model.safetensors (standalone)
7convert_to_safetensors.py model.png to model.safetensors
8train.py training (AMP, cosine LR, per epoch PNG write)
9model.py architecture, tokenizer and PNG weight codec
10fetch_coco_subset.py builds train and eval data plus vocab from COCO
11eval/run_eval.py FID and CLIP Score via torchmetrics1uv venv --python 3.11 .venv
2# training
3uv pip install torch numpy pillow safetensors datasets
4# eval (FID and CLIP). torchmetrics CLIPScore breaks on transformers 5.x, so pin
5# transformers to 4.49.0 or the metric raises inside torchmetrics.
6uv pip install torchmetrics torchvision torch-fidelity scipy "transformers==4.49.0"fetch_coco_subset.py downloads the split before iterating rather than streaming
it, because a long streaming loop dies to dropped connections partway through.