hyper-models 0.3.0__tar.gz → 0.3.1__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.
Files changed (24) hide show
  1. {hyper_models-0.3.0 → hyper_models-0.3.1}/PKG-INFO +5 -3
  2. {hyper_models-0.3.0 → hyper_models-0.3.1}/pyproject.toml +8 -2
  3. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/__init__.py +10 -1
  4. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/models.py +3 -1
  5. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/registry.py +3 -1
  6. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/torch_models.py +46 -7
  7. {hyper_models-0.3.0 → hyper_models-0.3.1}/.gitignore +0 -0
  8. {hyper_models-0.3.0 → hyper_models-0.3.1}/LICENSE +0 -0
  9. {hyper_models-0.3.0 → hyper_models-0.3.1}/README.md +0 -0
  10. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/__init__.py +0 -0
  11. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/__init__.py +0 -0
  12. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/encoders.py +0 -0
  13. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/experimental.py +0 -0
  14. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/himo.py +0 -0
  15. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/hyper3_clip.py +0 -0
  16. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/lorentz.py +0 -0
  17. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/losses.py +0 -0
  18. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/objectives.py +0 -0
  19. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/models/tren.py +0 -0
  20. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/training/__init__.py +0 -0
  21. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper3_clip/training/distributed.py +0 -0
  22. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/loader.py +0 -0
  23. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/loaders.py +0 -0
  24. {hyper_models-0.3.0 → hyper_models-0.3.1}/src/hyper_models/preprocessing.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: hyper-models
3
- Version: 0.3.0
3
+ Version: 0.3.1
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
@@ -22,11 +22,13 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
22
  Requires-Python: >=3.10
23
23
  Requires-Dist: huggingface-hub>=1.0
24
24
  Requires-Dist: numpy>=1.26
25
- Requires-Dist: onnxruntime>=1.20
25
+ Requires-Dist: onnxruntime<1.24,>=1.20; python_version < '3.11'
26
+ Requires-Dist: onnxruntime>=1.20; python_version >= '3.11'
26
27
  Requires-Dist: pillow>=10.0
27
28
  Provides-Extra: dev
28
29
  Requires-Dist: pytest>=7.0; extra == 'dev'
29
30
  Requires-Dist: ruff>=0.1; extra == 'dev'
31
+ Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
30
32
  Provides-Extra: ml
31
33
  Requires-Dist: protobuf>=4.25.0; extra == 'ml'
32
34
  Requires-Dist: pyyaml>=6.0.0; extra == 'ml'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyper-models"
3
- version = "0.3.0"
3
+ version = "0.3.1"
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" }
@@ -20,7 +20,11 @@ classifiers = [
20
20
  ]
21
21
  dependencies = [
22
22
  "numpy>=1.26",
23
- "onnxruntime>=1.20",
23
+ # onnxruntime stopped publishing cp310 wheels after 1.23.x; without this
24
+ # split a universal resolution picks a release that cannot install on the
25
+ # 3.10 this package still supports.
26
+ "onnxruntime>=1.20,<1.24; python_version<'3.11'",
27
+ "onnxruntime>=1.20; python_version>='3.11'",
24
28
  "huggingface-hub>=1.0",
25
29
  "pillow>=10.0",
26
30
  ]
