| # Reproducing the eval.md numbers | |
| Step-by-step guide to reproduce the FID / CLIP Score numbers in `eval.md` from | |
| scratch. Unlike v0 (whose eval scripts lived in a throwaway env), everything | |
| needed is **in this repo**: `fetch_coco_subset.py` builds the data, | |
| `eval/run_eval.py` computes the metrics with torchmetrics. | |
| CPU-only is fine (that's how the published numbers were produced). Budget | |
| ~7 GB disk: ~5 GB dataset shards + ~2 GB python deps and model weights | |
| (InceptionV3, CLIP ViT-B/32). | |
| ## 1. Environment | |
| ```bash | |
| python3.13 -m venv eval-venv | |
| # Windows: eval-venv\Scripts\activate macOS/Linux: source eval-venv/bin/activate | |
| pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu | |
| pip install torchmetrics torch-fidelity transformers "datasets<3" safetensors pillow numpy | |
| ``` | |
| `torch-fidelity` is the backend torchmetrics uses for the FID InceptionV3 | |
| features; `transformers` backs the CLIPScore metric. | |
| ## 2. Build the data (train + eval split) | |
| ```bash | |
| python fetch_coco_subset.py --out ../pm-work | |
| ``` | |
| This streams [`sayakpaul/coco-30-val-2014`](https://huggingface.co/datasets/sayakpaul/coco-30-val-2014) | |
| (a public 30K-pair subset of MS-COCO val2014) and produces: | |
| - `eval_real/` β stream rows 0β4999: real images, 256Γ256 center-crop JPEG (FID real set) | |
| - `eval_captions.json` β the 5,000 captions for those rows (generation + CLIP Score) | |
| - `coco_train.npz` + `coco_train.captions.json` β training pairs from stream | |
| rows 10,000+, at 64Γ64 | |
| **Leakage control:** the same COCO image appears in multiple rows with | |
| different captions, so training rows are dropped if their image content hash | |
| (md5 of a 64Γ64 bilinear thumbnail) appears in the eval set, and deduped | |
| against each other. The counts printed at the end of the script report both. | |
| Streaming row-by-row from the Hub is slow (~hours on a normal connection). The | |
| much faster path is to download the 10 parquet shards first (~4.9 GB), then: | |
| ```bash | |
| python fetch_coco_subset.py --out ../pm-work --parquet-dir ../pm-work/shards | |
| ``` | |
| Sorted shard filename order equals hub streaming order, so both paths produce | |
| identical splits. | |
| ## 3. (Optional) retrain | |
| ```bash | |
| python train.py --data ../pm-work/coco_train.npz --epochs 50 | |
| ``` | |
| Deterministic given `--seed` (default 0): same data + same seed reproduces the | |
| published `model.png` up to floating-point ordering. Skip this step to | |
| evaluate the shipped `model.png` as-is. | |
| ## 4. Run the eval | |
| ```bash | |
| python eval/run_eval.py --work ../pm-work --model model.png --n 5000 | |
| ``` | |
| This: | |
| 1. Generates one 64Γ64 image per eval caption (native resolution β no | |
| upscaling before metrics). | |
| 2. **FID** via `torchmetrics.image.fid.FrechetInceptionDistance` | |
| (`feature=2048`, InceptionV3 pool3): real = 5,000 COCO val2014 images at | |
| 256Γ256 center-crop, fake = the 5,000 generated 64Γ64 images. The metric's | |
| Inception backbone resizes both sets to 299Γ299 internally. | |
| 3. **CLIP Score** via `torchmetrics.multimodal.CLIPScore` with | |
| `openai/clip-vit-base-patch32` (the leaderboard default): each generated | |
| image against the caption that produced it, averaged. | |
| Results are printed and written to `eval_results.json` in the `--work` dir. | |
| First run downloads InceptionV3 (~95 MB) and CLIP ViT-B/32 (~600 MB). | |
| ## Notes | |
| - n=5000 vs the standard n=30000: FID's 2048-dim covariance estimate benefits | |
| from more samples; n=5000 was chosen as a compromise that is far past the | |
| singular-covariance regime that made v0's n=40 number directional-only, | |
| while staying CPU-friendly. Raising `--n` (and `EVAL_N` in | |
| `fetch_coco_subset.py`) toward 30K tightens the estimate at proportional | |
| cost β but note this dataset has 30K *rows*, not 30K unique images, and | |
| rows past index 10,000 are used for training, so a larger eval set requires | |
| re-splitting. | |
| - The generated set's resolution (64Γ64) is reported as the native generation | |
| resolution per the leaderboard rules; FID/CLIP preprocessing upsamples | |
| internally as part of the metric, not as part of generation. | |
| - `INFERENCE.py` (safetensors) and `main.py` (model.png) are verified | |
| byte-identical, so either weights file reproduces the same metrics. | |