File size: 9,319 Bytes
d39ef9e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
---
license: other
license_name: mixed-see-model-card
pipeline_tag: image-to-image
library_name: diffusers
base_model: black-forest-labs/FLUX.2-klein-base-4B
tags:
  - sar-to-eo
  - remote-sensing
  - synthetic-aperture-radar
  - flow-matching
  - image-to-image
  - lora
  - arxiv:2609.37496
---

# GeoSET

GeoSET is a generalist foundation model for SAR-to-EO image translation (SET). A pretrained text-to-image flow
transformer is repurposed for SAR conditioning: the text stream is replaced by a spatial SAR stream fed by a
speckle-robust SAR encoder, and the generator is pretrained on 3,204,744 curated SAR–EO pairs spanning diverse
sensors, spatial resolutions and ground sampling distances. The resulting parent is adapted to downstream
datasets by low-rank adaptation (LoRA), updating 0.60% of the generator parameters, or by full fine-tuning.

- **Paper:** https://arxiv.org/abs/2609.37496
- **Code:** https://github.com/KAIST-VICLab/GeoSET
- **Project page:** https://kaist-viclab.github.io/GeoSET_site/
- **Comparison-method weights:** [`baselines/`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/baselines) in this repository: the sixteen prior methods of the paper's Tables 2 and 3 on the four public benchmarks

## Files

| Folder | Content | Size | Licence |
|---|---|---:|---|
| [`generalist/transformer`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/generalist/transformer) | `GeoSETTransformer2DModel`, Stage 2 generalist (500,000 updates, EMA), 3.852B parameters, float32 | 15.41 GB | CC BY-NC-SA 4.0 |
| [`generalist/sar_encoder`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/generalist/sar_encoder) | `GeoSETSAREncoder`, Stage 1 speckle-robust SAR encoder (50,000 updates) | 137.7 MB | CC BY-NC-SA 4.0 |
| [`generalist/vae`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/generalist/vae) | `AutoencoderFlux2`, the frozen FLUX.2-klein-base-4B autoencoder converted to float32 | 336.2 MB | Apache-2.0 |
| [`lora/<dataset>`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/lora) | one LoRA adapter per benchmark (rank 16, α 16, 23.10M parameters, EMA after 20,000 updates at batch size 16) | 92.4 MB each | CC BY-NC-SA 4.0 |
| [`baselines/<dataset>/<method>`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/baselines) | 61 retrained comparison-method checkpoints | – | per method |

`generalist/` is a complete `diffusers` pipeline: `model_index.json`, the three model folders, `scheduler/`
and the pipeline code (`pipeline.py`). The same code files are also at the repository root and under
`src/geoset/` on GitHub. The full fine-tuned models are not released; the code that produces them is on GitHub.

## Usage

```python
import torch
from PIL import Image
from diffusers import DiffusionPipeline
from huggingface_hub import snapshot_download

root = snapshot_download("JeonghyeokDo/GeoSET", allow_patterns=["generalist/*", "lora/sar2opt/*"])
pipe = DiffusionPipeline.from_pretrained(f"{root}/generalist", custom_pipeline=f"{root}/generalist",
                                         torch_dtype=torch.float32).to("cuda")
pipe.load_lora("sar2opt")                                   # optional; resolved from {root}/lora/sar2opt
eo = pipe(Image.open("sar.png"), num_inference_steps=50, guidance_scale=2.0,
          generator=torch.Generator("cuda").manual_seed(20260812)).images[0]
eo.save("eo.png")
```

`custom_pipeline` points at the same folder because the pipeline, model and scheduler classes ship with the
checkpoint. Keep `torch_dtype=torch.float32`; the pipeline casts the autoencoder to bfloat16 itself. The
input is an 8-bit SAR image, read as one channel, or a list of equally sized images; every side must be a
multiple of 16. Images are not resized or cropped inside the pipeline, so SAR2Opt tiles (600 × 600) are
center-cropped to 512 × 512 first. The paper's results use **50 integration steps with two-pass classifier-free guidance of
weight 2.0**.

## LoRA adapters

| Adapter | Benchmark | Test pairs | Input size |
|---|---|---:|---|
| [`lora/qxs-saropt`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/lora/qxs-saropt) | QXS-SAROPT | 3,999 | 256 × 256 |
| [`lora/sar2opt`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/lora/sar2opt) | SAR2Opt | 627 | center 512 × 512 crop of the 600 × 600 tiles |
| [`lora/sar2eo`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/lora/sar2eo) | SAR2EO | first 4,000 of the 21,260 test pairs | 256 × 256 |
| [`lora/spacenet6`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/lora/spacenet6) | SpaceNet6 | 495 | 256 × 256 |

