File size: 2,741 Bytes
07c8635
d1ac326
 
 
 
07c8635
d1ac326
07c8635
d1ac326
07c8635
 
d1ac326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
title: Satellite Change Detection (Curated)
emoji: 🛰️
colorFrom: blue
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
license: mit
---

# Satellite Change Detection — curated demo (Track A)

A single-container [Hugging Face Docker Space](https://huggingface.co/docs/hub/spaces-sdks-docker):
**FastAPI** (uvicorn, `:7860`) serves a **React + MapLibre GL** build and a CPU **onnxruntime**
inference API. This is the **curated** before/after mode (PRD §10.1) — the always-fast demo path;
the live Sentinel-2 AOI mode is a later milestone.

## What it does

- Pick a curated before/after scene pair and a model bundle.
- The backend runs the pair through the exported **ONNX** change-detection model (CPU) and returns a
  change-mask overlay + stats (% area changed, mean confidence, inference time).
- A MapLibre **swipe slider** compares before vs after; the detected change is a colored overlay with
  an **opacity** control. A **model-card** page carries the real LEVIR-CD results and limitations.

## Model bundles (the contract)

The app consumes only **artifact bundles** produced by `src/export.py` (PRD §3/§9), never the
training code. Each bundle is a directory with:

```
model.onnx           # exported graph (parity-checked against PyTorch)
preprocessing.json   # normalization, input size, band order, tiling, recommended threshold
config.yaml          # provenance
metrics_card.md      # headline metrics
parity.json          # recorded PyTorch↔ONNXRuntime parity
```

Bundles are either baked into `./models` at build time or pulled at startup from a companion HF
**Model repo** by setting the `HF_BUNDLE_REPO` env var — this keeps the Space lean and separates
weights from the app.

## Run locally

```bash
# 1. export at least one bundle (from the repo root, with the train env):
python -m src.export --config configs/levircd_segformer.yaml   # or --random-init to smoke it
cp -r bundles/* app/backend/models/

# 2. synthesize curated pairs (or drop real LEVIR-CD tiles into app/backend/data/curated/):
python app/backend/gen_sample_pairs.py --out app/backend/data/curated

# 3. build the frontend + run the API (serves the build at http://localhost:7860):
cd app/frontend && npm ci && npm run build && cd ..
BUNDLES_DIR=backend/models CURATED_DIR=backend/data/curated FRONTEND_DIST=frontend/dist \
  uvicorn backend.app:app --host 0.0.0.0 --port 7860
```

Or build the whole thing with Docker: `docker build -t sat-cd app/ && docker run -p 7860:7860 sat-cd`.

## Notes / honesty

- Change-class metrics only — overall pixel accuracy is meaningless when change is a tiny pixel
  fraction (see the model card).
- Trained weights inherit LEVIR-CD research/non-commercial terms — showcase use only.