SailSwarm LRASPP student (real-time water/sky/obstacle segmentation for Raspberry Pi 4)

lraspp_mobilenet_v3_large (torchvision, ~3.2 M params) distilled for 3-class maritime semantic segmentation — obstacle / water / sky — for the SailSwarm autonomous-sailboat obstacle-detection module (University of Konstanz). Trained on LaRS ground truth plus 10,731 Lake-Constance fisheye frames labelled by the eWaSR teacher (NexusDwin/sailswarm-ewasr-lars).

The point of this model: the teacher costs 3.9 µs/pixel int8 on a Pi 4 — quantisation-saturated. The student costs **1.1 µs/pixel**, making on-device segmentation real-time.

Files

File What
student512t_best.pth / train_512.log 512×384-trained weights (val acc 0.9944, IoU obst/water/sky 0.947/0.995/0.991)
student864t_best.pth / train_864.log 864×648-trained weights (val acc 0.9955, IoU 0.957/0.996/0.993) — crisper thin structures at full resolution
student_512x384.onnx · student_640x480.onnx fp32 exports of the 512-trained model (opset 17, fixed size, single image input NCHW)
student864t_864x648.onnx fp32 export of the 864-trained model
*.int8.onnx static per-channel QDQ int8 (calibrated on Lake-Constance frames; 99.1–99.3% pixel agreement vs fp32), ~3 MB each

Measured performance (Raspberry Pi 4, onnxruntime CPU, 2 threads, unthrottled)

input int8 latency fps async worker (with free-space derivation)
512×384 217.6 ms 4.60 3.00 Hz — one mask per 3 fps camera frame
640×480 327.9 ms 3.05
864×648 (864-trained) 594 ms 1.68 1.30 Hz

Scales to 5.75 fps @512 with 4 threads. Quality vs the teacher on-domain: 99.50% mean pixel agreement over 10,731 frames (p5 99.01%, min 93.7%).

Usage (onnxruntime)

import onnxruntime as ort, numpy as np, cv2
sess = ort.InferenceSession("student_512x384.int8.onnx", providers=["CPUExecutionProvider"])
img = cv2.imread("frame.jpg")[:, :, ::-1]                       # RGB, undistorted
x = cv2.resize(img, (512, 384)).astype(np.float32) / 255.0
x = ((x - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225]).transpose(2, 0, 1)[None].astype(np.float32)
cls = sess.run(None, {"image": x})[0][0].argmax(0)              # {0 obstacle, 1 water, 2 sky}

Intended use & limits

  • Input: undistorted RGB frames (Kannala–Brandt-rectified fisheye in our deployment). Masks upsample to full frame with nearest-neighbour.
  • Daytime/dawn RGB only. On near-black night frames the model produces confidently wrong output (measured: 86% "obstacle" on a black frame) — our runtime refuses frames below a mean-luminance floor of 25/255 and defers to thermal + radar. Replicate that gate.
  • Trained for a lake-surface camera ~0.27 m above the waterline; expect a domain gap for high-mounted or open-sea cameras.
  • Not validated for closed-loop navigation.

Provenance / license

Backbone: torchvision lraspp_mobilenet_v3_large (BSD-3, ImageNet-pretrained). Training data: LaRS (research/non-commercial — derived weights inherit its terms) + teacher pseudo-labels from NexusDwin/sailswarm-ewasr-lars (itself LaRS-derived). Verify all licences before any commercial or redistribution use.

Citation

@InProceedings{Zust2023LaRS,
  title={LaRS: A Diverse Panoptic Maritime Obstacle Detection Dataset and Benchmark},
  author={{\v{Z}}ust, Lojze and Per{\v{s}}, Janez and Kristan, Matej},
  booktitle={International Conference on Computer Vision (ICCV)},
  year={2023}
}
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 NexusDwin/sailswarm-lraspp-student