GeoCore-9B
Towards Geo-Aware Generative Foundation Models in Earth Observation
Korea Advanced Institute of Science and Technology (KAIST)
A 9-billion-parameter generative foundation model for Earth Observation, trained from scratch exclusively on EO data. GeoCore-9B is a Flow Matching Diffusion Transformer that conditions generation on text and continuous geospatial metadata β ground sample distance (GSD), latitude and longitude.
2026-08-04 β corrected weights. The initial upload accidentally contained an EMA state that was never updated during training (pure initialization weights β see GitHub issue #2). The current files are the final 300K-step training weights, verified to load strictly and denoise correctly. If you downloaded the weights before this date, please re-download and check them against
SHA256SUMS.
Model details
| Parameters | 9.24 B |
| Weights | final training weights (non-EMA), bfloat16, sharded safetensors |
| Included | frozen Flux.2 VAE in vae/ (Apache-2.0, Black Forest Labs) |
| Architecture | Flow Matching DiT β 8 double-stream + 24 single-stream blocks, hidden 4096, 32 heads |
| Conditioning | CLIP + T5 text embeddings, GSD, latitude, longitude |
| Training data | Git-10M |
| Training | 300K steps, global batch 1024, AdamW lr 1e-4, bf16, DeepSpeed ZeRO-2, 8x B200 |
| Resolution | 256x256 |
Training used a Geospatial Semantic Alignment (GSA) loss that aligns intermediate DiT features
(block 8) with a frozen DINOv3-Sat teacher, weighted by mu = 0.5. GSA is training-only β the
teacher and projection head are not needed for inference, and the exported weights add no overhead.
Usage
These weights use a custom Flux2 architecture, so load them with the model definition from the
GitHub repository rather than a stock diffusers pipeline.
import torch
from huggingface_hub import snapshot_download
from models.flux2 import Flux2, GeoCore9BParams
from inference import load_state_dict
path = snapshot_download("JeonghyeokDo/GeoCore-9B")
model = Flux2(GeoCore9BParams()).to("cuda", torch.bfloat16)
model.load_state_dict(load_state_dict(path), strict=True)
model.eval()
Sampling, including the Euler flow-matching sampler and classifier-free guidance over both text and
metadata, is provided by inference.py:
python inference.py \
--ckpt /path/to/GeoCore-9B \
--vae /path/to/GeoCore-9B/vae \
--prompt "A satellite view of a highly dense urban city with towering skyscrapers" \
--lon 126.97 --lat 37.56 --res 0.0 \
--num-samples 4 --out samples/
Conditioning inputs
resβ resolution index, defined as17 - zfor Google XYZ tile zoomz.res = 0is roughly 1.2 m/px at the equator; each+1doubles the GSD.lon,latβ degrees.- Any field set to
-999.0falls back to the model's learned null embedding for that field, so metadata is fully optional.
The frozen VAE is included
vae/ in this repository holds the frozen Flux.2 autoencoder that encodes and decodes the latents,
so snapshot_download gives you everything the model needs:
python inference.py --ckpt /path/to/GeoCore-9B --vae /path/to/GeoCore-9B/vae ...
models/vae_flux2.py reads it directly (load_autoencoder), and vae/config.json is included so
diffusers >= 0.37 can load it too:
from diffusers import AutoencoderKLFlux2
vae = AutoencoderKLFlux2.from_pretrained("JeonghyeokDo/GeoCore-9B", subfolder="vae")
CLIP and T5 text encoders are still downloaded from the Hub at runtime.
Do not substitute
ae.safetensorsfromFLUX.2-dev. It holds the same autoencoder weights, but under the FLUX Non-Commercial License v2.1, whose Β§4(a)(iii) forbids "surveillance purposes, including all research and development related to surveillance" β a clause that Earth-observation work should not have to argue about. The copy shipped here is Apache-2.0, and the two were verified identical by pairing every tensor on value: 250 of 251 pair one-to-one with a worst deviation of 7.802e-03 (bf16 rounding); the odd one out is a BatchNorm step counter. In bf16, the precision this model runs in, latents and reconstructions are bit-identical.
Limitations
- Trained on 256x256 RGB optical imagery; other resolutions and sensor modalities require adaptation.
- Git-10M coverage is uneven across the globe, so generation quality varies by region.
- Geospatial conditioning reflects correlations in the training corpus and is not a substitute for real observations of a location.
License and attribution
GeoCore-9B is released under Apache-2.0, and so is every weight needed to run it.
model-*.safetensors (the 9.24B DiT) β Copyright 2026 Jeonghyeok Do and Munchurl Kim,
Apache-2.0. Trained from scratch on Git-10M; not derived from any FLUX checkpoint.
vae/ (the frozen 84M autoencoder) β Copyright Black Forest Labs, Apache-2.0. This is an
unmodified, byte-identical redistribution of
black-forest-labs/FLUX.2-klein-base-4B
vae/diffusion_pytorch_model.safetensors and its vae/config.json, bundled here only so the model
is usable in one download. Verify it against upstream:
sha256 ca70d2202afe6415bdbcb8793ba8cd99fd159cfe6192381504d6c4d3036e0f04 vae/diffusion_pytorch_model.safetensors
sha256 0d6dfb69ae95a5e2ac9836284bbb63d8b38ce67b25ba2dff380752b2a10ab948 vae/config.json
Those digests are the upstream files' own. A copy of the Apache License 2.0 as distributed with
that model is included as LICENSE-FLUX2-VAE.md. Black Forest Labs neither
endorses nor is affiliated with GeoCore-9B; the attribution above is a statement of origin, not of
sponsorship.
The Git-10M training corpus is CC BY-NC-ND 4.0, which restricts (re)training on that data to non-commercial use.
Citation
@article{do2026geocore,
title = {GeoCore-9B: Towards Geo-Aware Generative Foundation Models in Earth Observation},
author = {Do, Jeonghyeok and Kim, Munchurl},
year = {2026}
}
- Downloads last month
- 34