| # MixVPR β ONNX & CoreML Export |
|
|
| Exported and quantized models for [MixVPR](https://github.com/Vincentqyw/MixVPR): Feature Mixing for Visual Place Recognition (WACV 2023). |
|
|
| ## Models |
|
|
| | Format | File | Size | Latency (M-series) | CosSim | Status | |
| |---|---|---|---|---|---| |
| | ONNX FP32 | `onnx/mixvpr_fp32.onnx` | 41.7 MB | 32.4 ms | 1.0000 | β | |
| | ONNX FP16 | `onnx/mixvpr_fp16.onnx` | 21.0 MB | 38.2 ms | 0.9999 | β Recommended | |
| | CoreML FP16 | `coreml/mixvpr_fp16.mlpackage/` | 20.8 MB | **3.1 ms** | 0.9999 | β Recommended | |
| | CoreML INT8 | `coreml/mixvpr_int8.mlpackage/` | 10.5 MB | **3.3 ms** | 0.9983 | β | |
|
|
| ## Benchmark |
|
|
| All models were benchmarked against the original PyTorch FP32 model on a MacBook with Apple Silicon (M-series). The primary accuracy metric is **cosine similarity** between the exported model's 4096-dim descriptor and the PyTorch reference. |
|
|
| ### Latency (batch=1, averaged over 4 images) |
|
|
| | Model | Latency | Speedup | |
| |---|---|---| |
| | PyTorch FP32 (reference) | 44.5 ms | 1.0Γ | |
| | ONNX FP32 | 32.4 ms | 1.4Γ | |
| | ONNX FP16 | 38.2 ms | 1.2Γ | |
| | **CoreML FP16** | **3.1 ms** | **14.6Γ** | |
| | **CoreML INT8** | **3.3 ms** | **13.5Γ** | |
|
|
| ### Accuracy (cosine similarity vs PyTorch) |
|
|
| | Model | CosSim | Max Abs Error | Verdict | |
| |---|---|---|---| |
| | ONNX FP32 | 1.0000 | 1.9Γ10β»β· | No drop | |
| | ONNX FP16 | 0.9999 | 1.7Γ10β»β΄ | No drop | |
| | CoreML FP16 | 0.9999 | 3.2Γ10β»β΄ | No drop | |
| | CoreML INT8 | 0.9983 | 3.5Γ10β»Β³ | Negligible | |
|
|
| - CosSim > 0.9999 means retrieval results are **identical** to PyTorch. |
| - CosSim 0.9983 means top-1 may shift for borderline cases; top-10 remains stable. |
|
|
| ### File Size |
|
|
| | Model | Size | vs PyTorch (.pth) | |
| |---|---|---| |
| | PyTorch .pth | ~98 MB | β | |
| | ONNX FP32 | 41.7 MB | -57% | |
| | ONNX FP16 | 21.0 MB | -79% | |
| | CoreML FP16 | 20.8 MB | -79% | |
| | CoreML INT8 | 10.5 MB | -89% | |
|
|
| ## Model Architecture |
|
|
| ``` |
| Input: (1, 3, 320, 320) normalized RGB image |
| β |
| βΌ |
| ResNet50 backbone (layer4 cropped) β (1, 1024, 20, 20) |
| β |
| βΌ |
| MixVPR aggregator: |
| - 4Γ FeatureMixerLayer (LayerNorm β Linear β ReLU β Linear, residual) |
| - Channel projection (Linear: 1024 β 1024) |
| - Row projection (Linear: 400 β 4) |
| - Flatten + L2 normalize β (1, 4096) |
| ``` |
|
|
| Parameters: **10.88 M** |
|
|
| ## Usage |
|
|
| ### Download |
|
|
| ```bash |
| # All MixVPR models |
| huggingface-cli download Realcat/image_retrieval_checkpoints mixvpr/ --local-dir . |
| |
| # Single file |
| huggingface-cli download Realcat/image_retrieval_checkpoints mixvpr/onnx/mixvpr_fp16.onnx |
| ``` |
|
|
| ### Install Dependencies |
|
|
| ```bash |
| pip install onnxruntime # for ONNX |
| pip install coremltools # for CoreML (macOS only) |
| pip install torch torchvision Pillow numpy # for preprocessing |
| ``` |
|
|
| ### ONNX Inference |
|
|
| ```python |
| import onnxruntime as ort |
| import numpy as np |
| from PIL import Image |
| import torchvision.transforms as tvf |
| |
| sess = ort.InferenceSession("mixvpr/onnx/mixvpr_fp16.onnx", |
| providers=['CPUExecutionProvider']) |
| |
| # Images must be resized to 320Γ320 |
| preprocess = tvf.Compose([ |
| tvf.Resize((320, 320), interpolation=tvf.InterpolationMode.BICUBIC), |
| tvf.ToTensor(), |
| tvf.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), |
| ]) |
| |
| def extract_descriptor(image_path): |
| img = Image.open(image_path).convert("RGB") |
| tensor = preprocess(img).unsqueeze(0).numpy().astype(np.float32) |
| desc = sess.run(None, {'images': tensor})[0] |
| return desc # (1, 4096), L2-normalized |
| |
| # Compare two images via cosine similarity |
| d1 = extract_descriptor("query.jpg") |
| d2 = extract_descriptor("reference.jpg") |
| similarity = np.dot(d1.flatten(), d2.flatten()) |
| ``` |
|
|
| ### CoreML Inference (Apple Silicon, ~15Γ faster) |
|
|
| ```python |
| import coremltools as ct |
| import numpy as np |
| from PIL import Image |
| import torchvision.transforms as tvf |
| |
| mlmodel = ct.models.MLModel("mixvpr/coreml/mixvpr_fp16.mlpackage") |
| |
| preprocess = tvf.Compose([ |
| tvf.Resize((320, 320), interpolation=tvf.InterpolationMode.BICUBIC), |
| tvf.ToTensor(), |
| tvf.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), |
| ]) |
| |
| def extract_descriptor(image_path): |
| img = Image.open(image_path).convert("RGB") |
| tensor = preprocess(img).unsqueeze(0).numpy().astype(np.float32) |
| desc = mlmodel.predict({'images': tensor})['descriptor'] |
| return desc # (1, 4096), L2-normalized, runs on ANE + GPU |
| ``` |
|
|
| ## Notes |
|
|
| - **Input**: 320Γ320 RGB images, normalized with ImageNet stats. |
| - **Output**: 4096-dim L2-normalized global descriptor. Use cosine similarity for retrieval. |
| - **ONNX INT8/INT4**: Quantized models exist but the ONNX Runtime CPU EP lacks `ConvInteger` kernels for this architecture. Use a GPU EP (CUDA/TensorRT) or switch to CoreML for quantized inference. |
| - **Re-export**: Scripts available in the [source repo](https://github.com/Vincentqyw/MixVPR) (`export_quant_onnx.py`, `export_coreml.py`). |
|
|
| ## Reference |
|
|
| ```bibtex |
| @inproceedings{ali2023mixvpr, |
| title={{MixVPR}: Feature Mixing for Visual Place Recognition}, |
| author={Ali-bey, Amar and Chaib-draa, Brahim and Gigu{\`e}re, Philippe}, |
| booktitle={Proceedings of the IEEE/CVF Winter Conference on Applications of Computer Vision}, |
| pages={2998--3007}, |
| year={2023} |
| } |
| ``` |
|
|