hyper-models 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ # =============================================================================
2
+ # hyper_models - Model Zoo for Non-Euclidean Embeddings
3
+ # =============================================================================
4
+
5
+ # -----------------------------------------------------------------------------
6
+ # Python
7
+ # -----------------------------------------------------------------------------
8
+ __pycache__/
9
+ **/__pycache__/
10
+ *.py[cod]
11
+ *$py.class
12
+ *.so
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+
30
+ # -----------------------------------------------------------------------------
31
+ # Virtual Environments
32
+ # -----------------------------------------------------------------------------
33
+ .venv/
34
+ **/.venv/
35
+ venv/
36
+ ENV/
37
+ env/
38
+
39
+ # -----------------------------------------------------------------------------
40
+ # Large Local Artifacts (not committed - use HuggingFace Hub)
41
+ # -----------------------------------------------------------------------------
42
+ # Model checkpoints (PyTorch weights)
43
+ **/checkpoints/
44
+ *.pth
45
+ *.pt
46
+ *.bin
47
+ *.safetensors
48
+
49
+ # ONNX outputs (local exports before uploading to HF)
50
+ **/outputs/
51
+ *.onnx
52
+ *.onnx.data
53
+
54
+ # Cloned upstream repos (recreated via git clone)
55
+ hycoclip_repo/
56
+ **/hycoclip_repo/
57
+
58
+ # -----------------------------------------------------------------------------
59
+ # Package Management
60
+ # -----------------------------------------------------------------------------
61
+ # uv lockfile - can be committed for reproducibility, but optional
62
+ uv.lock
63
+
64
+ # pip
65
+ pip-log.txt
66
+ pip-delete-this-directory.txt
67
+
68
+ # -----------------------------------------------------------------------------
69
+ # Testing & Coverage
70
+ # -----------------------------------------------------------------------------
71
+ .tox/
72
+ .nox/
73
+ .coverage
74
+ .coverage.*
75
+ htmlcov/
76
+ .pytest_cache/
77
+ nosetests.xml
78
+ coverage.xml
79
+ *.cover
80
+ *.py,cover
81
+ .hypothesis/
82
+
83
+ # -----------------------------------------------------------------------------
84
+ # IDE / Editor
85
+ # -----------------------------------------------------------------------------
86
+ .idea/
87
+ .vscode/
88
+ *.swp
89
+ *.swo
90
+ *~
91
+ .project
92
+ .pydevproject
93
+ .settings/
94
+
95
+ # -----------------------------------------------------------------------------
96
+ # OS Generated
97
+ # -----------------------------------------------------------------------------
98
+ .DS_Store
99
+ .DS_Store?
100
+ ._*
101
+ .Spotlight-V100
102
+ .Trashes
103
+ ehthumbs.db
104
+ Thumbs.db
105
+
106
+ # -----------------------------------------------------------------------------
107
+ # Jupyter / IPython
108
+ # -----------------------------------------------------------------------------
109
+ .ipynb_checkpoints/
110
+ *.ipynb_checkpoints
111
+ profile_default/
112
+ ipython_config.py
113
+
114
+ # -----------------------------------------------------------------------------
115
+ # Documentation
116
+ # -----------------------------------------------------------------------------
117
+ docs/_build/
118
+ site/
119
+
120
+ # -----------------------------------------------------------------------------
121
+ # Misc
122
+ # -----------------------------------------------------------------------------
123
+ *.log
124
+ *.tmp
125
+ *.temp
126
+ .cache/
127
+ *.hf/
128
+ AGENTS.md
129
+ .specstory/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Hyper3Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyper-models
3
+ Version: 0.1.0
4
+ Summary: A model zoo for non-Euclidean embedding models (hyperbolic, spherical, product manifolds)
5
+ Project-URL: Homepage, https://github.com/Hyper3Labs/hyper-models
6
+ Project-URL: Repository, https://github.com/Hyper3Labs/hyper-models
7
+ Project-URL: Documentation, https://github.com/Hyper3Labs/hyper-models#readme
8
+ Project-URL: Issues, https://github.com/Hyper3Labs/hyper-models/issues
9
+ Author: Hyper3Labs
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: clip,embeddings,hyperbolic,model-zoo,non-euclidean,onnx
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: huggingface-hub>=1.0
24
+ Requires-Dist: numpy>=1.26
25
+ Requires-Dist: onnxruntime>=1.20
26
+ Requires-Dist: pillow>=10.0
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0; extra == 'dev'
29
+ Requires-Dist: ruff>=0.1; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # hyper-models
33
+
34
+ <p align="center">
35
+ <strong>A model zoo for non-Euclidean embedding models</strong>
36
+ <br>
37
+ <em>Hyperbolic · Spherical · Product Manifolds</em>
38
+ </p>
39
+
40
+ <p align="center">
41
+ <a href="https://huggingface.co/mnm-matin/hyperbolic-clip">
42
+ <img src="https://img.shields.io/badge/🤗_Models-hyperbolic--clip-orange" alt="Hugging Face">
43
+ </a>
44
+ <a href="LICENSE">
45
+ <img src="https://img.shields.io/badge/License-MIT-blue" alt="License: MIT">
46
+ </a>
47
+ </p>
48
+
49
+ ---
50
+
51
+ ## Why?
52
+
53
+ - **Standardized access** to non-Euclidean embedding models
54
+ - **Torch-free runtime** via ONNX (models published to Hugging Face Hub)
55
+ - **Simple API** — `load()` and `encode_images()`
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install hyper-models
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ```python
66
+ import hyper_models
67
+ from PIL import Image
68
+
69
+ # List available models
70
+ hyper_models.list_models()
71
+ # ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b']
72
+
73
+ # Load model (auto-downloads from Hugging Face Hub)
74
+ model = hyper_models.load("hycoclip-vit-s")
75
+ model.geometry # 'hyperboloid'
76
+ model.dim # 513
77
+
78
+ # Encode PIL images
79
+ images = [Image.open("image.jpg")]
80
+ embeddings = model.encode_images(images) # (1, 513) ndarray
81
+
82
+ # Get model info
83
+ info = hyper_models.get_model_info("hycoclip-vit-s")
84
+ info.hub_id # 'mnm-matin/hyperbolic-clip'
85
+ info.license # 'CC-BY-NC'
86
+
87
+ # Low-level: preprocess images yourself
88
+ batch = hyper_models.preprocess_images(images) # (B, 3, 224, 224)
89
+ embeddings = model.encode(batch)
90
+ ```
91
+
92
+ ## Models
93
+
94
+ ### Hyperbolic
95
+
96
+ | Model | Available | Paper | Code |
97
+ |-------|:---------:|-------|------|
98
+ | `hycoclip-vit-s` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/hycoclip-vit-s) | [ICLR 2025](https://arxiv.org/abs/2410.06912) | [PalAvik/hycoclip](https://github.com/PalAvik/hycoclip) |
99
+ | `hycoclip-vit-b` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/hycoclip-vit-b) | [ICLR 2025](https://arxiv.org/abs/2410.06912) | [PalAvik/hycoclip](https://github.com/PalAvik/hycoclip) |
100
+ | `meru-vit-s` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/meru-vit-s) | [ICML 2023](https://arxiv.org/abs/2304.09172) | [facebookresearch/meru](https://github.com/facebookresearch/meru) |
101
+ | `meru-vit-b` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/meru-vit-b) | [ICML 2023](https://arxiv.org/abs/2304.09172) | [facebookresearch/meru](https://github.com/facebookresearch/meru) |
102
+ | `hyp-vit` | — | [CVPR 2022](https://arxiv.org/abs/2203.10833) | [htdt/hyp_metric](https://github.com/htdt/hyp_metric) |
103
+ | `hie` | — | [CVPR 2020](https://arxiv.org/abs/1904.02239) | [leymir/hyperbolic-image-embeddings](https://github.com/leymir/hyperbolic-image-embeddings) |
104
+ | `hcnn` | — | [ICLR 2024](https://openreview.net/forum?id=ekz1hN5QNh) | [kschwethelm/HyperbolicCV](https://github.com/kschwethelm/HyperbolicCV) |
105
+
106
+ ### Spherical
107
+
108
+ | Model | Available | Paper | Code |
109
+ |-------|:---------:|-------|------|
110
+ | `sphereface` | — | [CVPR 2017](https://arxiv.org/abs/1704.08063) | [wy1iu/sphereface](https://github.com/wy1iu/sphereface) |
111
+ | `arcface` | — | [CVPR 2019](https://arxiv.org/abs/1801.07698) | [deepinsight/insightface](https://github.com/deepinsight/insightface) |
112
+
113
+ ### Product Manifolds
114
+
115
+ | Model | Available | Paper | Code |
116
+ |-------|:---------:|-------|------|
117
+ | `hyperbolics` | — | [ICLR 2019](https://openreview.net/forum?id=HJxeWnCcF7) | [HazyResearch/hyperbolics](https://github.com/HazyResearch/hyperbolics) |
118
+
119
+ ## Export Tooling
120
+
121
+ This repo also contains tooling to export PyTorch models to ONNX:
122
+
123
+ ```bash
124
+ cd export/hycoclip
125
+ uv run python export_onnx.py --checkpoint model.pth --onnx model.onnx
126
+ ```
127
+
128
+ See [export/hycoclip/README.md](export/hycoclip/README.md) for details.
129
+
130
+ ## References
131
+
132
+ - [HyCoCLIP](https://github.com/PalAvik/hycoclip)
133
+ - [MERU](https://github.com/facebookresearch/meru)
134
+ - [geoopt](https://github.com/geoopt/geoopt)
@@ -0,0 +1,103 @@
1
+ # hyper-models
2
+
3
+ <p align="center">
4
+ <strong>A model zoo for non-Euclidean embedding models</strong>
5
+ <br>
6
+ <em>Hyperbolic · Spherical · Product Manifolds</em>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://huggingface.co/mnm-matin/hyperbolic-clip">
11
+ <img src="https://img.shields.io/badge/🤗_Models-hyperbolic--clip-orange" alt="Hugging Face">
12
+ </a>
13
+ <a href="LICENSE">
14
+ <img src="https://img.shields.io/badge/License-MIT-blue" alt="License: MIT">
15
+ </a>
16
+ </p>
17
+
18
+ ---
19
+
20
+ ## Why?
21
+
22
+ - **Standardized access** to non-Euclidean embedding models
23
+ - **Torch-free runtime** via ONNX (models published to Hugging Face Hub)
24
+ - **Simple API** — `load()` and `encode_images()`
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pip install hyper-models
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```python
35
+ import hyper_models
36
+ from PIL import Image
37
+
38
+ # List available models
39
+ hyper_models.list_models()
40
+ # ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b']
41
+
42
+ # Load model (auto-downloads from Hugging Face Hub)
43
+ model = hyper_models.load("hycoclip-vit-s")
44
+ model.geometry # 'hyperboloid'
45
+ model.dim # 513
46
+
47
+ # Encode PIL images
48
+ images = [Image.open("image.jpg")]
49
+ embeddings = model.encode_images(images) # (1, 513) ndarray
50
+
51
+ # Get model info
52
+ info = hyper_models.get_model_info("hycoclip-vit-s")
53
+ info.hub_id # 'mnm-matin/hyperbolic-clip'
54
+ info.license # 'CC-BY-NC'
55
+
56
+ # Low-level: preprocess images yourself
57
+ batch = hyper_models.preprocess_images(images) # (B, 3, 224, 224)
58
+ embeddings = model.encode(batch)
59
+ ```
60
+
61
+ ## Models
62
+
63
+ ### Hyperbolic
64
+
65
+ | Model | Available | Paper | Code |
66
+ |-------|:---------:|-------|------|
67
+ | `hycoclip-vit-s` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/hycoclip-vit-s) | [ICLR 2025](https://arxiv.org/abs/2410.06912) | [PalAvik/hycoclip](https://github.com/PalAvik/hycoclip) |
68
+ | `hycoclip-vit-b` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/hycoclip-vit-b) | [ICLR 2025](https://arxiv.org/abs/2410.06912) | [PalAvik/hycoclip](https://github.com/PalAvik/hycoclip) |
69
+ | `meru-vit-s` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/meru-vit-s) | [ICML 2023](https://arxiv.org/abs/2304.09172) | [facebookresearch/meru](https://github.com/facebookresearch/meru) |
70
+ | `meru-vit-b` | [![HF](https://img.shields.io/badge/🤗-HuggingFace-yellow)](https://huggingface.co/mnm-matin/hyperbolic-clip/tree/main/meru-vit-b) | [ICML 2023](https://arxiv.org/abs/2304.09172) | [facebookresearch/meru](https://github.com/facebookresearch/meru) |
71
+ | `hyp-vit` | — | [CVPR 2022](https://arxiv.org/abs/2203.10833) | [htdt/hyp_metric](https://github.com/htdt/hyp_metric) |
72
+ | `hie` | — | [CVPR 2020](https://arxiv.org/abs/1904.02239) | [leymir/hyperbolic-image-embeddings](https://github.com/leymir/hyperbolic-image-embeddings) |
73
+ | `hcnn` | — | [ICLR 2024](https://openreview.net/forum?id=ekz1hN5QNh) | [kschwethelm/HyperbolicCV](https://github.com/kschwethelm/HyperbolicCV) |
74
+
75
+ ### Spherical
76
+
77
+ | Model | Available | Paper | Code |
78
+ |-------|:---------:|-------|------|
79
+ | `sphereface` | — | [CVPR 2017](https://arxiv.org/abs/1704.08063) | [wy1iu/sphereface](https://github.com/wy1iu/sphereface) |
80
+ | `arcface` | — | [CVPR 2019](https://arxiv.org/abs/1801.07698) | [deepinsight/insightface](https://github.com/deepinsight/insightface) |
81
+
82
+ ### Product Manifolds
83
+
84
+ | Model | Available | Paper | Code |
85
+ |-------|:---------:|-------|------|
86
+ | `hyperbolics` | — | [ICLR 2019](https://openreview.net/forum?id=HJxeWnCcF7) | [HazyResearch/hyperbolics](https://github.com/HazyResearch/hyperbolics) |
87
+
88
+ ## Export Tooling
89
+
90
+ This repo also contains tooling to export PyTorch models to ONNX:
91
+
92
+ ```bash
93
+ cd export/hycoclip
94
+ uv run python export_onnx.py --checkpoint model.pth --onnx model.onnx
95
+ ```
96
+
97
+ See [export/hycoclip/README.md](export/hycoclip/README.md) for details.
98
+
99
+ ## References
100
+
101
+ - [HyCoCLIP](https://github.com/PalAvik/hycoclip)
102
+ - [MERU](https://github.com/facebookresearch/meru)
103
+ - [geoopt](https://github.com/geoopt/geoopt)
@@ -0,0 +1,59 @@
1
+ [project]
2
+ name = "hyper-models"
3
+ version = "0.1.0"
4
+ description = "A model zoo for non-Euclidean embedding models (hyperbolic, spherical, product manifolds)"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ requires-python = ">=3.10"
8
+ authors = [{ name = "Hyper3Labs" }]
9
+ keywords = ["embeddings", "hyperbolic", "onnx", "clip", "model-zoo", "non-euclidean"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Developers",
13
+ "Intended Audience :: Science/Research",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ ]
21
+ dependencies = [
22
+ "numpy>=1.26",
23
+ "onnxruntime>=1.20",
24
+ "huggingface-hub>=1.0",
25
+ "pillow>=10.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest>=7.0",
31
+ "ruff>=0.1",
32
+ ]
33
+
34
+ [project.urls]
35
+ Homepage = "https://github.com/Hyper3Labs/hyper-models"
36
+ Repository = "https://github.com/Hyper3Labs/hyper-models"
37
+ Documentation = "https://github.com/Hyper3Labs/hyper-models#readme"
38
+ Issues = "https://github.com/Hyper3Labs/hyper-models/issues"
39
+
40
+ [build-system]
41
+ requires = ["hatchling"]
42
+ build-backend = "hatchling.build"
43
+
44
+ [tool.hatch.build.targets.wheel]
45
+ packages = ["src/hyper_models"]
46
+
47
+ [tool.hatch.build.targets.sdist]
48
+ include = ["/src", "/README.md", "/LICENSE"]
49
+
50
+ [tool.ruff]
51
+ line-length = 100
52
+ target-version = "py310"
53
+
54
+ [tool.ruff.lint]
55
+ select = ["E", "F", "I", "W"]
56
+ ignore = ["E501"]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
@@ -0,0 +1,28 @@
1
+ """hyper-models: A model zoo for non-Euclidean embedding models.
2
+
3
+ Hyperbolic, spherical, and product manifold models with torch-free ONNX inference.
4
+
5
+ Example:
6
+ >>> import hyper_models
7
+ >>> model = hyper_models.load("hycoclip-vit-s")
8
+ >>> embeddings = model.encode_images([Image.open("photo.jpg")])
9
+ >>> model.geometry # 'hyperboloid'
10
+ >>> model.dim # 513
11
+ """
12
+
13
+ from hyper_models.loader import load
14
+ from hyper_models.registry import ModelInfo, get_model_info, list_models
15
+ from hyper_models.models import ONNXModel
16
+ from hyper_models.preprocessing import ImageConfig, preprocess_images
17
+
18
+ __all__ = [
19
+ "load",
20
+ "list_models",
21
+ "get_model_info",
22
+ "ModelInfo",
23
+ "ONNXModel",
24
+ "ImageConfig",
25
+ "preprocess_images",
26
+ ]
27
+ __version__ = "0.1.0"
28
+
@@ -0,0 +1,45 @@
1
+ """Model loading - download from Hub and instantiate."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ from huggingface_hub import snapshot_download
8
+
9
+ from hyper_models.models import ONNXModel
10
+ from hyper_models.registry import get_model_info
11
+
12
+ __all__ = ["load"]
13
+
14
+
15
+ def load(name: str, *, local_path: str | Path | None = None) -> ONNXModel:
16
+ """Load a model by name.
17
+
18
+ Args:
19
+ name: Model name (e.g., 'hycoclip-vit-s').
20
+ local_path: Optional local ONNX path (skips Hub download).
21
+
22
+ Returns:
23
+ Model instance ready for inference.
24
+
25
+ Example:
26
+ >>> model = hyper_models.load("hycoclip-vit-s")
27
+ >>> embeddings = model.encode_images([Image.open("photo.jpg")])
28
+ """
29
+ info = get_model_info(name)
30
+
31
+ if local_path is None:
32
+ hub_path = f"{info.name}/model.onnx"
33
+ local_dir = snapshot_download(info.hub_id, allow_patterns=[f"{hub_path}*"])
34
+ local_path = Path(local_dir) / hub_path
35
+ else:
36
+ local_path = Path(local_path)
37
+
38
+ return ONNXModel(
39
+ path=Path(local_path),
40
+ geometry=info.geometry,
41
+ dim=info.dim,
42
+ input_name=info.input_name,
43
+ output_name=info.output_name,
44
+ image_config=info.image_config,
45
+ )
@@ -0,0 +1,55 @@
1
+ """ONNX model wrapper for hyper-models."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ import numpy as np
8
+ from PIL import Image
9
+
10
+ from hyper_models.preprocessing import ImageConfig, preprocess_images
11
+
12
+ __all__ = ["ONNXModel"]
13
+
14
+
15
+ class ONNXModel:
16
+ """ONNX Runtime model wrapper for embedding inference."""
17
+
18
+ def __init__(
19
+ self,
20
+ path: Path,
21
+ geometry: str,
22
+ dim: int,
23
+ *,
24
+ input_name: str = "image",
25
+ output_name: str | None = None,
26
+ image_config: ImageConfig | None = None,
27
+ ) -> None:
28
+ self._path = path
29
+ self.geometry = geometry
30
+ self.dim = dim
31
+ self._input_name = input_name
32
+ self._output_name = output_name
33
+ self._image_config = image_config or ImageConfig()
34
+ self._session = None
35
+
36
+ def _ensure_session(self) -> None:
37
+ if self._session is None:
38
+ import onnxruntime as ort
39
+
40
+ self._session = ort.InferenceSession(str(self._path), providers=["CPUExecutionProvider"])
41
+
42
+ def encode(self, inputs: np.ndarray) -> np.ndarray:
43
+ """Encode preprocessed inputs (B, C, H, W) to embeddings (B, D)."""
44
+ self._ensure_session()
45
+ outputs = self._session.run(None, {self._input_name: inputs})
46
+
47
+ if self._output_name:
48
+ output_names = [o.name for o in self._session.get_outputs()]
49
+ return np.asarray(outputs[output_names.index(self._output_name)], dtype=np.float32)
50
+
51
+ return np.asarray(outputs[0], dtype=np.float32)
52
+
53
+ def encode_images(self, images: list[Image.Image]) -> np.ndarray:
54
+ """Encode PIL images to embeddings (B, D)."""
55
+ return self.encode(preprocess_images(images, self._image_config))
@@ -0,0 +1,70 @@
1
+ """Image preprocessing for ONNX inference."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Literal
7
+
8
+ import numpy as np
9
+ from PIL import Image
10
+
11
+ __all__ = ["preprocess_images", "ImageConfig"]
12
+
13
+ _RESAMPLE = {
14
+ "nearest": Image.Resampling.NEAREST,
15
+ "bilinear": Image.Resampling.BILINEAR,
16
+ "bicubic": Image.Resampling.BICUBIC,
17
+ "lanczos": Image.Resampling.LANCZOS,
18
+ }
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class ImageConfig:
23
+ """Image preprocessing configuration (CLIP-style defaults)."""
24
+
25
+ size: int = 224
26
+ interpolation: Literal["nearest", "bilinear", "bicubic", "lanczos"] = "bicubic"
27
+ rescale: float = 1.0 / 255.0
28
+ mean: tuple[float, float, float] | None = None
29
+ std: tuple[float, float, float] | None = None
30
+
31
+
32
+ def preprocess_images(images: list[Image.Image], config: ImageConfig | None = None) -> np.ndarray:
33
+ """Preprocess PIL images for ONNX inference.
34
+
35
+ Args:
36
+ images: List of PIL Images.
37
+ config: Preprocessing config. Uses CLIP defaults if None.
38
+
39
+ Returns:
40
+ (B, 3, H, H) float32 array.
41
+ """
42
+ config = config or ImageConfig()
43
+ resample = _RESAMPLE[config.interpolation]
44
+
45
+ batch = []
46
+ for img in images:
47
+ if img.mode != "RGB":
48
+ img = img.convert("RGB")
49
+
50
+ # Resize shortest side, then center crop
51
+ w, h = img.size
52
+ scale = config.size / min(w, h)
53
+ img = img.resize((int(round(w * scale)), int(round(h * scale))), resample=resample)
54
+
55
+ w, h = img.size
56
+ left, top = (w - config.size) // 2, (h - config.size) // 2
57
+ img = img.crop((left, top, left + config.size, top + config.size))
58
+
59
+ # To float32 CHW
60
+ arr = np.asarray(img, dtype=np.float32) * config.rescale
61
+ arr = np.transpose(arr, (2, 0, 1))
62
+
63
+ if config.mean is not None and config.std is not None:
64
+ mean = np.array(config.mean, dtype=np.float32).reshape(3, 1, 1)
65
+ std = np.array(config.std, dtype=np.float32).reshape(3, 1, 1)
66
+ arr = (arr - mean) / std
67
+
68
+ batch.append(arr)
69
+
70
+ return np.stack(batch, axis=0)
@@ -0,0 +1,78 @@
1
+ """Model registry - maps model names to hub locations and metadata."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+ from hyper_models.preprocessing import ImageConfig
8
+
9
+ __all__ = ["ModelInfo", "list_models", "get_model_info"]
10
+
11
+
12
+ @dataclass
13
+ class ModelInfo:
14
+ """Metadata for a registered model."""
15
+
16
+ name: str
17
+ geometry: str # 'hyperboloid', 'poincare', 'sphere', 'euclidean'
18
+ dim: int
19
+ hub_id: str
20
+ license: str
21
+ description: str = ""
22
+ input_name: str = "image"
23
+ output_name: str | None = None
24
+ image_config: ImageConfig = field(default_factory=ImageConfig)
25
+
26
+
27
+ _MODELS: dict[str, ModelInfo] = {
28
+ "hycoclip-vit-s": ModelInfo(
29
+ name="hycoclip-vit-s",
30
+ geometry="hyperboloid",
31
+ dim=513,
32
+ hub_id="mnm-matin/hyperbolic-clip",
33
+ license="CC-BY-NC",
34
+ description="HyCoCLIP ViT-Small (512D hyperboloid)",
35
+ output_name="embedding_hyperboloid",
36
+ ),
37
+ "hycoclip-vit-b": ModelInfo(
38
+ name="hycoclip-vit-b",
39
+ geometry="hyperboloid",
40
+ dim=513,
41
+ hub_id="mnm-matin/hyperbolic-clip",
42
+ license="CC-BY-NC",
43
+ description="HyCoCLIP ViT-Base (512D hyperboloid)",
44
+ output_name="embedding_hyperboloid",
45
+ ),
46
+ "meru-vit-s": ModelInfo(
47
+ name="meru-vit-s",
48
+ geometry="hyperboloid",
49
+ dim=513,
50
+ hub_id="mnm-matin/hyperbolic-clip",
51
+ license="CC-BY-NC",
52
+ description="MERU ViT-Small (512D hyperboloid)",
53
+ output_name="embedding_hyperboloid",
54
+ ),
55
+ "meru-vit-b": ModelInfo(
56
+ name="meru-vit-b",
57
+ geometry="hyperboloid",
58
+ dim=513,
59
+ hub_id="mnm-matin/hyperbolic-clip",
60
+ license="CC-BY-NC",
61
+ description="MERU ViT-Base (512D hyperboloid)",
62
+ output_name="embedding_hyperboloid",
63
+ ),
64
+ }
65
+
66
+
67
+ def list_models(geometry: str | None = None) -> list[str]:
68
+ """List available model names, optionally filtered by geometry."""
69
+ if geometry is None:
70
+ return list(_MODELS.keys())
71
+ return [name for name, info in _MODELS.items() if info.geometry == geometry]
72
+
73
+
74
+ def get_model_info(name: str) -> ModelInfo:
75
+ """Get metadata for a model. Raises KeyError if not found."""
76
+ if name not in _MODELS:
77
+ raise KeyError(f"Model '{name}' not found. Available: {', '.join(_MODELS.keys())}")
78
+ return _MODELS[name]