Update benchmark with full 6-model comparison
Browse files- megaloc/README.md +87 -46
megaloc/README.md
CHANGED
|
@@ -1,80 +1,121 @@
|
|
| 1 |
-
# MegaLoc
|
|
|
|
| 2 |
|
| 3 |
-
|
| 4 |
|
| 5 |
-
##
|
|
|
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
```
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
│ ├── megaloc.onnx # FP32 (873 MB, batch=1)
|
| 11 |
-
│ ├── megaloc_fp16.onnx # FP16 (437 MB, dynamic batch)
|
| 12 |
-
│ └── megaloc_int8.onnx # INT8 (223 MB, batch=1)
|
| 13 |
-
└── coreml/ # CoreML models (macOS / Apple Silicon, all multi-batch)
|
| 14 |
-
├── megaloc_coreml_fp32.mlpackage # FP32 (873 MB)
|
| 15 |
-
├── megaloc_coreml_fp16.mlpackage # FP16 (437 MB)
|
| 16 |
-
└── megaloc_coreml_int8.mlpackage # INT8 (219 MB)
|
| 17 |
```
|
| 18 |
|
| 19 |
-
|
| 20 |
|
| 21 |
-
###
|
|
|
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|-------|------|--------|-----|-----|-----|-----|
|
| 25 |
-
| FP32 | 873 MB | 1.000000 | 399ms / 2.5fps | 872ms / 2.3fps | 1514ms / 2.6fps | 2699ms / 3.0fps |
|
| 26 |
-
| FP16 | 437 MB | 0.999989 | 400ms / 2.5fps | 850ms / 2.4fps | 1602ms / 2.5fps | 2876ms / 2.8fps |
|
| 27 |
-
| INT8 | 223 MB | 0.996453 | 475ms / 2.1fps | — | — | — |
|
| 28 |
|
| 29 |
-
FP16 is near-lossless at all batch sizes. INT8 preserves Recall@1 = 100% in retrieval tasks.
|
| 30 |
|
| 31 |
-
### CoreML (Apple Silicon GPU, multi-batch)
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|-------|------|--------|-------------|-------|
|
| 35 |
-
| FP32 | 873 MB | 1.000000 | ~74ms / 13fps | RangeDim(1,16) dynamic batch |
|
| 36 |
-
| FP16 | 437 MB | TBD | TBD | RangeDim(1,16) dynamic batch |
|
| 37 |
-
| INT8 | 219 MB | TBD | TBD | RangeDim(1,16) dynamic batch |
|
| 38 |
|
| 39 |
-
|
| 40 |
|
| 41 |
-
|
| 42 |
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
-
import onnxruntime as ort, numpy as np
|
| 47 |
-
from PIL import Image
|
| 48 |
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
|
| 52 |
-
data = np.expand_dims(np.array(img).astype(np.float32).transpose(2,0,1)/255.0, 0)
|
| 53 |
|
| 54 |
-
|
| 55 |
-
```
|
| 56 |
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
|
| 64 |
|
| 65 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
data = np.expand_dims(np.array(img).astype(np.float32).transpose(2,0,1)/255.0, 0)
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
```
|
| 70 |
|
| 71 |
-
|
|
|
|
|
|
|
| 72 |
|
|
|
|
| 73 |
```bibtex
|
| 74 |
@inproceedings{Berton_2025_MegaLoc,
|
| 75 |
author = {Berton, Gabriele and Masone, Carlo},
|
| 76 |
title = {MegaLoc: One Retrieval to Place Them All},
|
| 77 |
-
booktitle = {
|
|
|
|
| 78 |
year = {2025},
|
|
|
|
| 79 |
}
|
| 80 |
```
|
|
|
|
|
|
| 1 |
+
# MegaLoc
|
| 2 |
+
An image retrieval model for any localization task, which achieves SOTA on most VPR datasets, including indoor and outdoor ones.
|
| 3 |
|
| 4 |
+
[Gradio Demo](https://gmberton.github.io/demos-url/megaloc/) - [ArXiv](https://arxiv.org/abs/2502.17237) - [Paper on ArXiv](https://arxiv.org/pdf/2502.17237) - [Paper on HF](https://huggingface.co/papers/2502.17237) - [Model on HF](https://huggingface.co/gberton/MegaLoc).
|
| 5 |
|
| 6 |
+
### Demo
|
| 7 |
+
Try the demo on your own images to see how good MegaLoc is! The demo uses a database of ~5M street-view images from San Francisco, and when you upload one it will find the most similar one from the same place.
|
| 8 |
|
| 9 |
+
<img width="746" height="576" alt="image" src="https://github.com/user-attachments/assets/4e7a3eec-dfee-4aae-83cc-f5146a1b421d" />
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
### Using the model
|
| 13 |
+
You can use the model with torch.hub, as simple as this
|
| 14 |
```
|
| 15 |
+
import torch
|
| 16 |
+
model = torch.hub.load("gmberton/MegaLoc", "get_trained_model")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
```
|
| 18 |
|
| 19 |
+
For more complex uses, like computing results on VPR datasets, visualizing predictions and so on, you can use our [VPR-methods-evaluation](https://github.com/gmberton/VPR-methods-evaluation), which lets you do all this for MegaLoc and multiple other VPR methods on labelled or unlabelled datasets.
|
| 20 |
|
| 21 |
+
### Qualitative examples
|
| 22 |
+
Here are some examples of top-1 retrieved images from the SF-XL test set, which has 2.8M images as database.
|
| 23 |
|
| 24 |
+

|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
|
|
|
| 26 |
|
|
|
|
| 27 |
|
| 28 |
+
---
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
+
## Available Models
|
| 31 |
|
| 32 |
+
Pre-quantized models on HuggingFace: [Realcat/image_retrieval_checkpoints](https://huggingface.co/Realcat/image_retrieval_checkpoints)
|
| 33 |
|
| 34 |
+
```bash
|
| 35 |
+
# ONNX
|
| 36 |
+
huggingface-cli download Realcat/image_retrieval_checkpoints --include "megaloc/onnx/*" --local-dir .
|
| 37 |
+
# CoreML
|
| 38 |
+
huggingface-cli download Realcat/image_retrieval_checkpoints --include "megaloc/coreml/*" --local-dir .
|
| 39 |
+
```
|
| 40 |
|
| 41 |
+
### Benchmark (MacBook Pro M-series, 518×518, B=1 vs PyTorch FP32)
|
|
|
|
|
|
|
| 42 |
|
| 43 |
+
| Model | Size | CosSim | SNR | Latency | FPS | Multi-Batch |
|
| 44 |
+
|-------|------|--------|-----|---------|-----|-------------|
|
| 45 |
+
| **PyTorch FP32** | (mem) | 1.000000 | ∞ | 367 ms | 2.7 | — |
|
| 46 |
+
| ONNX FP32 | 873 MB | 1.000000 | 80.5 dB | 367 ms | 2.7 | **Y** |
|
| 47 |
+
| ONNX FP16 | 437 MB | 0.999989 | 46.4 dB | 345 ms | 2.9 | **Y** |
|
| 48 |
+
| ONNX INT8 | 223 MB | 0.996625 | 21.7 dB | 395 ms | 2.5 | **Y** |
|
| 49 |
+
| CoreML FP32 | 873 MB | 1.000000 | 80.5 dB | **74 ms** | **13.6** | N |
|
| 50 |
+
| CoreML INT8 | 219 MB | 0.998699 | 25.8 dB | **74 ms** | **13.5** | N |
|
| 51 |
|
| 52 |
+
> CoreML FP16 excluded due to poor accuracy (cos=0.944, SNR=9.5dB). CoreML's FP16 path uses half-precision for all intermediate activations, causing error accumulation in this deep ViT.
|
|
|
|
| 53 |
|
| 54 |
+
### ONNX Multi-Batch Throughput
|
|
|
|
| 55 |
|
| 56 |
+
| Model | B=1 | B=2 | B=4 | B=8 |
|
| 57 |
+
|-------|-----|-----|-----|-----|
|
| 58 |
+
| ONNX FP32 | 2.7 img/s | 2.3 img/s | 2.7 img/s | 2.9 img/s |
|
| 59 |
+
| ONNX FP16 | 2.9 img/s | 2.6 img/s | 2.7 img/s | 2.9 img/s |
|
| 60 |
+
| ONNX INT8 | 2.5 img/s | 2.1 img/s | 2.3 img/s | 2.5 img/s |
|
| 61 |
|
| 62 |
+
### Recommendations
|
| 63 |
+
|
| 64 |
+
- **Best accuracy/size**: CoreML INT8 — 219 MB, 74ms, cos=0.9987, 13.5 FPS (macOS only)
|
| 65 |
+
- **Cross-platform**: ONNX FP16 — 437 MB, 345ms, cos=0.99999, multi-batch
|
| 66 |
+
- **Maximum compression**: ONNX INT8 — 223 MB, all platforms, multi-batch
|
| 67 |
+
|
| 68 |
+
### On sub-8-bit quantization
|
| 69 |
+
|
| 70 |
+
4-bit/1-bit quantization fails catastrophically (cos_sim ≈ 0). DINOv2 ViT has 12 blocks + aggregator (~200 weight tensors). Error from only 16 levels accumulates across 48+ MatMul layers. ViT architectures below 8-bit require **quantization-aware training**.
|
| 71 |
|
| 72 |
+
### Usage
|
| 73 |
|
| 74 |
+
```bash
|
| 75 |
+
uv sync
|
| 76 |
+
|
| 77 |
+
# ONNX (cross-platform, multi-batch)
|
| 78 |
+
python3 -c "
|
| 79 |
+
import onnxruntime as ort, numpy as np
|
| 80 |
+
from PIL import Image
|
| 81 |
+
sess = ort.InferenceSession('megaloc_fp16.onnx', providers=['CPUExecutionProvider'])
|
| 82 |
+
img = Image.open('img.jpg').convert('RGB').resize((518,518), Image.LANCZOS)
|
| 83 |
+
data = np.expand_dims(np.array(img).astype(np.float32).transpose(2,0,1)/255.0, 0)
|
| 84 |
+
desc = sess.run(None, {'images': data})[0] # [B, 8448]
|
| 85 |
+
"
|
| 86 |
+
|
| 87 |
+
# CoreML (macOS, 5x faster)
|
| 88 |
+
python3 -c "
|
| 89 |
+
import coremltools as ct, numpy as np
|
| 90 |
+
from PIL import Image
|
| 91 |
+
model = ct.models.MLModel('megaloc_coreml_int8.mlpackage')
|
| 92 |
+
img = Image.open('img.jpg').convert('RGB').resize((518,518), Image.LANCZOS)
|
| 93 |
data = np.expand_dims(np.array(img).astype(np.float32).transpose(2,0,1)/255.0, 0)
|
| 94 |
+
desc = list(model.predict({'images': data}).values())[0]
|
| 95 |
+
"
|
| 96 |
+
```
|
| 97 |
|
| 98 |
+
### Reproduce
|
| 99 |
+
|
| 100 |
+
```bash
|
| 101 |
+
uv run python export_onnx_batch.py # ONNX multi-batch
|
| 102 |
+
uv run python quantize_megaloc.py --method 8bit --input megaloc_fp32.onnx # ONNX INT8
|
| 103 |
+
uv run python convert_coreml.py # CoreML FP32/FP16/INT8
|
| 104 |
```
|
| 105 |
|
| 106 |
+
---
|
| 107 |
+
|
| 108 |
+
## Acknowledgements / Cite / BibTex
|
| 109 |
|
| 110 |
+
If you use this repository please cite the following
|
| 111 |
```bibtex
|
| 112 |
@inproceedings{Berton_2025_MegaLoc,
|
| 113 |
author = {Berton, Gabriele and Masone, Carlo},
|
| 114 |
title = {MegaLoc: One Retrieval to Place Them All},
|
| 115 |
+
booktitle = {IEEE/CVF Conference on Computer Vision and Pattern Recognition Workshops},
|
| 116 |
+
month = {June},
|
| 117 |
year = {2025},
|
| 118 |
+
pages = {2886--2892}
|
| 119 |
}
|
| 120 |
```
|
| 121 |
+
|