U-Net land-cover classifier for landscape-change-detection-pipeline

Pixel-wise land-cover / land-surface segmentation model (U-Net with FiLM conditioning) trained for the landscape-change-detection-pipeline. It classifies satellite scenes (Landsat 5/7/8/9, Sentinel-2) on a common 10 m grid into 16 classes. The resulting class maps feed the pipeline's monthly composites, break detection and change-event analysis.

This checkpoint is not a general-purpose land-cover model. It is meant to be run through the pipeline above, which builds the exact 21-channel input it expects. See Limitations.

Quick start

git clone https://github.com/Research-Tarka/landscape-change-detection-pipeline
cd landscape-change-detection-pipeline
conda env create -f environment.yml && conda activate landscape-change-detection-pipeline
pip install torch torchvision --index-url https://download.pytorch.org/whl/cu130
pip install -r requirements-torch.txt && pip install -e . huggingface_hub

hf download <USER>/<REPO> unet_best.pt --local-dir models/checkpoints

Then run python scripts/06_run_inference.py (with inference.checkpoint_path: null it picks up models/checkpoints/unet_best.pt by default) (steps 01-03 of the README produce the scenes it needs).

The checkpoint is self-describing (weights, class names, feature names, normalisation, architecture), so nothing else is needed to load it:

from landscape_change_detection_pipeline.inference.model_loader import load_model_for_inference

loaded = load_model_for_inference("models/checkpoints/unet_best.pt", device="cuda")
print(loaded.class_names, loaded.feature_names)
# loaded.model, loaded.mean, loaded.std are what inference.engine.predict_scene() takes.

Model

Architecture U-Net, depth 4, 48 base channels, batch norm, dropout 0.006, multi-head self-attention in the bottleneck (8 heads)
Conditioning FiLM on sensor and day-of-year (film_sensor, film_doy); no lat/lon FiLM
Checkpoint num_sensors 1
Input 21 channels, 256 x 256 patches (sliding window + Hann weighting at inference), normalised with the train-only mean/std stored in the checkpoint
Output 16 classes (dense ids = position in configs/classes.yaml)
Size ~20 MB

Input channels (in this order): NDVI, NDSI, NDWI_GAO, NBR, ND_SWIR1_SWIR2, ND_BLUE_RED, ND_BLUE_NIR, ND_GREEN_RED, NDWI_MCFEETERS, r, g, b, BSI, EVI, TC_BRIGHTNESS, TC_GREENNESS, TC_WETNESS, elevation, slope, aspect_sin, aspect_cos. Spectral inputs are top-of-atmosphere (TOA) reflectance; terrain layers come from the tile DEM. Changing this list changes the input size and requires retraining.

Classes (dense id: name): 0 forest, 1 bare_ground, 2 grassland_herbaceous, 3 cultivated_agriculture, 4 wetland_marsh, 5 open_water, 6 cutblock_harvest, 7 burned_disturbed, 8 snow_cover, 9 ice_cover, 10 rock_alpine_bare, 11 built_up_infrastructure, 12 cloud, 13 shadow, 14 firn, 15 sand_gravel.

Not every class is predicted: cultivated_agriculture, wetland_marsh, cutblock_harvest and sand_gravel had no training pixels in this run, and three classes were merged into others (training.class_merge): built_up_infrastructure and rock_alpine_bare into bare_ground, and firn into ice_cover. The model effectively predicts 9 classes: forest, bare ground, grassland/herbaceous, open water, burned/disturbed, snow, ice, cloud and shadow (the other outputs are unused). Because firn is folded into ice, this checkpoint never outputs a separate firn class.

Raw ids (used in masks, class_map.npz, composites) differ from dense ids; the pipeline converts between them. See configs/classes.yaml and section 5 of the pipeline README.

Training

  • Labels: 705 hand-annotated scenes painted with MaskForge (420 train / 142 val / 143 test), split by tile (60 / 20 / 20, seed 0) so no tile appears in more than one partition. No pseudo-labels were used in this run.
  • Loss: focal (gamma 1.33) + Dice (weight 0.588), class weighting (power 0.447, max 10), extra penalties on six confusable (true, predicted) pairs (cloud->burned, bare->burned, forest->water, forest->ice, bare->snow, snow->ice).
  • Optimisation: AdamW, lr 4.5e-4, weight decay 2e-3, batch 32 (micro-batch 8), AMP, grad clip 1.0, EMA of the weights (decay 0.995), flips + 90-degree rotations and radiometric augmentation (brightness / contrast / noise), early stopping (patience 15). Best epoch 52 (validation mIoU 0.632 during training); training stopped at epoch 67 and the released weights are the best-epoch ones.
  • Full configuration, per-epoch history, per-class IoU and confusion matrices are in unet_run_report.json.

Evaluation

Macro mIoU over the classes present in each split:

Split mIoU Kappa
Train 0.665 0.822
Validation 0.643 0.803
Test 0.604 0.749

Per-class IoU on the test split:

Class IoU Precision Recall
forest 0.761 0.873 0.856
bare_ground 0.600 0.728 0.774
grassland_herbaceous 0.609 0.762 0.752
open_water 0.790 0.854 0.913
burned_disturbed 0.532 0.578 0.869
snow_cover 0.592 0.795 0.698
ice_cover 0.383 0.685 0.465
cloud 0.715 0.830 0.837
shadow 0.457 0.629 0.626

The split is by tile, so the test score measures generalisation to unseen tiles of the same study area and is the realistic figure to use.

Limitations and intended use

  • Weak classes: ice_cover (test IoU 0.38, recall 0.47) and shadow (0.46) are the least reliable. burned_disturbed is over-predicted (precision 0.58 for recall 0.87), so burned areas can include bare ground or dark surfaces. Firn, rock and built-up are merged into other classes and cannot be told apart.
  • Domain: trained on one study area and its annotation protocol; the checkpoint was not validated elsewhere. Expect degraded results in other regions, climates or seasons, and re-annotate / fine-tune for a new study.
  • Resolution: all sensors are resampled to a 10 m grid; Landsat pixels remain ~30 m information. A 1-2 pixel misregistration with reference data is the same size as the boundary errors being measured.
  • Inputs: TOA reflectance (not surface reflectance); Landsat 7 after 2002 (SLC-off) is not used.
  • Not a certified product: not suitable on its own for safety-critical, legal or regulatory decisions.

Data sources and licences

Imagery is accessed through Google Earth Engine: Landsat Collection 2 TOA (USGS, public domain), Sentinel-2 harmonized (Copernicus, free and open), DEM from MRDEM-30 / Copernicus GLO-30. Please check the terms of each provider if you redistribute derived products. Model weights and code: MIT licence.

Citation

@software{tarka_landscape_change_detection_pipeline,
  author  = {Tarka, Maxime},
  title   = {landscape-change-detection-pipeline},
  url     = {https://github.com/Research-Tarka/landscape-change-detection-pipeline},
  license = {MIT}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support