George Plessias (@Redmonkeycloud) · supervised by Ioannis Kakogeorgiou (@gkakogeorgiou)
MSc thesis, MSc in Artificial Intelligence, University of Piraeus and NCSR "Demokritos"
TerraDiT-Ω-XL, 100 Euler steps, same tiles and noise: fp32 (top) vs bf16 autocast (bottom). Mean PSNR 54.2 dB; bf16 is 1.7× faster on an RTX 3060 (6.3 vs 10.8 s per image).
EO-TTS studies test-time scaling for Earth observation diffusion transformers: inference-only search (Best-of-N, then particle-based search with Rollover Budget Forcing) over pretrained satellite image generators, guided by remote-sensing verifiers.
All experiments build on TerraDiT-Ω-XL by Wei, Sastry, Cher, Xing and Jacobs
(Multimodal Vision Research Lab, Washington University in St. Louis). Their code is pinned
here as a git submodule at commit 8d90f0d and used unmodified.
| Link | |
|---|---|
| Paper (TerraDiT-Ω, ECCV 2026) | arXiv:2606.31029 · project page |
| Paper (TerraDiT-α/Σ) | arXiv:2603.02172 · project page |
| Code | github.com/mvrl/TerraDiT |
| Weights | huggingface.co/MVRL/TerraDiT |
| Derived data and test splits | huggingface.co/datasets/MVRL/TerraDiT-data |
| Imagery (Git-10M) | huggingface.co/datasets/lcybuaa/Git-10M |
If you use this repository, please cite their work:
@inproceedings{wei2026terraditomega,
title = {TerraDiT-{\Omega}: Unified Spatial Control for Satellite Image Synthesis with Any Geospatial Primitive},
author = {Wei, Brian and Sastry, Srikumar and Cher, Daniel and Xing, Eric and Jacobs, Nathan},
booktitle = {European Conference on Computer Vision},
year = {2026}
}
@article{sastry2026terradit,
title = {TerraDiT: Point-Conditioned Diffusion Transformer for Satellite Image Synthesis},
author = {Sastry, Srikumar and Cher, Daniel and Wei, Brian and Dhakal, Aayush and Khanal, Subash and Gupta, Dev and Jacobs, Nathan},
journal = {arXiv:2603.02172},
year = {2026}
}| Stage | State |
|---|---|
| Paper-protocol baseline, TerraDiT-Ω-XL, Git-Rand | done: FID 9.81 vs 9.25 in the paper (details) |
| Experiment protocol for Best-of-N, fixed before any run | done (protocol) |
| Best-of-N on 2,000 Git-Rand tiles, N ∈ {1, 2, 4, 8, 16}, 2 verifiers | generating (started 2026-10-30) |
| Best-of-N on 500 Git-Spatial tiles (held-out region), with fp32 anchor | queued after R2000 |
| Full Git-Spatial baseline | not run; Spatial is used as a held-out test set for search (why) |
| Best verifier on the full Git-Rand split, N = 4 | after the subset results |
| Rollover Budget Forcing with custom allocation rules | later |
TerraDiT-Ω-XL re-run with the authors' code and weights on the full Git-Rand split (14,932 tiles, 100 Euler steps, no guidance, batch 32, seed 42, fp32):
| Metric | Ours | Paper | Ours − paper |
|---|---|---|---|
| FID ↓ | 9.81 | 9.25 | +0.56 |
| LPIPS ↓ | 0.3401 | 0.3438 | −0.0037 |
| SSIM ↑ | 0.2669 | 0.2665 | +0.0004 |
| CLIP score (cosine) ↑ | 0.2882 | 0.2812 | +0.0070 |
| KID ×10³ ↓ | 3.98 ± 0.41 | not reported | – |
The per-image metrics match the paper; FID is 6 % higher. What each metric measures, what the paper leaves unstated, and the likely reasons for the gap (fp16 release weights, seed, software and hardware) are in docs/baseline_reproduction.md. Raw output: results/baseline/omega_xl_random_omega.json. All later experiments are compared against this re-run.
The baseline calls TerraDiT's own generate.py and eval/metrics.py in-process. The only
substitution is where imagery comes from: instead of downloading all of Git-10M (394 GB,
787 shards), Git10MSubset keeps exactly the rows a test split uses, checked against the
split metadata by img_name, so pixels and captions are byte-identical.
| Split | Tiles | Git-10M shards needed | Download |
|---|---|---|---|
| random | 14,932 | 151 of 787 | 29.3 GB |
| spatial | 14,387 | 2 of 787 | 0.3 GB |
Shards are fetched one at a time and deleted after extraction; the stored subset is ~0.2 GB per split.
Paper targets (TerraDiT-Ω-XL, condition Ω, from Table 1 and Table S3 of arXiv:2606.31029) are in
configs/paper_targets.json; every result file stores them next to our numbers.
| Split | FID ↓ | LPIPS ↓ | SSIM ↑ | CLIP (cos) ↑ |
|---|---|---|---|---|
| random | 9.25 | 0.3438 | 0.2665 | 0.2812 |
| spatial | 17.54 | 0.3614 | 0.3421 | 0.2761 |
Differences between the paper's stated protocol and the released code, recorded in each result:
- Batch size: the paper says 32, the repo defaults to 16. Noise is drawn per batch, so
this changes individual samples, not the distribution. Use
--batch-size 32if it fits. - Seed: not reported in the paper; we use the repo default, 42.
- CLIP: the repo's
metrics.pyreports the CLIP logit (cosine × 100); the paper reports cosine. Results carry bothclip_scoreandclip_cos. - sFID: in the paper, not computed by the repo; not reported here.
- KID: not in the paper; added because it is unbiased on small subsets (Best-of-N).
git clone --recursive https://github.com/Redmonkeycloud/eo-tts.git
cd eo-tts
conda create -n eotts python=3.11 -y
conda activate eotts
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu124
pip install -e "third_party/TerraDiT[eval]"
pip install -e ".[dev]"
huggingface-cli login # optional, avoids Hub rate limits on the 29 GB download
python scripts/00_check_env.pyIf you cloned without --recursive: git submodule update --init.
python scripts/01_download_assets.py # omega_xl weights + test split files (~2.5 GB)
python scripts/02_build_git10m_subset.py --split spatial # ~0.3 GB, about a minute
python scripts/03_benchmark.py # speed, VRAM, fp32 vs bf16 (~10 min)
python scripts/04_run_baseline.py --split spatial --limit 64 # smoke test
python scripts/02_build_git10m_subset.py --split random # ~29 GB download, resumable
python scripts/04_run_baseline.py --split random # the paper number (long run, resumable)
python scripts/04_run_baseline.py --split spatialGeneration resumes from the images already on disk, so an interrupted run is restarted with
the same command. Results land in runs/baseline/<run>/results.json.
Fixed in advance by docs/experiment_protocol.md. GPU hours are on an RTX 3060.
python scripts/05_generate_bon.py --set S500 --limit-tiles 2 # smoke test, a few minutes
python scripts/05_generate_bon.py --set R2000 # 32,000 samples, bf16, ~56 h
python scripts/05_generate_bon.py --set S500 # 8,000 samples, bf16, ~14 h
python scripts/05_generate_bon.py --set S500 --anchor-fp32 # sample 0 in fp32, same noise, ~1.6 h
python scripts/06_score_bon.py --run R2000
python scripts/06_score_bon.py --run S500
python scripts/06_score_bon.py --run S500_fp32_k0
python scripts/06_score_bon.py --run R2000_baseline_fp32 # the fp32 baseline images on R2000 (anchors 1-2)
python scripts/07_analyze_bon.py # -> results/bon/report.mdEvery step resumes after an interruption. Each sample has its own seed, derived from (split, tile, sample index), so a sample is identical however and whenever it is generated.
configs/paper_targets.json paper numbers we compare against
docs/baseline_reproduction.md baseline results, metric definitions, gap analysis
docs/experiment_protocol.md Best-of-N questions, tiles, verifiers, endpoints, statistics (pre-registered)
configs/subsets/ fixed evaluation tile lists and their representativeness statistics
eotts/data/subsets.py how the subsets are drawn and checked
eotts/bon/ Best-of-N: sets and seeds, generation, selection rules, analysis, report
eotts/scoring/ verifiers (V1, V2) and evaluators (E1-E5)
eotts/stats/ KID from features, paired bootstrap, Holm
results/ result files of finished runs (images stay local)
eotts/data/git10m_subset.py exact local subset of Git-10M (shard math, verify, read)
eotts/baselines/ paper-protocol baseline runner
eotts/eval/kid.py KID (extra metric for small subsets)
eotts/provenance.py code versions, environment, GPU, written into every result
scripts/00..07 the steps above, in order
third_party/TerraDiT upstream code, pinned, unmodified
tests/ subset builder, statistics and selection tests (no GPU, no network)
Code licence for this repo: to be decided. TerraDiT code is Apache-2.0; its weights are CC-BY-NC-4.0 and Git-10M imagery is CC-BY-NC-ND-4.0, so this work is non-commercial research only. Git-10M data is never redistributed by this repo; it is downloaded from the original repository.