@@ -29,6 +33,8 @@ dependencies = [
29
33
  dev = [
30
34
  "pytest>=7.0",
31
35
  "ruff>=0.1",
36
+ # tomllib is stdlib from 3.11; the version test reads pyproject.toml on 3.10 too.
37
+ "tomli>=2.0; python_version<'3.11'",
32
38
  ]
33
39
  ml = [
34
40
  "torch>=2.9.1",
@@ -11,6 +11,9 @@ Example:
11
11
  >>> model.dim # 513
12
12
  """
13
13
 
14
+ from importlib.metadata import PackageNotFoundError
15
+ from importlib.metadata import version as _installed_version
16
+
14
17
  from hyper_models.loader import load
15
18
  from hyper_models.loaders import list_loaders
16
19
  from hyper_models.models import ONNXModel
@@ -27,4 +30,10 @@ __all__ = [
27
30
  "ImageConfig",
28
31
  "preprocess_images",
29
32
  ]
30
- __version__ = "0.3.0"
33
+ try:
34
+ # Read the installed distribution so this cannot drift from pyproject.toml:
35
+ # a hand-maintained literal here stayed at 0.3.0 through the 0.3.1 release,
36
+ # and the demo Dockerfiles print this value to confirm what they installed.
37
+ __version__ = _installed_version("hyper-models")
38
+ except PackageNotFoundError: # running from a source tree that was never installed
39
+ __version__ = "0.0.0.dev0"
@@ -37,7 +37,9 @@ class ONNXModel:
37
37
  if self._session is None:
38
38
  import onnxruntime as ort
39
39
 
40
- self._session = ort.InferenceSession(str(self._path), providers=["CPUExecutionProvider"])
40
+ self._session = ort.InferenceSession(
41
+ str(self._path), providers=["CPUExecutionProvider"]
42
+ )
41
43
 
42
44
  def encode(self, inputs: np.ndarray) -> np.ndarray:
43
45
  """Encode preprocessed inputs (B, C, H, W) to embeddings (B, D)."""
@@ -31,6 +31,7 @@ class ModelInfo:
31
31
  description: str = ""
32
32
  input_name: str = "image"
33
33
  output_name: str | None = None
34
+ modalities: tuple[str, ...] = ("image",) # what the loaded model can encode
34
35
  image_config: ImageConfig = field(default_factory=ImageConfig)
35
36
 
36
37
 
@@ -109,7 +110,8 @@ _MODELS: dict[str, ModelInfo] = {
109
110
  license="Unknown",
110
111
  loader="hyper3-clip-torch",
111
112
  optional_dependencies=("ml",),
112
- description="Hyper3-CLIP v0.5 ViT-B image encoder (HF safetensors, torch inference)",
113
+ modalities=("image", "text"),
114
+ description="Hyper3-CLIP v0.5 ViT-B image+text encoder (HF safetensors, torch inference)",
113
115
  image_config=ImageConfig(
114
116
  size=224,
115
117
  interpolation="bicubic",
@@ -232,6 +232,30 @@ class UNCHATorchModel:
232
232
  return self.encode(preprocess_images(images, self._image_config))
233
233
 
234
234
 
235
+ _CHECKPOINT_TEXT_PREFIX = "text_encoder.backbone.text_model."
236
+ _MODEL_TEXT_PREFIX = "text_encoder.backbone."
237
+
238
+
239
+ def _align_text_tower_keys(state: dict[str, Any]) -> dict[str, Any]:
240
+ """Match published Hyper3-CLIP text weights to the model's parameter names.
241
+
242
+ The checkpoint stores the text tower under the full Hugging Face
243
+ ``CLIPTextModel`` path, while :class:`Hyper3CLIP` binds its backbone one
244
+ level deeper, at ``CLIPTextModel.text_model``. Without this rename the text
245
+ tower silently loads no pretrained weights and every text embedding comes
246
+ from a randomly initialised encoder.
247
+ """
248
+
249
+ return {
250
+ (
251
+ _MODEL_TEXT_PREFIX + key[len(_CHECKPOINT_TEXT_PREFIX) :]
252
+ if key.startswith(_CHECKPOINT_TEXT_PREFIX)
253
+ else key
254
+ ): value
255
+ for key, value in state.items()
256
+ }
257
+
258
+
235
259
  class Hyper3ClipTorchModel:
236
260
  """Hyper3-CLIP catalog entry runtime using torch for image inference."""
237
261
 
@@ -297,14 +321,11 @@ class Hyper3ClipTorchModel:
297
321
  model_config["vision_pretrained"] = False
298
322
  model_config["text_pretrained"] = False
299
323
  model = Hyper3CLIP(**model_config)
300
- state = load_file(self._checkpoint_path, device="cpu")
324
+ state = _align_text_tower_keys(load_file(self._checkpoint_path, device="cpu"))
301
325
  load_result = model.load_state_dict(state, strict=False)
302
- missing_non_text = [
303
- key for key in load_result.missing_keys if not key.startswith("text_encoder.")
304
- ]
305
- if missing_non_text:
306
- missing = ", ".join(missing_non_text[:8])
307
- raise RuntimeError(f"Hyper3-CLIP checkpoint missing required image keys: {missing}")
326
+ if load_result.missing_keys:
327
+ missing = ", ".join(load_result.missing_keys[:8])
328
+ raise RuntimeError(f"Hyper3-CLIP checkpoint missing required keys: {missing}")
308
329
  model.to(self._device)
309
330
  model.eval()
310
331
  self._model = model
@@ -326,3 +347,21 @@ class Hyper3ClipTorchModel:
326
347
  def encode_images(self, images: list[Image.Image]) -> np.ndarray:
327
348
  """Encode PIL images to Hyper3-CLIP embeddings (B, D)."""
328
349
  return self.encode(preprocess_images(images, self._image_config))
350
+
351
+ def encode_texts(self, texts: list[str]) -> np.ndarray:
352
+ """Encode text queries into the same hyperboloid as the images (B, D)."""
353
+ self._ensure_model()
354
+
355
+ assert self._model is not None
356
+ assert self._torch is not None
357
+ assert self._device is not None
358
+
359
+ encoded = self._model.tokenizer(
360
+ list(texts), padding=True, truncation=True, return_tensors="pt"
361
+ )
362
+ input_ids = encoded["input_ids"].to(self._device)
363
+ attention_mask = encoded["attention_mask"].to(self._device)
364
+ with self._torch.inference_mode():
365
+ emb = self._model.encode_text(input_ids, attention_mask)
366
+
367
+ return np.asarray(emb.detach().cpu().numpy(), dtype=np.float32)
File without changes
File without changes
File without changes