`pipe.load_lora(name)` merges one adapter into the transformer weights (`name` is one of the four keys above,
or the path of an adapter directory). Without it, the pipeline runs the pretrained generalist. An adapter is
merged once; load the pipeline again to switch to another one. The frozen train/test lists, the dataset
preparation and `scripts/translate.py`, which translates a whole test split, are in the
[GitHub repository](https://github.com/KAIST-VICLab/GeoSET). Metrics of every checkpoint are in
[MODEL_ZOO.md](https://github.com/KAIST-VICLab/GeoSET/blob/main/MODEL_ZOO.md).

## Training

All stages train on 256 × 256 crops with AdamW and a gradient-norm clip of 1.0.

| | Stage 1 | Stage 2 | Stage 3, LoRA | Stage 3, full FT |
|---|---|---|---|---|
| Trained | SAR encoder | all 3.852B generator parameters | 23.10M adapter parameters (0.60%) | all 3.852B generator parameters |
| Updates × global batch size | 50,000 × 432 | 500,000 × 256 | 20,000 × 16 | 20,000 × 16 |
| Learning rate | 10⁻⁵, 500-update warmup | 10⁻⁴ peak, 1,000-update warmup | 10⁻⁴ | 2 × 10⁻⁵ |
| Hardware, time | 4 × NVIDIA B200, 14.8 h | 4 × NVIDIA B200, 129.3 h | 1 GPU, 0.98 h per dataset | 1 GPU, 1.34 h per dataset |

Stage 1 trains the SAR encoder, initialised from the FLUX.2-klein-base-4B autoencoder encoder, to reconstruct
SAR observations from speckle-perturbed copies through the frozen decoder. Stage 2 initialises the generator
from FLUX.2-klein-base-4B, copies the image-stream parameters into the SAR stream, and learns conditional flow
matching from Gaussian noise to the EO latent; the SAR condition is dropped with probability 0.1 so that
two-pass classifier-free guidance can be used at inference. Stages 2 and 3 keep an EMA with decay 0.9999, and
the released weights are the EMA parameters.

**Training data.** Pretraining: GUSO, TerraMesh, SARLO-80, SAR-1M and 3MOS, selected by the keep tables
published on GitHub (`corpus/keep_v1/`). Adaptation: the training splits of QXS-SAROPT, SAR2Opt, SAR2EO and
SpaceNet6. No dataset is redistributed here.

## Comparison methods, in this same repository

`baselines/` holds the sixteen prior methods of the paper's Tables 2 and 3, retrained on the same training
splits and evaluated on the same test pairs: 61 checkpoints, one folder per dataset and method (Seg-CycleGAN on
SpaceNet6 only), each with its own card and licence. Start at
[`baselines/README.md`](https://huggingface.co/JeonghyeokDo/GeoSET/blob/main/baselines/README.md); the
training and inference code is in
[`baselines/`](https://github.com/KAIST-VICLab/GeoSET/tree/main/baselines) on GitHub.

```bash
hf download JeonghyeokDo/GeoSET --include "baselines/sar2opt/c-diffset/*" --local-dir hf
```

## Licences

**This repository is mixed-licence, so the Hub tag is `other`.**

- **GeoSET weights** (`generalist/transformer`, `generalist/sar_encoder`, `lora/`):
  [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/).
- **Autoencoder** (`generalist/vae`): the FLUX.2-klein-base-4B autoencoder of Black Forest Labs, converted to
  float32, under [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0).
- **Code** (the `.py` files here and the GitHub repository): Apache-2.0. The transformer and autoencoder code is
  adapted from [black-forest-labs/flux2](https://github.com/black-forest-labs/flux2) (Apache-2.0).
- **Comparison methods** (`baselines/`): the terms of the code each was trained with; the texts are in
  [`baselines/licenses/`](https://huggingface.co/JeonghyeokDo/GeoSET/tree/main/baselines/licenses). Check the
  method you intend to use; the repository-level tag is not a substitute.

The generator is initialised from
[FLUX.2-klein-base-4B](https://huggingface.co/black-forest-labs/FLUX.2-klein-base-4B) (Apache-2.0). GeoSET is
not a FLUX product and is not endorsed by Black Forest Labs. See
[LICENSE-WEIGHTS.md](https://github.com/KAIST-VICLab/GeoSET/blob/main/LICENSE-WEIGHTS.md) and
[NOTICE](https://github.com/KAIST-VICLab/GeoSET/blob/main/NOTICE) on GitHub.

## Citation

```bibtex
@article{do2026geoset,
  title={GeoSET: Generalist Foundation Model for SAR-to-EO Image Translation},
  author={Do, Jeonghyeok and Kim, Munchurl},
  journal={arXiv preprint arXiv:2609.37496},
  year={2026}
}
```

Our prior work on SAR-to-EO image translation, [C-DiffSET](https://github.com/KAIST-VICLab/C-DiffSET):

```bibtex
@article{do2026cdiffset,
  title={C-diffset: Leveraging latent diffusion for sar-to-eo image translation with confidence-guided reliable object generation},
  author={Do, Jeonghyeok and Lee, Jaehyup and Lee, Seungchul and Kim, Munchurl},
  journal={IEEE Transactions on Circuits and Systems for Video Technology},
  year={2026},
  publisher={IEEE}
}
```