PHANTOM-Net sonar models
Two small models behind the PHANTOM-Net sonar hazard console (see the linked Space).
| folder | model | trained on | validation |
|---|---|---|---|
klsg_shipwreck/ |
shipwreck / aircraft classifier, GhostNet backbone, ghostnet_100.in1k (0.95 M params) | KLSG / SeabedObjects real side-scan chips (447 images, grouped split) | balanced accuracy 94.6%, accuracy 96.7% |
phantomnet/ |
PhantomNet detector: boxes, instance masks, semantic mask, shadow, uncertainty (4.0 M params) | Marine Debris FLS forward-looking tank sonar, 11 classes | mAP@50 0.874, mAP@50-95 0.543, mIoU 0.647 |
onnx/ holds ONNX exports of both (dynamic batch; parity with PyTorch < 1e-4).
Measured with the full console pipeline
On 8 synthetic XTF lines (dataset/synthetic_sonar_files):
| object | found |
|---|---|
| small debris | 83/105 (79.0%) |
| ghost nets | 6/11 (54.5%) |
| pipelines | 5/5 (100.0%) |
| wrecks | 4/4 (100.0%) |
False boxes on empty seabed: 0.62 per line.
Forward-looking, 60 Marine Debris FLS validation frames (seed-0 split), walls excluded: 102/107 objects found at IoU >= 0.5.
CPU speed
On Intel64 Family 6 Model 186 Stepping 2, GenuineIntel, no GPU:
| model | PyTorch, 1 thread | ONNX Runtime, 1 thread |
|---|---|---|
| classifier | 21.88 ms | 8.97 ms |
| PhantomNet | 194.27 ms | 138.83 ms |
Limits - read before quoting numbers
- The side-scan figures come from synthetic survey lines: an upper bound, not a real-survey result.
- Each model only works on the sonar it was trained on: PhantomNet (forward-looking tank sonar) found 3 of 60 debris items on side-scan; the classifier has never seen a forward-looking frame.
- The classifier knows two classes (shipwreck, aircraft); anything else should come out below the confidence threshold and be reported as an unknown object.
- No sonar with labelled ghost nets or pipelines was available; those labels in the console are shape-based guesses.
Loading
The checkpoints are dicts {"model": state_dict, "cfg": config, ...} for the phantom_net package in the project repository:
from phantom_net.classify import SonarClassifier, ClassifierConfig
from phantom_net.infer import load_detector
import torch
ck = torch.load('klsg_shipwreck/final.pt', map_location='cpu', weights_only=False)
clf = SonarClassifier(ClassifierConfig(**{**ck['cfg'], 'pretrained': False})).eval()
clf.load_state_dict(ck['model'])
det, info = load_detector('phantomnet/final.pt', device='cpu')