hyper-models 0.1.0__tar.gz → 0.2.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.
- {hyper_models-0.1.0 → hyper_models-0.2.0}/PKG-INFO +76 -10
- {hyper_models-0.1.0 → hyper_models-0.2.0}/README.md +71 -8
- {hyper_models-0.1.0 → hyper_models-0.2.0}/pyproject.toml +6 -2
- {hyper_models-0.1.0 → hyper_models-0.2.0}/src/hyper_models/__init__.py +5 -2
- {hyper_models-0.1.0 → hyper_models-0.2.0}/src/hyper_models/loader.py +15 -18
- hyper_models-0.2.0/src/hyper_models/loaders.py +72 -0
- {hyper_models-0.1.0 → hyper_models-0.2.0}/src/hyper_models/registry.py +50 -2
- hyper_models-0.2.0/src/hyper_models/torch_models.py +230 -0
- {hyper_models-0.1.0 → hyper_models-0.2.0}/.gitignore +0 -0
- {hyper_models-0.1.0 → hyper_models-0.2.0}/LICENSE +0 -0
- {hyper_models-0.1.0 → hyper_models-0.2.0}/src/hyper_models/models.py +0 -0
- {hyper_models-0.1.0 → hyper_models-0.2.0}/src/hyper_models/preprocessing.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyper-models
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A model zoo for non-Euclidean embedding models (hyperbolic, spherical, product manifolds)
|
|
5
5
|
Project-URL: Homepage, https://github.com/Hyper3Labs/hyper-models
|
|
6
6
|
Project-URL: Repository, https://github.com/Hyper3Labs/hyper-models
|
|
7
7
|
Project-URL: Documentation, https://github.com/Hyper3Labs/hyper-models#readme
|
|
8
8
|
Project-URL: Issues, https://github.com/Hyper3Labs/hyper-models/issues
|
|
9
|
-
Author:
|
|
9
|
+
Author: hyper3labs
|
|
10
10
|
License: MIT
|
|
11
11
|
License-File: LICENSE
|
|
12
12
|
Keywords: clip,embeddings,hyperbolic,model-zoo,non-euclidean,onnx
|
|
@@ -27,6 +27,9 @@ Requires-Dist: pillow>=10.0
|
|
|
27
27
|
Provides-Extra: dev
|
|
28
28
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
29
29
|
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
30
|
+
Provides-Extra: ml
|
|
31
|
+
Requires-Dist: timm>=1.0.0; extra == 'ml'
|
|
32
|
+
Requires-Dist: torch>=2.9.1; extra == 'ml'
|
|
30
33
|
Description-Content-Type: text/markdown
|
|
31
34
|
|
|
32
35
|
# hyper-models
|
|
@@ -51,13 +54,22 @@ Description-Content-Type: text/markdown
|
|
|
51
54
|
## Why?
|
|
52
55
|
|
|
53
56
|
- **Standardized access** to non-Euclidean embedding models
|
|
54
|
-
- **
|
|
57
|
+
- **One catalog surface**: model names map to internal loaders such as ONNX or optional torch-backed runtimes
|
|
55
58
|
- **Simple API** — `load()` and `encode_images()`
|
|
56
59
|
|
|
57
60
|
## Installation
|
|
58
61
|
|
|
59
62
|
```bash
|
|
60
|
-
pip install hyper-models
|
|
63
|
+
uv pip install hyper-models
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This base install is the simple path: it stays **torch-free** and is enough for
|
|
67
|
+
ONNX-backed catalog entries such as HyCoCLIP and MERU.
|
|
68
|
+
|
|
69
|
+
For torch-backed checkpoints (for example UNCHA):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv pip install "hyper-models[ml]"
|
|
61
73
|
```
|
|
62
74
|
|
|
63
75
|
## Usage
|
|
@@ -68,7 +80,11 @@ from PIL import Image
|
|
|
68
80
|
|
|
69
81
|
# List available models
|
|
70
82
|
hyper_models.list_models()
|
|
71
|
-
# ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b']
|
|
83
|
+
# ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b', 'uncha-vit-s', 'uncha-vit-b']
|
|
84
|
+
|
|
85
|
+
# Inspect supported internal loader kinds
|
|
86
|
+
hyper_models.list_loaders()
|
|
87
|
+
# ['onnx', 'uncha-image-torch']
|
|
72
88
|
|
|
73
89
|
# Load model (auto-downloads from Hugging Face Hub)
|
|
74
90
|
model = hyper_models.load("hycoclip-vit-s")
|
|
@@ -82,6 +98,7 @@ embeddings = model.encode_images(images) # (1, 513) ndarray
|
|
|
82
98
|
# Get model info
|
|
83
99
|
info = hyper_models.get_model_info("hycoclip-vit-s")
|
|
84
100
|
info.hub_id # 'mnm-matin/hyperbolic-clip'
|
|
101
|
+
info.loader # 'onnx'
|
|
85
102
|
info.license # 'CC-BY-NC'
|
|
86
103
|
|
|
87
104
|
# Low-level: preprocess images yourself
|
|
@@ -89,6 +106,51 @@ batch = hyper_models.preprocess_images(images) # (B, 3, 224, 224)
|
|
|
89
106
|
embeddings = model.encode(batch)
|
|
90
107
|
```
|
|
91
108
|
|
|
109
|
+
### Architecture
|
|
110
|
+
|
|
111
|
+
`hyper-models` is intended to be a timm-like catalog for non-Euclidean models.
|
|
112
|
+
|
|
113
|
+
- The public abstraction is the catalog entry name, for example `hycoclip-vit-s`.
|
|
114
|
+
- Each entry declares metadata such as geometry, dimensionality, artifact path,
|
|
115
|
+
and an internal loader kind.
|
|
116
|
+
- Internal loaders may differ by model family:
|
|
117
|
+
- `onnx` for exported, torch-free runtimes
|
|
118
|
+
- `uncha-image-torch` for raw checkpoints that need a PyTorch image runtime
|
|
119
|
+
|
|
120
|
+
This keeps callers on one stable API:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
model = hyper_models.load("hycoclip-vit-s")
|
|
124
|
+
model = hyper_models.load("uncha-vit-b")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Callers do not need to know which internal loader is used, except for optional
|
|
128
|
+
dependency installation when choosing entries that need `hyper-models[ml]`.
|
|
129
|
+
|
|
130
|
+
### HyperView integration
|
|
131
|
+
|
|
132
|
+
HyperView auto-detects `hyper-models` names and routes them to the `hyper-models` provider.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import hyperview as hv
|
|
136
|
+
|
|
137
|
+
dataset = hv.Dataset.from_huggingface(
|
|
138
|
+
name="demo",
|
|
139
|
+
hf_dataset="uoft-cs/cifar10",
|
|
140
|
+
split="train",
|
|
141
|
+
image_key="img",
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Uses provider='hyper-models' automatically.
|
|
145
|
+
space_key = dataset.compute_embeddings(model="uncha-vit-b")
|
|
146
|
+
layout_key = dataset.compute_visualization(space_key=space_key, layout="poincare")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
HyperView's simple path remains torch-free. If you use the default ONNX-backed
|
|
150
|
+
`hyper-models` entries or the default `embed-anything` provider, HyperView does
|
|
151
|
+
not need PyTorch. PyTorch is only needed when you explicitly select a
|
|
152
|
+
torch-backed catalog entry such as `uncha-vit-s` or `uncha-vit-b`.
|
|
153
|
+
|
|
92
154
|
## Models
|
|
93
155
|
|
|
94
156
|
### Hyperbolic
|
|
@@ -99,16 +161,20 @@ embeddings = model.encode(batch)
|
|
|
99
161
|
| `hycoclip-vit-b` | [](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
162
|
| `meru-vit-s` | [](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
163
|
| `meru-vit-b` | [](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) |
|
|
164
|
+
| `uncha-vit-s` | [](https://huggingface.co/hayeonkim/uncha/blob/main/uncha_vit_s.pth) | [CVPR 2026](https://arxiv.org/abs/2603.22042) | [jeeit17/UNCHA](https://github.com/jeeit17/UNCHA) |
|
|
165
|
+
| `uncha-vit-b` | [](https://huggingface.co/hayeonkim/uncha/blob/main/uncha_vit_b.pth) | [CVPR 2026](https://arxiv.org/abs/2603.22042) | [jeeit17/UNCHA](https://github.com/jeeit17/UNCHA) |
|
|
102
166
|
| `hyp-vit` | — | [CVPR 2022](https://arxiv.org/abs/2203.10833) | [htdt/hyp_metric](https://github.com/htdt/hyp_metric) |
|
|
103
167
|
| `hie` | — | [CVPR 2020](https://arxiv.org/abs/1904.02239) | [leymir/hyperbolic-image-embeddings](https://github.com/leymir/hyperbolic-image-embeddings) |
|
|
104
168
|
| `hcnn` | — | [ICLR 2024](https://openreview.net/forum?id=ekz1hN5QNh) | [kschwethelm/HyperbolicCV](https://github.com/kschwethelm/HyperbolicCV) |
|
|
105
169
|
|
|
106
|
-
###
|
|
170
|
+
### Hyperspherical
|
|
171
|
+
|
|
172
|
+
| Model | Available | Paper | Code |
|
|
173
|
+
|------------------|:---------:|-------|------|
|
|
174
|
+
| `megadescriptor` (via timm) | [](https://huggingface.co/BVRA/MegaDescriptor-L-384) | [WACV 2024](https://openaccess.thecvf.com/content/WACV2024/papers/Cermak_WildlifeDatasets_An_Open-Source_Toolkit_for_Animal_Re-Identification_WACV_2024_paper.pdf) | [WildlifeDatasets/wildlife-datasets](https://github.com/WildlifeDatasets/wildlife-datasets) |
|
|
175
|
+
| `sphereface` | — | [CVPR 2017](https://arxiv.org/abs/1704.08063) | [wy1iu/sphereface](https://github.com/wy1iu/sphereface) |
|
|
176
|
+
| `arcface` | — | [CVPR 2019](https://arxiv.org/abs/1801.07698) | [deepinsight/insightface](https://github.com/deepinsight/insightface) |
|
|
107
177
|
|
|
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
178
|
|
|
113
179
|
### Product Manifolds
|
|
114
180
|
|
|
@@ -20,13 +20,22 @@
|
|
|
20
20
|
## Why?
|
|
21
21
|
|
|
22
22
|
- **Standardized access** to non-Euclidean embedding models
|
|
23
|
-
- **
|
|
23
|
+
- **One catalog surface**: model names map to internal loaders such as ONNX or optional torch-backed runtimes
|
|
24
24
|
- **Simple API** — `load()` and `encode_images()`
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
pip install hyper-models
|
|
29
|
+
uv pip install hyper-models
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This base install is the simple path: it stays **torch-free** and is enough for
|
|
33
|
+
ONNX-backed catalog entries such as HyCoCLIP and MERU.
|
|
34
|
+
|
|
35
|
+
For torch-backed checkpoints (for example UNCHA):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv pip install "hyper-models[ml]"
|
|
30
39
|
```
|
|
31
40
|
|
|
32
41
|
## Usage
|
|
@@ -37,7 +46,11 @@ from PIL import Image
|
|
|
37
46
|
|
|
38
47
|
# List available models
|
|
39
48
|
hyper_models.list_models()
|
|
40
|
-
# ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b']
|
|
49
|
+
# ['hycoclip-vit-s', 'hycoclip-vit-b', 'meru-vit-s', 'meru-vit-b', 'uncha-vit-s', 'uncha-vit-b']
|
|
50
|
+
|
|
51
|
+
# Inspect supported internal loader kinds
|
|
52
|
+
hyper_models.list_loaders()
|
|
53
|
+
# ['onnx', 'uncha-image-torch']
|
|
41
54
|
|
|
42
55
|
# Load model (auto-downloads from Hugging Face Hub)
|
|
43
56
|
model = hyper_models.load("hycoclip-vit-s")
|
|
@@ -51,6 +64,7 @@ embeddings = model.encode_images(images) # (1, 513) ndarray
|
|
|
51
64
|
# Get model info
|
|
52
65
|
info = hyper_models.get_model_info("hycoclip-vit-s")
|
|
53
66
|
info.hub_id # 'mnm-matin/hyperbolic-clip'
|
|
67
|
+
info.loader # 'onnx'
|
|
54
68
|
info.license # 'CC-BY-NC'
|
|
55
69
|
|
|
56
70
|
# Low-level: preprocess images yourself
|
|
@@ -58,6 +72,51 @@ batch = hyper_models.preprocess_images(images) # (B, 3, 224, 224)
|
|
|
58
72
|
embeddings = model.encode(batch)
|
|
59
73
|
```
|
|
60
74
|
|
|
75
|
+
### Architecture
|
|
76
|
+
|
|
77
|
+
`hyper-models` is intended to be a timm-like catalog for non-Euclidean models.
|
|
78
|
+
|
|
79
|
+
- The public abstraction is the catalog entry name, for example `hycoclip-vit-s`.
|
|
80
|
+
- Each entry declares metadata such as geometry, dimensionality, artifact path,
|
|
81
|
+
and an internal loader kind.
|
|
82
|
+
- Internal loaders may differ by model family:
|
|
83
|
+
- `onnx` for exported, torch-free runtimes
|
|
84
|
+
- `uncha-image-torch` for raw checkpoints that need a PyTorch image runtime
|
|
85
|
+
|
|
86
|
+
This keeps callers on one stable API:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
model = hyper_models.load("hycoclip-vit-s")
|
|
90
|
+
model = hyper_models.load("uncha-vit-b")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Callers do not need to know which internal loader is used, except for optional
|
|
94
|
+
dependency installation when choosing entries that need `hyper-models[ml]`.
|
|
95
|
+
|
|
96
|
+
### HyperView integration
|
|
97
|
+
|
|
98
|
+
HyperView auto-detects `hyper-models` names and routes them to the `hyper-models` provider.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import hyperview as hv
|
|
102
|
+
|
|
103
|
+
dataset = hv.Dataset.from_huggingface(
|
|
104
|
+
name="demo",
|
|
105
|
+
hf_dataset="uoft-cs/cifar10",
|
|
106
|
+
split="train",
|
|
107
|
+
image_key="img",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Uses provider='hyper-models' automatically.
|
|
111
|
+
space_key = dataset.compute_embeddings(model="uncha-vit-b")
|
|
112
|
+
layout_key = dataset.compute_visualization(space_key=space_key, layout="poincare")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
HyperView's simple path remains torch-free. If you use the default ONNX-backed
|
|
116
|
+
`hyper-models` entries or the default `embed-anything` provider, HyperView does
|
|
117
|
+
not need PyTorch. PyTorch is only needed when you explicitly select a
|
|
118
|
+
torch-backed catalog entry such as `uncha-vit-s` or `uncha-vit-b`.
|
|
119
|
+
|
|
61
120
|
## Models
|
|
62
121
|
|
|
63
122
|
### Hyperbolic
|
|
@@ -68,16 +127,20 @@ embeddings = model.encode(batch)
|
|
|
68
127
|
| `hycoclip-vit-b` | [](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
128
|
| `meru-vit-s` | [](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
129
|
| `meru-vit-b` | [](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) |
|
|
130
|
+
| `uncha-vit-s` | [](https://huggingface.co/hayeonkim/uncha/blob/main/uncha_vit_s.pth) | [CVPR 2026](https://arxiv.org/abs/2603.22042) | [jeeit17/UNCHA](https://github.com/jeeit17/UNCHA) |
|
|
131
|
+
| `uncha-vit-b` | [](https://huggingface.co/hayeonkim/uncha/blob/main/uncha_vit_b.pth) | [CVPR 2026](https://arxiv.org/abs/2603.22042) | [jeeit17/UNCHA](https://github.com/jeeit17/UNCHA) |
|
|
71
132
|
| `hyp-vit` | — | [CVPR 2022](https://arxiv.org/abs/2203.10833) | [htdt/hyp_metric](https://github.com/htdt/hyp_metric) |
|
|
72
133
|
| `hie` | — | [CVPR 2020](https://arxiv.org/abs/1904.02239) | [leymir/hyperbolic-image-embeddings](https://github.com/leymir/hyperbolic-image-embeddings) |
|
|
73
134
|
| `hcnn` | — | [ICLR 2024](https://openreview.net/forum?id=ekz1hN5QNh) | [kschwethelm/HyperbolicCV](https://github.com/kschwethelm/HyperbolicCV) |
|
|
74
135
|
|
|
75
|
-
###
|
|
136
|
+
### Hyperspherical
|
|
137
|
+
|
|
138
|
+
| Model | Available | Paper | Code |
|
|
139
|
+
|------------------|:---------:|-------|------|
|
|
140
|
+
| `megadescriptor` (via timm) | [](https://huggingface.co/BVRA/MegaDescriptor-L-384) | [WACV 2024](https://openaccess.thecvf.com/content/WACV2024/papers/Cermak_WildlifeDatasets_An_Open-Source_Toolkit_for_Animal_Re-Identification_WACV_2024_paper.pdf) | [WildlifeDatasets/wildlife-datasets](https://github.com/WildlifeDatasets/wildlife-datasets) |
|
|
141
|
+
| `sphereface` | — | [CVPR 2017](https://arxiv.org/abs/1704.08063) | [wy1iu/sphereface](https://github.com/wy1iu/sphereface) |
|
|
142
|
+
| `arcface` | — | [CVPR 2019](https://arxiv.org/abs/1801.07698) | [deepinsight/insightface](https://github.com/deepinsight/insightface) |
|
|
76
143
|
|
|
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
144
|
|
|
82
145
|
### Product Manifolds
|
|
83
146
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hyper-models"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "A model zoo for non-Euclidean embedding models (hyperbolic, spherical, product manifolds)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
7
7
|
requires-python = ">=3.10"
|
|
8
|
-
authors = [{ name = "
|
|
8
|
+
authors = [{ name = "hyper3labs" }]
|
|
9
9
|
keywords = ["embeddings", "hyperbolic", "onnx", "clip", "model-zoo", "non-euclidean"]
|
|
10
10
|
classifiers = [
|
|
11
11
|
"Development Status :: 3 - Alpha",
|
|
@@ -30,6 +30,10 @@ dev = [
|
|
|
30
30
|
"pytest>=7.0",
|
|
31
31
|
"ruff>=0.1",
|
|
32
32
|
]
|
|
33
|
+
ml = [
|
|
34
|
+
"torch>=2.9.1",
|
|
35
|
+
"timm>=1.0.0",
|
|
36
|
+
]
|
|
33
37
|
|
|
34
38
|
[project.urls]
|
|
35
39
|
Homepage = "https://github.com/Hyper3Labs/hyper-models"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""hyper-models: A model zoo for non-Euclidean embedding models.
|
|
2
2
|
|
|
3
|
-
Hyperbolic, spherical, and product manifold models
|
|
3
|
+
Hyperbolic, spherical, and product manifold models exposed through one catalog
|
|
4
|
+
surface, with internal loaders such as ONNX and optional torch-backed runtimes.
|
|
4
5
|
|
|
5
6
|
Example:
|
|
6
7
|
>>> import hyper_models
|
|
@@ -11,12 +12,14 @@ Example:
|
|
|
11
12
|
"""
|
|
12
13
|
|
|
13
14
|
from hyper_models.loader import load
|
|
15
|
+
from hyper_models.loaders import list_loaders
|
|
14
16
|
from hyper_models.registry import ModelInfo, get_model_info, list_models
|
|
15
17
|
from hyper_models.models import ONNXModel
|
|
16
18
|
from hyper_models.preprocessing import ImageConfig, preprocess_images
|
|
17
19
|
|
|
18
20
|
__all__ = [
|
|
19
21
|
"load",
|
|
22
|
+
"list_loaders",
|
|
20
23
|
"list_models",
|
|
21
24
|
"get_model_info",
|
|
22
25
|
"ModelInfo",
|
|
@@ -24,5 +27,5 @@ __all__ = [
|
|
|
24
27
|
"ImageConfig",
|
|
25
28
|
"preprocess_images",
|
|
26
29
|
]
|
|
27
|
-
__version__ = "0.
|
|
30
|
+
__version__ = "0.2.0"
|
|
28
31
|
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Public catalog loading entrypoint for hyper-models."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
6
7
|
|
|
7
8
|
from huggingface_hub import snapshot_download
|
|
8
9
|
|
|
9
|
-
from hyper_models.
|
|
10
|
+
from hyper_models.loaders import load_model
|
|
10
11
|
from hyper_models.registry import get_model_info
|
|
11
12
|
|
|
12
13
|
__all__ = ["load"]
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def load(name: str, *, local_path: str | Path | None = None) ->
|
|
16
|
+
def load(name: str, *, local_path: str | Path | None = None) -> Any:
|
|
16
17
|
"""Load a model by name.
|
|
17
18
|
|
|
18
19
|
Args:
|
|
19
|
-
name:
|
|
20
|
-
local_path: Optional local
|
|
20
|
+
name: Catalog model name (e.g., 'hycoclip-vit-s').
|
|
21
|
+
local_path: Optional local artifact path (skips Hub download).
|
|
21
22
|
|
|
22
23
|
Returns:
|
|
23
24
|
Model instance ready for inference.
|
|
@@ -28,18 +29,14 @@ def load(name: str, *, local_path: str | Path | None = None) -> ONNXModel:
|
|
|
28
29
|
"""
|
|
29
30
|
info = get_model_info(name)
|
|
30
31
|
|
|
32
|
+
# Route-only entries (e.g. timm-image) raise immediately without downloading.
|
|
33
|
+
if info.loader == "timm-image":
|
|
34
|
+
return load_model(info, Path())
|
|
35
|
+
|
|
31
36
|
if local_path is None:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
local_path = Path(local_dir) / hub_path
|
|
37
|
+
local_dir = snapshot_download(info.hub_id, allow_patterns=[f"{info.hub_path}*"])
|
|
38
|
+
artifact_path = Path(local_dir) / info.hub_path
|
|
35
39
|
else:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return
|
|
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
|
-
)
|
|
40
|
+
artifact_path = Path(local_path)
|
|
41
|
+
|
|
42
|
+
return load_model(info, artifact_path)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Internal loader implementations for hyper-models catalog entries."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Callable
|
|
7
|
+
|
|
8
|
+
from hyper_models.models import ONNXModel
|
|
9
|
+
from hyper_models.registry import ModelInfo
|
|
10
|
+
|
|
11
|
+
__all__ = ["list_loaders", "load_model"]
|
|
12
|
+
|
|
13
|
+
LoaderFn = Callable[[ModelInfo, Path], Any]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_onnx_model(info: ModelInfo, artifact_path: Path) -> ONNXModel:
|
|
17
|
+
return ONNXModel(
|
|
18
|
+
path=artifact_path,
|
|
19
|
+
geometry=info.geometry,
|
|
20
|
+
dim=info.dim,
|
|
21
|
+
input_name=info.input_name,
|
|
22
|
+
output_name=info.output_name,
|
|
23
|
+
image_config=info.image_config,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _load_uncha_image_torch_model(info: ModelInfo, artifact_path: Path) -> Any:
|
|
28
|
+
if info.variant is None:
|
|
29
|
+
raise ValueError(f"UNCHA model '{info.name}' is missing a registry variant")
|
|
30
|
+
|
|
31
|
+
from hyper_models.torch_models import UNCHATorchModel
|
|
32
|
+
|
|
33
|
+
return UNCHATorchModel(
|
|
34
|
+
checkpoint_path=artifact_path,
|
|
35
|
+
geometry=info.geometry,
|
|
36
|
+
dim=info.dim,
|
|
37
|
+
variant=info.variant,
|
|
38
|
+
image_config=info.image_config,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _load_timm_image_route(info: ModelInfo, artifact_path: Path) -> Any:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
f"Model '{info.name}' is a timm model. "
|
|
45
|
+
f"Use HyperView provider='timm-image' with model='hf-hub:{info.hub_id}' instead.\n"
|
|
46
|
+
f" dataset.compute_embeddings(model='hf-hub:{info.hub_id}', provider='timm-image')"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
_LOADERS: dict[str, LoaderFn] = {
|
|
51
|
+
"onnx": _load_onnx_model,
|
|
52
|
+
"uncha-image-torch": _load_uncha_image_torch_model,
|
|
53
|
+
"timm-image": _load_timm_image_route,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def list_loaders() -> list[str]:
|
|
58
|
+
"""List supported internal loader kinds for catalog entries."""
|
|
59
|
+
return sorted(_LOADERS)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def load_model(info: ModelInfo, artifact_path: Path) -> Any:
|
|
63
|
+
"""Instantiate a catalog entry using the loader declared in ``ModelInfo``."""
|
|
64
|
+
try:
|
|
65
|
+
loader = _LOADERS[info.loader]
|
|
66
|
+
except KeyError:
|
|
67
|
+
available = ", ".join(sorted(_LOADERS))
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"Unsupported loader '{info.loader}' for model '{info.name}'. Available: {available}"
|
|
70
|
+
) from None
|
|
71
|
+
|
|
72
|
+
return loader(info, artifact_path)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Catalog registry for hyper-models entries and their loader metadata."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -11,13 +11,22 @@ __all__ = ["ModelInfo", "list_models", "get_model_info"]
|
|
|
11
11
|
|
|
12
12
|
@dataclass
|
|
13
13
|
class ModelInfo:
|
|
14
|
-
"""Metadata for a registered model.
|
|
14
|
+
"""Metadata for a registered catalog model.
|
|
15
|
+
|
|
16
|
+
`loader` describes how the catalog entry is instantiated internally.
|
|
17
|
+
This is intentionally separate from the public catalog surface so callers
|
|
18
|
+
can always use ``hyper_models.load(name)`` regardless of runtime backend.
|
|
19
|
+
"""
|
|
15
20
|
|
|
16
21
|
name: str
|
|
17
22
|
geometry: str # 'hyperboloid', 'poincare', 'sphere', 'euclidean'
|
|
18
23
|
dim: int
|
|
19
24
|
hub_id: str
|
|
25
|
+
hub_path: str
|
|
20
26
|
license: str
|
|
27
|
+
loader: str = "onnx" # e.g. 'onnx', 'uncha-image-torch'
|
|
28
|
+
variant: str | None = None # optional loader hint (e.g., 'vit_s', 'vit_b')
|
|
29
|
+
optional_dependencies: tuple[str, ...] = ()
|
|
21
30
|
description: str = ""
|
|
22
31
|
input_name: str = "image"
|
|
23
32
|
output_name: str | None = None
|
|
@@ -30,6 +39,7 @@ _MODELS: dict[str, ModelInfo] = {
|
|
|
30
39
|
geometry="hyperboloid",
|
|
31
40
|
dim=513,
|
|
32
41
|
hub_id="mnm-matin/hyperbolic-clip",
|
|
42
|
+
hub_path="hycoclip-vit-s/model.onnx",
|
|
33
43
|
license="CC-BY-NC",
|
|
34
44
|
description="HyCoCLIP ViT-Small (512D hyperboloid)",
|
|
35
45
|
output_name="embedding_hyperboloid",
|
|
@@ -39,6 +49,7 @@ _MODELS: dict[str, ModelInfo] = {
|
|
|
39
49
|
geometry="hyperboloid",
|
|
40
50
|
dim=513,
|
|
41
51
|
hub_id="mnm-matin/hyperbolic-clip",
|
|
52
|
+
hub_path="hycoclip-vit-b/model.onnx",
|
|
42
53
|
license="CC-BY-NC",
|
|
43
54
|
description="HyCoCLIP ViT-Base (512D hyperboloid)",
|
|
44
55
|
output_name="embedding_hyperboloid",
|
|
@@ -48,6 +59,7 @@ _MODELS: dict[str, ModelInfo] = {
|
|
|
48
59
|
geometry="hyperboloid",
|
|
49
60
|
dim=513,
|
|
50
61
|
hub_id="mnm-matin/hyperbolic-clip",
|
|
62
|
+
hub_path="meru-vit-s/model.onnx",
|
|
51
63
|
license="CC-BY-NC",
|
|
52
64
|
description="MERU ViT-Small (512D hyperboloid)",
|
|
53
65
|
output_name="embedding_hyperboloid",
|
|
@@ -57,10 +69,46 @@ _MODELS: dict[str, ModelInfo] = {
|
|
|
57
69
|
geometry="hyperboloid",
|
|
58
70
|
dim=513,
|
|
59
71
|
hub_id="mnm-matin/hyperbolic-clip",
|
|
72
|
+
hub_path="meru-vit-b/model.onnx",
|
|
60
73
|
license="CC-BY-NC",
|
|
61
74
|
description="MERU ViT-Base (512D hyperboloid)",
|
|
62
75
|
output_name="embedding_hyperboloid",
|
|
63
76
|
),
|
|
77
|
+
"uncha-vit-s": ModelInfo(
|
|
78
|
+
name="uncha-vit-s",
|
|
79
|
+
geometry="hyperboloid",
|
|
80
|
+
dim=513,
|
|
81
|
+
hub_id="hayeonkim/uncha",
|
|
82
|
+
hub_path="uncha_vit_s.pth",
|
|
83
|
+
license="Unknown",
|
|
84
|
+
loader="uncha-image-torch",
|
|
85
|
+
variant="vit_s",
|
|
86
|
+
optional_dependencies=("ml",),
|
|
87
|
+
description="UNCHA ViT-S/16 checkpoint (HF .pth, torch inference)",
|
|
88
|
+
),
|
|
89
|
+
"uncha-vit-b": ModelInfo(
|
|
90
|
+
name="uncha-vit-b",
|
|
91
|
+
geometry="hyperboloid",
|
|
92
|
+
dim=513,
|
|
93
|
+
hub_id="hayeonkim/uncha",
|
|
94
|
+
hub_path="uncha_vit_b.pth",
|
|
95
|
+
license="Unknown",
|
|
96
|
+
loader="uncha-image-torch",
|
|
97
|
+
variant="vit_b",
|
|
98
|
+
optional_dependencies=("ml",),
|
|
99
|
+
description="UNCHA ViT-B/16 checkpoint (HF .pth, torch inference)",
|
|
100
|
+
),
|
|
101
|
+
"megadescriptor": ModelInfo(
|
|
102
|
+
name="megadescriptor",
|
|
103
|
+
geometry="sphere",
|
|
104
|
+
dim=1024,
|
|
105
|
+
hub_id="BVRA/MegaDescriptor-L-384",
|
|
106
|
+
hub_path="",
|
|
107
|
+
license="MIT",
|
|
108
|
+
loader="timm-image",
|
|
109
|
+
description="MegaDescriptor-L-384 (via timm, use provider='timm-image')",
|
|
110
|
+
image_config=ImageConfig(size=384),
|
|
111
|
+
),
|
|
64
112
|
}
|
|
65
113
|
|
|
66
114
|
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""Torch-backed catalog model implementations.
|
|
2
|
+
|
|
3
|
+
These are internal loader targets used by selected hyper-models catalog entries.
|
|
4
|
+
They do not create a separate public provider surface.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from PIL import Image
|
|
14
|
+
|
|
15
|
+
from hyper_models.preprocessing import ImageConfig, preprocess_images
|
|
16
|
+
|
|
17
|
+
__all__ = ["UNCHATorchModel"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class _UNCHAImageEncoder:
|
|
21
|
+
"""Minimal UNCHA image encoder graph for inference-only embeddings."""
|
|
22
|
+
|
|
23
|
+
def __init__(self, torch: Any, timm: Any, nn: Any, *, variant: str) -> None:
|
|
24
|
+
self._torch = torch
|
|
25
|
+
self._timm = timm
|
|
26
|
+
self._nn = nn
|
|
27
|
+
self._variant = variant
|
|
28
|
+
|
|
29
|
+
self._register_custom_variants()
|
|
30
|
+
self.visual = self._build_visual()
|
|
31
|
+
self.visual_proj = nn.Linear(self.visual.width, 512, bias=False)
|
|
32
|
+
|
|
33
|
+
self.visual_alpha = nn.Parameter(torch.tensor(512**-0.5).log())
|
|
34
|
+
self.curv = nn.Parameter(torch.tensor(1.0).log())
|
|
35
|
+
|
|
36
|
+
self.pixel_mean = torch.tensor((0.485, 0.456, 0.406)).view(1, 3, 1, 1)
|
|
37
|
+
self.pixel_std = torch.tensor((0.229, 0.224, 0.225)).view(1, 3, 1, 1)
|
|
38
|
+
|
|
39
|
+
def _register_custom_variants(self) -> None:
|
|
40
|
+
if self._timm.models.is_model("vit_small_mocov3_patch16_224"):
|
|
41
|
+
return
|
|
42
|
+
|
|
43
|
+
@self._timm.models.register_model
|
|
44
|
+
def vit_small_mocov3_patch16_224(**kwargs: Any):
|
|
45
|
+
return self._timm.models.vision_transformer._create_vision_transformer(
|
|
46
|
+
"vit_small_patch16_224",
|
|
47
|
+
patch_size=16,
|
|
48
|
+
embed_dim=384,
|
|
49
|
+
depth=12,
|
|
50
|
+
num_heads=12,
|
|
51
|
+
**kwargs,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def _build_visual(self) -> Any:
|
|
55
|
+
arch = {
|
|
56
|
+
"vit_s": "vit_small_mocov3_patch16_224",
|
|
57
|
+
"vit_b": "vit_base_patch16_224",
|
|
58
|
+
}[self._variant]
|
|
59
|
+
|
|
60
|
+
visual = self._timm.create_model(
|
|
61
|
+
arch,
|
|
62
|
+
num_classes=0,
|
|
63
|
+
global_pool="token",
|
|
64
|
+
class_token=True,
|
|
65
|
+
norm_layer=self._nn.LayerNorm,
|
|
66
|
+
pretrained=False,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Match upstream UNCHA image encoder API expected by projection layers.
|
|
70
|
+
visual.width = int(getattr(visual, "embed_dim", getattr(visual, "num_features", 0)))
|
|
71
|
+
if visual.width <= 0:
|
|
72
|
+
raise RuntimeError("Unable to infer visual width for UNCHA image encoder")
|
|
73
|
+
return visual
|
|
74
|
+
|
|
75
|
+
def _exp_map0(self, tangent: Any, curvature: Any) -> Any:
|
|
76
|
+
torch = self._torch
|
|
77
|
+
sqrt_curvature = torch.sqrt(curvature)
|
|
78
|
+
norm = torch.linalg.norm(tangent, dim=-1, keepdim=True).clamp_min(1e-12)
|
|
79
|
+
scale = torch.sinh(sqrt_curvature * norm) / (sqrt_curvature * norm)
|
|
80
|
+
return tangent * scale
|
|
81
|
+
|
|
82
|
+
def _lift_hyperboloid(self, space: Any, curvature: Any) -> Any:
|
|
83
|
+
torch = self._torch
|
|
84
|
+
time = torch.sqrt((1.0 / curvature) + torch.sum(space * space, dim=-1, keepdim=True))
|
|
85
|
+
return torch.cat([time, space], dim=-1)
|
|
86
|
+
|
|
87
|
+
def encode(self, images_bchw: Any) -> Any:
|
|
88
|
+
torch = self._torch
|
|
89
|
+
|
|
90
|
+
images = (images_bchw - self.pixel_mean) / self.pixel_std
|
|
91
|
+
image_feats = self.visual(images)
|
|
92
|
+
image_feats = self.visual_proj(image_feats)
|
|
93
|
+
|
|
94
|
+
visual_scale = torch.exp(torch.clamp(self.visual_alpha, max=0.0))
|
|
95
|
+
tangent = image_feats * visual_scale
|
|
96
|
+
|
|
97
|
+
curvature = torch.exp(self.curv).clamp(min=1e-8)
|
|
98
|
+
space = self._exp_map0(tangent, curvature)
|
|
99
|
+
return self._lift_hyperboloid(space, curvature)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class UNCHATorchModel:
|
|
103
|
+
"""UNCHA catalog entry runtime using torch+timm for image inference."""
|
|
104
|
+
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
checkpoint_path: Path,
|
|
108
|
+
*,
|
|
109
|
+
geometry: str,
|
|
110
|
+
dim: int,
|
|
111
|
+
variant: str,
|
|
112
|
+
image_config: ImageConfig | None = None,
|
|
113
|
+
device: str | None = None,
|
|
114
|
+
) -> None:
|
|
115
|
+
self._checkpoint_path = checkpoint_path
|
|
116
|
+
self.geometry = geometry
|
|
117
|
+
self.dim = dim
|
|
118
|
+
self._variant = variant
|
|
119
|
+
self._image_config = image_config or ImageConfig()
|
|
120
|
+
self._device_override = device
|
|
121
|
+
|
|
122
|
+
self._torch = None
|
|
123
|
+
self._device = None
|
|
124
|
+
self._encoder = None
|
|
125
|
+
|
|
126
|
+
def _import_ml_stack(self) -> tuple[Any, Any, Any]:
|
|
127
|
+
try:
|
|
128
|
+
import timm
|
|
129
|
+
import torch
|
|
130
|
+
from torch import nn
|
|
131
|
+
except ImportError as e:
|
|
132
|
+
raise ImportError(
|
|
133
|
+
"This catalog entry requires the optional 'ml' dependencies. "
|
|
134
|
+
"Install with: uv sync --extra ml or uv pip install 'hyper-models[ml]'"
|
|
135
|
+
) from e
|
|
136
|
+
|
|
137
|
+
return torch, timm, nn
|
|
138
|
+
|
|
139
|
+
def _resolve_device(self, torch: Any) -> Any:
|
|
140
|
+
if self._device_override:
|
|
141
|
+
return torch.device(self._device_override)
|
|
142
|
+
if torch.cuda.is_available():
|
|
143
|
+
return torch.device("cuda")
|
|
144
|
+
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
|
145
|
+
return torch.device("mps")
|
|
146
|
+
return torch.device("cpu")
|
|
147
|
+
|
|
148
|
+
def _load_state_dict(self) -> dict[str, Any]:
|
|
149
|
+
assert self._torch is not None
|
|
150
|
+
|
|
151
|
+
checkpoint_obj = self._torch.load(
|
|
152
|
+
self._checkpoint_path,
|
|
153
|
+
map_location="cpu",
|
|
154
|
+
weights_only=False,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if isinstance(checkpoint_obj, dict) and "model" in checkpoint_obj:
|
|
158
|
+
model_state = checkpoint_obj["model"]
|
|
159
|
+
if isinstance(model_state, dict):
|
|
160
|
+
return model_state
|
|
161
|
+
|
|
162
|
+
if isinstance(checkpoint_obj, dict):
|
|
163
|
+
return checkpoint_obj
|
|
164
|
+
|
|
165
|
+
raise TypeError("Unexpected UNCHA checkpoint format; expected dict or {'model': state_dict}")
|
|
166
|
+
|
|
167
|
+
def _ensure_encoder(self) -> None:
|
|
168
|
+
if self._encoder is not None:
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
torch, timm, nn = self._import_ml_stack()
|
|
172
|
+
self._torch = torch
|
|
173
|
+
self._device = self._resolve_device(torch)
|
|
174
|
+
|
|
175
|
+
encoder = _UNCHAImageEncoder(torch, timm, nn, variant=self._variant)
|
|
176
|
+
state_dict = self._load_state_dict()
|
|
177
|
+
|
|
178
|
+
own_state: dict[str, Any] = {}
|
|
179
|
+
for key, value in state_dict.items():
|
|
180
|
+
if key.startswith("module."):
|
|
181
|
+
key = key[len("module.") :]
|
|
182
|
+
if key.startswith("model."):
|
|
183
|
+
key = key[len("model.") :]
|
|
184
|
+
|
|
185
|
+
if key.startswith("visual.") or key.startswith("visual_proj."):
|
|
186
|
+
own_state[key] = value
|
|
187
|
+
elif key in {"visual_alpha", "curv"}:
|
|
188
|
+
own_state[key] = value
|
|
189
|
+
|
|
190
|
+
module = torch.nn.Module()
|
|
191
|
+
module.visual = encoder.visual
|
|
192
|
+
module.visual_proj = encoder.visual_proj
|
|
193
|
+
module.visual_alpha = encoder.visual_alpha
|
|
194
|
+
module.curv = encoder.curv
|
|
195
|
+
|
|
196
|
+
load_result = module.load_state_dict(own_state, strict=False)
|
|
197
|
+
if len(own_state) == 0:
|
|
198
|
+
raise RuntimeError("UNCHA checkpoint did not contain visual encoder weights")
|
|
199
|
+
if "visual_proj.weight" in load_result.missing_keys:
|
|
200
|
+
raise RuntimeError("UNCHA checkpoint missing required key: visual_proj.weight")
|
|
201
|
+
|
|
202
|
+
encoder.visual = module.visual.to(self._device)
|
|
203
|
+
encoder.visual_proj = module.visual_proj.to(self._device)
|
|
204
|
+
encoder.visual_alpha = torch.nn.Parameter(module.visual_alpha.to(self._device))
|
|
205
|
+
encoder.curv = torch.nn.Parameter(module.curv.to(self._device))
|
|
206
|
+
encoder.pixel_mean = encoder.pixel_mean.to(self._device)
|
|
207
|
+
encoder.pixel_std = encoder.pixel_std.to(self._device)
|
|
208
|
+
|
|
209
|
+
encoder.visual.eval()
|
|
210
|
+
encoder.visual_proj.eval()
|
|
211
|
+
|
|
212
|
+
self._encoder = encoder
|
|
213
|
+
|
|
214
|
+
def encode(self, inputs: np.ndarray) -> np.ndarray:
|
|
215
|
+
"""Encode preprocessed inputs (B, C, H, W) to embeddings (B, D)."""
|
|
216
|
+
self._ensure_encoder()
|
|
217
|
+
|
|
218
|
+
assert self._encoder is not None
|
|
219
|
+
assert self._torch is not None
|
|
220
|
+
assert self._device is not None
|
|
221
|
+
|
|
222
|
+
images = self._torch.from_numpy(inputs).to(device=self._device, dtype=self._torch.float32)
|
|
223
|
+
with self._torch.inference_mode():
|
|
224
|
+
emb = self._encoder.encode(images)
|
|
225
|
+
|
|
226
|
+
return np.asarray(emb.detach().cpu().numpy(), dtype=np.float32)
|
|
227
|
+
|
|
228
|
+
def encode_images(self, images: list[Image.Image]) -> np.ndarray:
|
|
229
|
+
"""Encode PIL images to embeddings (B, D)."""
|
|
230
|
+
return self.encode(preprocess_images(images, self._image_config))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|