JeonghyeokDo's picture
Upload folder using huggingface_hub
bf48bd4 verified
|
Raw
History Blame Contribute Delete
9.28 kB
# Conditional Diffusion — SAR2Opt
**Conditional Diffusion for SAR to Optical Image Translation**, Bai, Pu and Xu,
*IEEE Geoscience and Remote Sensing Letters*, 2023
([doi:10.1109/LGRS.2023.3337143](https://doi.org/10.1109/LGRS.2023.3337143); the
year is the one in the authors' own citation block — a table that labels this
row with a later issue year is referring to the same paper).
Upstream code:
[`Coordi777/Conditional-Diffusion-for-SAR-to-Optical-Image-Translation`](https://github.com/Coordi777/Conditional-Diffusion-for-SAR-to-Optical-Image-Translation),
a modified copy of [`openai/guided-diffusion`](https://github.com/openai/guided-diffusion).
**The exact upstream commit is not recoverable** — see the licence section.
This is the pixel-space conditional diffusion model we retrained ourselves on
SAR2Opt, and it is the checkpoint behind the Conditional Diffusion row of the
ReFlowSET comparison table.
## What is in this folder
| file | bytes | what it is |
|---|---|---|
| `ema_final.pt` | 662,459,343 | EMA (decay 0.9999) of the UNet at update 50,000 — a **bare state dict**, no wrapper key |
`ema_final.pt` is the EMA of a **164.3 M-parameter guided-diffusion UNet**:
`num_channels` 128, `num_res_blocks` 3, `learn_sigma` **False**, attention at
resolutions 16 and 8. It is a plain `state_dict` — load it directly, with no
`['model']` or `['ema']` indirection.
The QXS-SAROPT and SAR2Opt files differ in size (657,495,287 vs 662,459,343
bytes) purely because of the 256 px versus 512 px positional and attention
buffers; the parameter count is otherwise the same.
**Conditioning.** The SAR image is concatenated to the noisy state **noise-free**
at every reverse step and at training time — that is the paper's claim, and the
code does exactly that.
## Training budget we used
| | |
|---|---|
| **generator updates released** | **50,000** |
| batch size / resolution | 6 @ 512 px |
| optimizer | Adam, **constant** lr 1e-4 with `--lr_anneal_steps 50000` (linear decay to zero, which is also the only stop mechanism in the released code) |
| EMA | decay 0.9999 |
| diffusion | T = 2,000, linear β schedule, eps-prediction, `learn_sigma` False |
| sampler (test) | **respaced DDPM, 250 steps**, `clip_denoised` on |
| augmentation | none — the released code has none |
| input | deterministic centre 512 crops of the 600 px tiles |
**The paper and the released code disagree about the learning-rate schedule.**
The paper describes warmup plus cosine; the released code implements neither. We
ran the code.
## Measured on the SAR2Opt test set (n = 627, 512 px)
| FID↓ | DISTS↓ | LPIPS↓ | SSIM↑ | PSNR↑ |
|---|---|---|---|---|
| 211.8 | 0.415 | 0.686 | 0.248 | 12.48 |
Evaluated on the official split's 627 test tiles, centre-cropped to 512 px.
The tiles are 600 px natively; this benchmark crops and never resizes, in every
method's training and in the evaluation. No subsampling: every metric on this
page is measured over all 627 pairs.
These are our own re-evaluation numbers, measured by us on the images this
checkpoint produced. **No number here is copied from any paper.** PSNR and SSIM
are per-image torchmetrics with `data_range=1`; LPIPS is **LPIPS-VGG on inputs
mapped to [-1, 1]** (the `normalize=False` convention); DISTS is the standard
implementation on the same pairs; FID is `pytorch-fid` against the size-matched
ground-truth test set. The LPIPS convention matters: the alternative [0, 1]
convention gives a systematically different number and the two must never be
mixed, or compared against a paper that used the other one.
## Load it and translate one SAR image
```python
import torch
from guided_diffusion.script_util import (create_model_and_diffusion,
model_and_diffusion_defaults)
d = model_and_diffusion_defaults()
d.update(image_size=512, num_channels=128, num_res_blocks=3, learn_sigma=False,
diffusion_steps=2000, noise_schedule='linear', timestep_respacing='250')
model, diffusion = create_model_and_diffusion(**d)
model.load_state_dict(torch.load('ema_final.pt', map_location='cpu'))
model.cuda().eval()
# sar: (1, 3, 512, 512) float tensor in [-1, 1]
sample = diffusion.p_sample_loop(model, (1, 3, 512, 512),
clip_denoised=True, model_kwargs={},
noise=None, condition=sar)
```
The repository imports `blobfile` and `mpi4py` unconditionally; a single-process
run on a local filesystem needs either those packages or small local stand-ins on
`PYTHONPATH`.
**Never pass `use_ddim=True`.** See below.
## Read before using this checkpoint
* **DDIM is broken upstream, and that is not a choice we made.**
`p_sample_loop(..., condition=None, ...)` accepts and threads the SAR
condition; `ddim_sample_loop(...)` has **no `condition` parameter at all**, so
passing `--use_ddim True` raises `TypeError`. Sampling is respaced DDPM with
250 steps, which is also what the authors' own `sample.sh` uses.
* **A correctness bug in the released sampler, which we fixed.** Upstream paired
each SAR image with an EO image by **unsorted `os.listdir` position** — i.e. by
filesystem order. Any number produced with the unpatched sampler is measured
against effectively arbitrary ground truth. We sort both listings. If you
reproduce this row from a clean upstream checkout, apply that fix or your
metrics are meaningless.
* **Three further changes we made**, all commented in place: the
distributed-init helper no longer overwrites `CUDA_VISIBLE_DEVICES` (upstream
pins rank % 8, which on a shared machine hijacks another user's device); the
noise tensor for a partial last batch is shaped from the batch rather than from
the `--batch_size` flag; and the sampler takes explicit input/output directories
and builds its resize transform at run time, because the module-level transform
hard-codes 256 px and would silently downsize the 512 px cell.
* **The training loader requires integer filenames.** It sorts with
`int(stem)`, so any non-numeric stem raises `ValueError`. Feed it an
integer-named adapter directory and keep a manifest to map back to the real
stems.
* **Do not let the released 512 px path resize.** The fork's `center_crop_arr`
*resizes* 600 → 512. We wrote deterministic centre-512 crops instead, to keep a
crop-not-resize protocol across the whole benchmark.
* Passes the identity-collapse audit on both datasets.
## Licence — stated factually ⚠ no upstream licence exists
**The upstream code base publishes no licence.**
[`Coordi777/Conditional-Diffusion-for-SAR-to-Optical-Image-Translation`](https://github.com/Coordi777/Conditional-Diffusion-for-SAR-to-Optical-Image-Translation)
has no LICENSE, LICENCE, COPYING or NOTICE file anywhere in the tree we trained
from, no licence section in its README, and the GitHub API reports no declared
licence, with the `/license` endpoint returning 404. Checked 2026-08-28.
Under default copyright that means **all rights are reserved by the authors and
no express permission to redistribute derived work has been granted** to us or
to you. We publish this checkpoint anyway and state the position plainly. Assess
redistribution for yourself; consider asking the authors.
**A second gap, which is about reproducibility rather than licensing.** Our
vendored copy of this repository carries no version control and records no
upstream URL inside its tree, so **the exact commit these weights were trained
from cannot be recovered**. A "clone upstream, then apply our patch" recipe is
therefore not possible for this row.
**Lineage.** The README states the repository is based on
`openai/guided-diffusion` with modifications, and the tree is visibly that code
base — OpenAI provenance comments survive in `guided_diffusion/logger.py` and
`guided_diffusion/unet.py`. `openai/guided-diffusion` is **MIT**; the unmodified
guided-diffusion parts carry that licence, which does **not** extend to the
authors' modifications. We do not ship the guided-diffusion licence text here
because it is not vendored in the tree we trained from — take it from that
repository if you need it, and make sure the copyright line you carry is
OpenAI's rather than another project's MIT file.
**We modified the code further**, and say so as a matter of discipline rather
than because any licence compels it: the four changes listed in the section
above, of which the sorted-listing fix is a correctness fix.
Please cite: Bai, Pu and Xu, *Conditional Diffusion for SAR to Optical Image
Translation*, IEEE Geoscience and Remote Sensing Letters,
[doi:10.1109/LGRS.2023.3337143](https://doi.org/10.1109/LGRS.2023.3337143).
The full record of what we checked, per method, is in
`licenses/NO-UPSTREAM-LICENSE.md` at the root of this repository.
---
Part of the **ReFlowSET** release. This folder holds one comparison-method
checkpoint that we retrained ourselves on SAR2Opt; it is not ReFlowSET
itself. Every comparison method in this repository was retrained by us on the
same splits at the same resolution and scored through one evaluation pipeline,
so the rows are directly comparable to each other — and, for the same reason,
**not** directly comparable with the numbers in the methods' own papers.