Downloads · 30 days
0
aiprojektgaia/gaia_roads_50e
gaia_roads_50e is a image segmentation model from aiprojektgaia. Use it for the image segmentation task on the model card, and read the license before you ship it in a product. It is set up for segmentation-models-pytorch. The card lists the license as apache-2.0.
Binary semantic segmentation model that extracts roads from aerial imagery. Produces a per-pixel likelihood map, not a thresholded mask.
Downloads · 30 days
0
Access
Public
Updated Nov 3, 2026
Repo size
278 MB
Likes
0
Public
Click a slice to open those files.
.ckpt278 MB · 100%
From the Hugging Face model README
Binary semantic segmentation model that extracts roads from aerial imagery. Produces a per-pixel likelihood map, not a thresholded mask.
Trained for GAIA, a self-hosted system that turns aerial imagery into vector map data for Swedish municipalities.
An FPN (Feature Pyramid Network) segmentation model with a ResNet34 encoder,
trained to score each RGB pixel by how likely it is to be road. Built with
segmentation_models_pytorch and trained via PyTorch Lightning.
smp.encoders.get_preprocessing_params("resnet34"),
which returns ImageNet values — consistent with an ImageNet-pretrained
encoder. Confirm against ckpt["hyper_parameters"].segmentation module of gaia-engine, via
ResUNetInferencerNaming note. GAIA registers this checkpoint under
"model type": "resunet"insegmentation/parameters.json. That string selects the loader, not the architecture — the loader passesarchstraight from the checkpoint hyperparameters intosmp.create_model(). The architecture is whatever the checkpoint declares (FPN), despite theresunetlabel.
Road extraction from nadir aerial RGB orthophotos.
The model is resolution-sensitive and expects imagery at approximately
0.05 m/pixel. The GAIA inference wrapper rescales input to that target
before inference (resizeImageToTargetResolution), and additionally crops
dimensions to a multiple of 32 pixels, as the FPN decoder requires.
In production GAIA requests tiles from a WMS at 0.08 m/pixel and the wrapper upsamples them to 0.05 m/pixel. This is handled explicitly rather than being a silent mismatch, but upsampling cannot recover detail that was never captured — imagery natively at or near 0.05 m/pixel should be expected to perform better.
Output is a single-channel uint8 raster, 0–255, where the value is the
sigmoid-scaled likelihood that the pixel is road. It is not a binary mask.
Within GAIA the likelihood raster feeds a fixed pipeline:
Keeping the model's output continuous is deliberate: it lets a run be re-thresholded without re-running inference.
Plausible uses beyond GAIA include map updating, infrastructure inventory and change detection — none of which have been evaluated here.
Geographic and distributional bias. The model was trained for Swedish municipal use. Road appearance, surfacing materials, markings, vehicle density, vegetation and lighting all vary by region and season; performance elsewhere is unknown and should not be assumed.
Resolution sensitivity. The model targets 0.05 m/pixel. Imagery at materially different ground sampling distance is rescaled, which degrades quality in both directions.
Systematic failure modes for linear features. Roads are thin and long, so they are disproportionately affected by occlusion — tree canopy, shadow, parked vehicles, bridges and tunnels. Breaks in output are expected and are partly compensated for downstream by gap closure during vectorisation, which can itself bridge gaps that are genuinely not roads.
Class ambiguity. The boundary between road, driveway, parking area, cycle path and other hard surfaces is a definitional choice made during annotation. Users applying a different definition will read correct predictions as errors.
Unquantified. No evaluation metrics are published with this checkpoint (see Evaluation). Its accuracy on any given imagery is therefore unverified.
Normalisation is applied inside the training wrapper, not by the bare
smpmodel. Loading the raw state dict as below and feeding it unnormalised images will produce poor results. Either reproduce the wrapper (shown second) or normalise with ImageNet statistics yourself.
import torch
import segmentation_models_pytorch as smp
# weights_only=True is a security control: without it, torch.load unpickles
# arbitrary Python objects and a crafted checkpoint can execute code.
ckpt = torch.load("roads_50e.ckpt", map_location="cpu", weights_only=True)
hparams = ckpt["hyper_parameters"]
model = smp.create_model(
arch=hparams["arch"],
encoder_name=hparams["encoder_name"],
in_channels=hparams["in_channels"],
classes=hparams["out_classes"],
)
state_dict = {
k.replace("model.", "", 1): v
for k, v in ckpt["state_dict"].items()
if k.startswith("model.")
}
model.load_state_dict(state_dict)
model.eval()
Reproducing the wrapper, which matches how GAIA runs the model:
import cv2, numpy as np, torch
import pytorch_lightning as pl
import segmentation_models_pytorch as smp
class RoadSegModel(pl.LightningModule):
def __init__(self, arch, encoder_name, in_channels, out_classes, **kwargs):
super().__init__()
self.save_hyperparameters()
self.model = smp.create_model(
arch, encoder_name=encoder_name,
in_channels=in_channels, classes=out_classes, **kwargs,
)
params = smp.encoders.get_preprocessing_params(encoder_name)
self.register_buffer("std", torch.tensor(params["std"]).view(1, 3, 1, 1))
self.register_buffer("mean", torch.tensor(params["mean"]).view(1, 3, 1, 1))
def forward(self, image):
return self.model((image - self.mean) / self.std)
ckpt = torch.load("roads_50e.ckpt", map_location="cpu", weights_only=True)
model = RoadSegModel(**ckpt["hyper_parameters"])
model.load_state_dict(ckpt["state_dict"])
model.eval()
TARGET_RES = 0.05 # m/pixel
def predict(image: np.ndarray, image_resolution: float) -> np.ndarray:
"""RGB HxWx3 uint8 -> HxW uint8 likelihood (0-255)."""
h, w = image.shape[:2]
scale = image_resolution / TARGET_RES
# FPN requires spatial dimensions divisible by 32
nh, nw = int(h * scale) // 32 * 32, int(w * scale) // 32 * 32
resized = cv2.resize(image, (nw, nh))
tensor = torch.tensor(np.array([np.moveaxis(resized, 2, 0)]))
with torch.no_grad():
logits = model(tensor)
pred = logits.sigmoid()[0].numpy().squeeze()
pred = cv2.resize(pred, (w, h), interpolation=cv2.INTER_NEAREST)
return np.uint8(255 * pred)
Threshold the result to obtain a binary mask, e.g. pred >= 191 for 75%
confidence.
[More Information Needed]
Not documented in the released artefacts. Required for a complete card: dataset provenance and licence, imagery source and date, ground sampling distance, geographic coverage, annotation guidelines (specifically how road was delimited against driveways, parking and other hard surfaces), dataset size, and the train/validation/test split with any geographic separation between them.
Check the licence of the source imagery before relying on the Apache-2.0 designation. Models derived from licensed orthophotography may carry obligations from the imagery provider.
smp.encoders.get_preprocessing_params("resnet34"), applied inside the model
wrapper.At 50 epochs over 3,500 steps, the training set is on the order of 70 batches per epoch — a small dataset by segmentation standards. Worth stating explicitly once the dataset size is known, as it bears directly on generalisation.
.ckpt, includes optimizer state)The published checkpoint retains optimizer state, which roughly triples its size. Stripping it to weights only would reduce the download substantially for inference-only users, at the cost of resumable training.
[More Information Needed]
Evaluation should be disaggregated by at least: urban / suburban / rural setting; road class and width; surface type (asphalt, gravel, unpaved); occlusion by canopy, shadow or vehicles; and imagery source, season and resolution.
[More Information Needed]
Recommended for binary segmentation of thin linear features: IoU and F1 at the operating threshold, precision/recall curves across thresholds, and a boundary-aware or connectivity-aware metric — pixel IoU understates breaks in a road network, which matter more than pixel counts for downstream vectorisation.
[More Information Needed]
No quantitative evaluation is published with this checkpoint. Its performance on any given imagery is unverified, and it should be validated before operational use.
Carbon emissions can be estimated using the Machine Learning Impact calculator presented in Lacoste et al. (2019).
FPN decoder over a ResNet34 encoder; single-channel output with a sigmoid, trained for binary road segmentation. ~23.2M parameters. Spatial dimensions must be divisible by 32.
[More Information Needed]
[More Information Needed]
The model is one component of GAIA, which handles tiling, thresholding and vectorisation around it. See the GAIA repositories for the surrounding pipeline.