Blue Marble Ships

License Sizes Device Params

Introduction

Blue Marble Ships is a family of five ship detection models for Sentinel-2 imagery, from 32k to 13.5M parameters. Every model is under 15M parameters and runs fully in int8 on the Qualcomm Dragonwing QCS8275 NPU (Arduino VENTUNO Q).

Highlights

  • 86.6 AP on our Sentinel-2 vessel test split (tiles unseen in training), 82.4 AP on April 2026 scenes; ship length mean absolute error 17 m (medium).
  • 81.2 AP at 32k parameters; ship position and length in one pass.
  • 3.6 ms per 256x256 tile (medium) on the Arduino VENTUNO Q NPU, int8, every layer on the NPU.

Model Downloads

Model Params int8 size VENTUNO Q latency Ops on NPU Ships test (ours): fp32 / int8 Download
Blue-Marble-Ships-pico 0.032M 0.14 MB 1.0 ms 62/62 81.2 / 78.7 pico/
Blue-Marble-Ships-nano 0.19M 0.36 MB 1.0 ms 76/76 84.3 / 81.6 nano/
Blue-Marble-Ships-tiny 1.26M 1.62 MB 1.3 ms 117/117 82.7 / 82.0 tiny/
Blue-Marble-Ships-small 2.4M 2.86 MB 1.5 ms 130/130 80.8 / 78.3 small/
Blue-Marble-Ships-medium 13.5M 14.58 MB 3.6 ms 224/224 86.6 / 86.2 medium/

Each size folder contains:

File Use
model_qcs8275.dlc Compiled for the Qualcomm QCS8275 NPU (QNN runtime): runs as-is on the Arduino VENTUNO Q
model_int8.onnx int8 ONNX, the source of the compiled model; ONNX Runtime or your own NPU toolchain
model_fp32.onnx Full precision ONNX (CPU / GPU); the scores below are for this model
model.safetensors + config.json PyTorch weights for fine-tuning, with models.py in this repository
ventuno_q_profile.json On-device profile on the Arduino VENTUNO Q (Qualcomm AI Hub): the compute unit of every op, total latency, memory, load times

Scores in this table are for the exact files in this repository, re-scored on our held-out ships test split (332 ships). Latency and ops on NPU: on-device profile of model_qcs8275.dlc on an Arduino VENTUNO Q (Qualcomm AI Hub).

Evaluation Results

Models under 15M parameters

Model Params Ships test (ours) (AP) Ships Apr-2026 (ours) (AP)
Blue Marble pico 0.032M 81.2 81.7 ± 0.6
Blue Marble nano 0.19M 84.3 80.1 ± 0.5
Blue Marble tiny 1.26M 82.7 80.7 ± 0.7
Blue Marble small 2.4M 80.8 82.2 ± 0.5
Blue Marble medium 13.5M 86.6 82.4 ± 0.8

Blue Marble, test: the released checkpoint in this repository; Apr-2026: mean ± std over 3 training runs. Both are our own splits, not public leaderboards. Other models: published numbers, with inputs noted where they differ from ours (our models use Sentinel-2 only); * = trained and evaluated by us on the same data and split (parameter count includes our decoder). Best per column among models under 15M in bold. Labels: Global Fishing Watch Sentinel-2 vessel detections (AIS-matched, plus high-confidence detections without AIS); ambiguous detections are ignored. Test (332 ships) and Apr-2026 (April 2026 scenes) use tiles not seen in training. Ship length error: mean absolute error of the predicted length for matched ships. AP: detections are local maxima of the heatmap, a detection is correct if its centre is within 50 m of an unmatched label, all-point interpolated average precision.

Quickstart

import numpy as np, onnxruntime as ort

MEAN = np.array([2357.089, 2137.385, 2018.788, 2082.986, 2295.651, 2854.537, 3122.849, 3040.560, 3306.481, 1473.847, 506.070, 2472.825, 1838.929], np.float32)[:, None, None]
STD  = np.array([1624.683, 1675.806, 1557.708, 1833.702, 1823.738, 1733.977, 1732.131, 1679.732, 1727.26, 1024.687, 442.165, 1331.411, 1160.419], np.float32)[:, None, None]

def prepare(dn):                       # dn: Sentinel-2 L1C digital numbers, [13, H, W], H and W multiples of 16
    dn = np.clip(dn - 1000, 0, None)   # only for products from 2022 on (processing baseline 04.00+)
    return ((dn - MEAN) / STD)[None].astype(np.float32)

sess = ort.InferenceSession("tiny/model_int8.onnx")
out = sess.run(None, {"image": prepare(dn)})[0]

PyTorch:

import json, torch
from safetensors.torch import load_file
from models import BlueMarble                     # models.py from this repository

cfg = json.load(open("tiny/config.json"))
model = BlueMarble(cfg["arch"], cfg["num_classes"]).eval()
model.load_state_dict(load_file("tiny/model.safetensors"))
  • Input: 13 Sentinel-2 L1C bands, B01 to B12 including B8A and B10. Missing bands (other sensors): set to 0 after normalisation.
  • Output: [1, 2, H, W]: channel 0 ship-centre heatmap logit (sigmoid; 5x5 local maxima above 0.3 are ships), channel 1 log ship length (length_m = exp(v) * 10).

License

Apache-2.0. Contains modified Copernicus Sentinel data.

Citation

@misc{bluemarble2026,
  title  = {Blue Marble: Edge Earth Observation Models},
  author = {Harsh Kumar},
  year   = {2026},
  url    = {https://huggingface.co/Civimatica}
}
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

Collection including Civimatica/blue-marble-ships