fastembed-gpu 0.6.1__tar.gz → 0.7.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 (61) hide show
  1. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/PKG-INFO +1 -1
  2. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/onnx_model.py +10 -1
  3. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/preprocessor_utils.py +3 -3
  4. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/types.py +1 -0
  5. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/image_embedding.py +34 -0
  6. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/image_embedding_base.py +11 -0
  7. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/onnx_embedding.py +7 -2
  8. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/onnx_image_model.py +16 -3
  9. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/transform/functional.py +10 -10
  10. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction/colbert.py +5 -2
  11. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction/late_interaction_embedding_base.py +11 -0
  12. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction/late_interaction_text_embedding.py +34 -0
  13. fastembed_gpu-0.7.1/fastembed/late_interaction/token_embeddings.py +83 -0
  14. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction_multimodal/colpali.py +7 -2
  15. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction_multimodal/late_interaction_multimodal_embedding.py +34 -0
  16. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction_multimodal/late_interaction_multimodal_embedding_base.py +11 -0
  17. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction_multimodal/onnx_multimodal_model.py +8 -0
  18. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/onnx_text_cross_encoder.py +7 -2
  19. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/onnx_text_model.py +16 -1
  20. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/bm25.py +10 -13
  21. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/bm42.py +7 -2
  22. fastembed_gpu-0.7.1/fastembed/sparse/minicoil.py +356 -0
  23. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/sparse_text_embedding.py +3 -2
  24. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/splade_pp.py +7 -2
  25. fastembed_gpu-0.7.1/fastembed/sparse/utils/minicoil_encoder.py +146 -0
  26. fastembed_gpu-0.7.1/fastembed/sparse/utils/sparse_vectors_converter.py +247 -0
  27. fastembed_gpu-0.7.1/fastembed/sparse/utils/vocab_resolver.py +202 -0
  28. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/clip_embedding.py +3 -1
  29. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/custom_text_embedding.py +8 -1
  30. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/onnx_embedding.py +7 -2
  31. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/onnx_text_model.py +18 -3
  32. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/pooled_embedding.py +3 -1
  33. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/pooled_normalized_embedding.py +3 -1
  34. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/text_embedding.py +41 -7
  35. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/text_embedding_base.py +11 -0
  36. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/pyproject.toml +2 -2
  37. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/LICENSE +0 -0
  38. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/NOTICE +0 -0
  39. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/README.md +0 -0
  40. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/__init__.py +0 -0
  41. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/__init__.py +0 -0
  42. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/model_description.py +0 -0
  43. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/model_management.py +0 -0
  44. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/common/utils.py +0 -0
  45. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/embedding.py +0 -0
  46. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/__init__.py +0 -0
  47. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/image/transform/operators.py +0 -0
  48. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction/__init__.py +0 -0
  49. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction/jina_colbert.py +0 -0
  50. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/late_interaction_multimodal/__init__.py +0 -0
  51. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/parallel_processor.py +0 -0
  52. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/py.typed +0 -0
  53. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/__init__.py +0 -0
  54. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/custom_text_cross_encoder.py +0 -0
  55. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/text_cross_encoder.py +0 -0
  56. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/rerank/cross_encoder/text_cross_encoder_base.py +0 -0
  57. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/__init__.py +0 -0
  58. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/sparse_embedding_base.py +0 -0
  59. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/sparse/utils/tokenizer.py +0 -0
  60. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/__init__.py +0 -0
  61. {fastembed_gpu-0.6.1 → fastembed_gpu-0.7.1}/fastembed/text/multitask_embedding.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fastembed-gpu
3
- Version: 0.6.1
3
+ Version: 0.7.1
4
4
  Summary: Fast, light, accurate library built for retrieval embedding generation
5
5
  License: Apache License
6
6
  Keywords: vector,embedding,neural,search,qdrant,sentence-transformers
@@ -28,7 +28,16 @@ class OnnxModel(Generic[T]):
28
28
  def _get_worker_class(cls) -> Type["EmbeddingWorker[T]"]:
29
29
  raise NotImplementedError("Subclasses must implement this method")
30
30
 
31
- def _post_process_onnx_output(self, output: OnnxOutputContext) -> Iterable[T]:
31
+ def _post_process_onnx_output(self, output: OnnxOutputContext, **kwargs: Any) -> Iterable[T]:
32
+ """Post-process the ONNX model output to convert it into a usable format.
33
+
34
+ Args:
35
+ output (OnnxOutputContext): The raw output from the ONNX model.
36
+ **kwargs: Additional keyword arguments that may be needed by specific implementations.
37
+
38
+ Returns:
39
+ Iterable[T]: Post-processed output as an iterable of type T.
40
+ """
32
41
  raise NotImplementedError("Subclasses must implement this method")
33
42
 
34
43
  def __init__(self) -> None:
@@ -36,9 +36,9 @@ def load_tokenizer(model_dir: Path) -> tuple[Tokenizer, dict[str, int]]:
36
36
 
37
37
  with open(str(tokenizer_config_path)) as tokenizer_config_file:
38
38
  tokenizer_config = json.load(tokenizer_config_file)
39
- assert (
40
- "model_max_length" in tokenizer_config or "max_length" in tokenizer_config
41
- ), "Models without model_max_length or max_length are not supported."
39
+ assert "model_max_length" in tokenizer_config or "max_length" in tokenizer_config, (
40
+ "Models without model_max_length or max_length are not supported."
41
+ )
42
42
  if "model_max_length" not in tokenizer_config:
43
43
  max_context = tokenizer_config["max_length"]
44
44
  elif "max_length" not in tokenizer_config:
@@ -16,6 +16,7 @@ ImageInput: TypeAlias = Union[PathInput, Image.Image]
16
16
 
17
17
  OnnxProvider: TypeAlias = Union[str, tuple[str, dict[Any, Any]]]
18
18
  NumpyArray = Union[
19
+ NDArray[np.float64],
19
20
  NDArray[np.float32],
20
21
  NDArray[np.float16],
21
22
  NDArray[np.int8],
@@ -77,6 +77,40 @@ class ImageEmbedding(ImageEmbeddingBase):
77
77
  "Please check the supported models using `ImageEmbedding.list_supported_models()`"
78
78
  )
79
79
 
80
+ @property
81
+ def embedding_size(self) -> int:
82
+ """Get the embedding size of the current model"""
83
+ if self._embedding_size is None:
84
+ self._embedding_size = self.get_embedding_size(self.model_name)
85
+ return self._embedding_size
86
+
87
+ @classmethod
88
+ def get_embedding_size(cls, model_name: str) -> int:
89
+ """Get the embedding size of the passed model
90
+
91
+ Args:
92
+ model_name (str): The name of the model to get embedding size for.
93
+
94
+ Returns:
95
+ int: The size of the embedding.
96
+
97
+ Raises:
98
+ ValueError: If the model name is not found in the supported models.
99
+ """
100
+ descriptions = cls._list_supported_models()
101
+ embedding_size: Optional[int] = None
102
+ for description in descriptions:
103
+ if description.model.lower() == model_name.lower():
104
+ embedding_size = description.dim
105
+ break
106
+ if embedding_size is None:
107
+ model_names = [description.model for description in descriptions]
108
+ raise ValueError(
109
+ f"Embedding size for model {model_name} was None. "
110
+ f"Available model names: {model_names}"
111
+ )
112
+ return embedding_size
113
+
80
114
  def embed(
81
115
  self,
82
116
  images: Union[ImageInput, Iterable[ImageInput]],
@@ -18,6 +18,7 @@ class ImageEmbeddingBase(ModelManagement[DenseModelDescription]):
18
18
  self.cache_dir = cache_dir
19
19
  self.threads = threads
20
20
  self._local_files_only = kwargs.pop("local_files_only", False)
21
+ self._embedding_size: Optional[int] = None
21
22
 
22
23
  def embed(
23
24
  self,
@@ -42,3 +43,13 @@ class ImageEmbeddingBase(ModelManagement[DenseModelDescription]):
42
43
  Iterable[NdArray]: The embeddings.
43
44
  """
44
45
  raise NotImplementedError()
46
+
47
+ @classmethod
48
+ def get_embedding_size(cls, model_name: str) -> int:
49
+ """Returns embedding size of the chosen model."""
50
+ raise NotImplementedError("Subclasses must implement this method")
51
+
52
+ @property
53
+ def embedding_size(self) -> int:
54
+ """Returns embedding size for the current model"""
55
+ raise NotImplementedError("Subclasses must implement this method")
@@ -112,11 +112,12 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[NumpyArray]):
112
112
 
113
113
  self.model_description = self._get_model_description(model_name)
114
114
  self.cache_dir = str(define_cache_dir(cache_dir))
115
+ self._specific_model_path = specific_model_path
115
116
  self._model_dir = self.download_model(
116
117
  self.model_description,
117
118
  self.cache_dir,
118
119
  local_files_only=self._local_files_only,
119
- specific_model_path=specific_model_path,
120
+ specific_model_path=self._specific_model_path,
120
121
  )
121
122
 
122
123
  if not self.lazy_load:
@@ -177,6 +178,8 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[NumpyArray]):
177
178
  providers=self.providers,
178
179
  cuda=self.cuda,
179
180
  device_ids=self.device_ids,
181
+ local_files_only=self._local_files_only,
182
+ specific_model_path=self._specific_model_path,
180
183
  **kwargs,
181
184
  )
182
185
 
@@ -193,7 +196,9 @@ class OnnxImageEmbedding(ImageEmbeddingBase, OnnxImageModel[NumpyArray]):
193
196
 
194
197
  return onnx_input
195
198
 
196
- def _post_process_onnx_output(self, output: OnnxOutputContext) -> Iterable[NumpyArray]:
199
+ def _post_process_onnx_output(
200
+ self, output: OnnxOutputContext, **kwargs: Any
201
+ ) -> Iterable[NumpyArray]:
197
202
  return normalize(output.model_output)
198
203
 
199
204
 
@@ -23,7 +23,16 @@ class OnnxImageModel(OnnxModel[T]):
23
23
  def _get_worker_class(cls) -> Type["ImageEmbeddingWorker[T]"]:
24
24
  raise NotImplementedError("Subclasses must implement this method")
25
25
 
26
- def _post_process_onnx_output(self, output: OnnxOutputContext) -> Iterable[T]:
26
+ def _post_process_onnx_output(self, output: OnnxOutputContext, **kwargs: Any) -> Iterable[T]:
27
+ """Post-process the ONNX model output to convert it into a usable format.
28
+
29
+ Args:
30
+ output (OnnxOutputContext): The raw output from the ONNX model.
31
+ **kwargs: Additional keyword arguments that may be needed by specific implementations.
32
+
33
+ Returns:
34
+ Iterable[T]: Post-processed output as an iterable of type T.
35
+ """
27
36
  raise NotImplementedError("Subclasses must implement this method")
28
37
 
29
38
  def __init__(self) -> None:
@@ -88,6 +97,8 @@ class OnnxImageModel(OnnxModel[T]):
88
97
  providers: Optional[Sequence[OnnxProvider]] = None,
89
98
  cuda: bool = False,
90
99
  device_ids: Optional[list[int]] = None,
100
+ local_files_only: bool = False,
101
+ specific_model_path: Optional[str] = None,
91
102
  **kwargs: Any,
92
103
  ) -> Iterable[T]:
93
104
  is_small = False
@@ -104,7 +115,7 @@ class OnnxImageModel(OnnxModel[T]):
104
115
  self.load_onnx_model()
105
116
 
106
117
  for batch in iter_batch(images, batch_size):
107
- yield from self._post_process_onnx_output(self.onnx_embed(batch))
118
+ yield from self._post_process_onnx_output(self.onnx_embed(batch), **kwargs)
108
119
  else:
109
120
  if parallel == 0:
110
121
  parallel = os.cpu_count()
@@ -114,6 +125,8 @@ class OnnxImageModel(OnnxModel[T]):
114
125
  "model_name": model_name,
115
126
  "cache_dir": cache_dir,
116
127
  "providers": providers,
128
+ "local_files_only": local_files_only,
129
+ "specific_model_path": specific_model_path,
117
130
  **kwargs,
118
131
  }
119
132
 
@@ -125,7 +138,7 @@ class OnnxImageModel(OnnxModel[T]):
125
138
  start_method=start_method,
126
139
  )
127
140
  for batch in pool.ordered_map(iter_batch(images, batch_size), **params):
128
- yield from self._post_process_onnx_output(batch) # type: ignore
141
+ yield from self._post_process_onnx_output(batch, **kwargs) # type: ignore
129
142
 
130
143
 
131
144
  class ImageEmbeddingWorker(EmbeddingWorker[T]):
@@ -72,26 +72,26 @@ def normalize(
72
72
  if not np.issubdtype(image.dtype, np.floating):
73
73
  image = image.astype(np.float32)
74
74
 
75
- mean = mean if isinstance(mean, list) else [mean] * num_channels
75
+ mean_list = mean if isinstance(mean, list) else [mean] * num_channels
76
76
 
77
- if len(mean) != num_channels:
77
+ if len(mean_list) != num_channels:
78
78
  raise ValueError(
79
79
  f"mean must have the same number of channels as the image, image has {num_channels} channels, got "
80
- f"{len(mean)}"
80
+ f"{len(mean_list)}"
81
81
  )
82
82
 
83
- mean_arr = np.array(mean, dtype=np.float32)
83
+ mean_arr = np.array(mean_list, dtype=np.float32)
84
84
 
85
- std = std if isinstance(std, list) else [std] * num_channels
86
- if len(std) != num_channels:
85
+ std_list = std if isinstance(std, list) else [std] * num_channels
86
+ if len(std_list) != num_channels:
87
87
  raise ValueError(
88
- f"std must have the same number of channels as the image, image has {num_channels} channels, got {len(std)}"
88
+ f"std must have the same number of channels as the image, image has {num_channels} channels, got {len(std_list)}"
89
89
  )
90
90
 
91
- std_arr = np.array(std, dtype=np.float32)
91
+ std_arr = np.array(std_list, dtype=np.float32)
92
92
 
93
- image = ((image.T - mean_arr) / std_arr).T
94
- return image
93
+ image_upd = ((image.T - mean_arr) / std_arr).T
94
+ return image_upd
95
95
 
96
96
 
97
97
  def resize(
@@ -43,7 +43,7 @@ class Colbert(LateInteractionTextEmbeddingBase, OnnxTextModel[NumpyArray]):
43
43
  MASK_TOKEN = "[MASK]"
44
44
 
45
45
  def _post_process_onnx_output(
46
- self, output: OnnxOutputContext, is_doc: bool = True
46
+ self, output: OnnxOutputContext, is_doc: bool = True, **kwargs: Any
47
47
  ) -> Iterable[NumpyArray]:
48
48
  if not is_doc:
49
49
  return output.model_output
@@ -169,11 +169,12 @@ class Colbert(LateInteractionTextEmbeddingBase, OnnxTextModel[NumpyArray]):
169
169
  self.model_description = self._get_model_description(model_name)
170
170
  self.cache_dir = str(define_cache_dir(cache_dir))
171
171
 
172
+ self._specific_model_path = specific_model_path
172
173
  self._model_dir = self.download_model(
173
174
  self.model_description,
174
175
  self.cache_dir,
175
176
  local_files_only=self._local_files_only,
176
- specific_model_path=specific_model_path,
177
+ specific_model_path=self._specific_model_path,
177
178
  )
178
179
  self.mask_token_id: Optional[int] = None
179
180
  self.pad_token_id: Optional[int] = None
@@ -233,6 +234,8 @@ class Colbert(LateInteractionTextEmbeddingBase, OnnxTextModel[NumpyArray]):
233
234
  providers=self.providers,
234
235
  cuda=self.cuda,
235
236
  device_ids=self.device_ids,
237
+ local_files_only=self._local_files_only,
238
+ specific_model_path=self._specific_model_path,
236
239
  **kwargs,
237
240
  )
238
241
 
@@ -17,6 +17,7 @@ class LateInteractionTextEmbeddingBase(ModelManagement[DenseModelDescription]):
17
17
  self.cache_dir = cache_dir
18
18
  self.threads = threads
19
19
  self._local_files_only = kwargs.pop("local_files_only", False)
20
+ self._embedding_size: Optional[int] = None
20
21
 
21
22
  def embed(
22
23
  self,
@@ -58,3 +59,13 @@ class LateInteractionTextEmbeddingBase(ModelManagement[DenseModelDescription]):
58
59
  yield from self.embed([query], **kwargs)
59
60
  else:
60
61
  yield from self.embed(query, **kwargs)
62
+
63
+ @classmethod
64
+ def get_embedding_size(cls, model_name: str) -> int:
65
+ """Returns embedding size of the chosen model."""
66
+ raise NotImplementedError("Subclasses must implement this method")
67
+
68
+ @property
69
+ def embedding_size(self) -> int:
70
+ """Returns embedding size for the current model"""
71
+ raise NotImplementedError("Subclasses must implement this method")
@@ -80,6 +80,40 @@ class LateInteractionTextEmbedding(LateInteractionTextEmbeddingBase):
80
80
  "Please check the supported models using `LateInteractionTextEmbedding.list_supported_models()`"
81
81
  )
82
82
 
83
+ @property
84
+ def embedding_size(self) -> int:
85
+ """Get the embedding size of the current model"""
86
+ if self._embedding_size is None:
87
+ self._embedding_size = self.get_embedding_size(self.model_name)
88
+ return self._embedding_size
89
+
90
+ @classmethod
91
+ def get_embedding_size(cls, model_name: str) -> int:
92
+ """Get the embedding size of the passed model
93
+
94
+ Args:
95
+ model_name (str): The name of the model to get embedding size for.
96
+
97
+ Returns:
98
+ int: The size of the embedding.
99
+
100
+ Raises:
101
+ ValueError: If the model name is not found in the supported models.
102
+ """
103
+ descriptions = cls._list_supported_models()
104
+ embedding_size: Optional[int] = None
105
+ for description in descriptions:
106
+ if description.model.lower() == model_name.lower():
107
+ embedding_size = description.dim
108
+ break
109
+ if embedding_size is None:
110
+ model_names = [description.model for description in descriptions]
111
+ raise ValueError(
112
+ f"Embedding size for model {model_name} was None. "
113
+ f"Available model names: {model_names}"
114
+ )
115
+ return embedding_size
116
+
83
117
  def embed(
84
118
  self,
85
119
  documents: Union[str, Iterable[str]],
@@ -0,0 +1,83 @@
1
+ from dataclasses import asdict
2
+ from typing import Union, Iterable, Optional, Any, Type
3
+
4
+ from fastembed.common.model_description import DenseModelDescription, ModelSource
5
+ from fastembed.common.onnx_model import OnnxOutputContext
6
+ from fastembed.common.types import NumpyArray
7
+ from fastembed.late_interaction.late_interaction_embedding_base import (
8
+ LateInteractionTextEmbeddingBase,
9
+ )
10
+ from fastembed.text.onnx_embedding import OnnxTextEmbedding
11
+ from fastembed.text.onnx_text_model import TextEmbeddingWorker
12
+
13
+
14
+ supported_token_embeddings_models = [
15
+ DenseModelDescription(
16
+ model="jinaai/jina-embeddings-v2-small-en-tokens",
17
+ dim=512,
18
+ description="Text embeddings, Unimodal (text), English, 8192 input tokens truncation,"
19
+ " Prefixes for queries/documents: not necessary, 2023 year.",
20
+ license="apache-2.0",
21
+ size_in_GB=0.12,
22
+ sources=ModelSource(hf="xenova/jina-embeddings-v2-small-en"),
23
+ model_file="onnx/model.onnx",
24
+ ),
25
+ ]
26
+
27
+
28
+ class TokenEmbeddingsModel(OnnxTextEmbedding, LateInteractionTextEmbeddingBase):
29
+ @classmethod
30
+ def _list_supported_models(cls) -> list[DenseModelDescription]:
31
+ """Lists the supported models.
32
+
33
+ Returns:
34
+ list[DenseModelDescription]: A list of DenseModelDescription objects containing the model information.
35
+ """
36
+ return supported_token_embeddings_models
37
+
38
+ @classmethod
39
+ def list_supported_models(cls) -> list[dict[str, Any]]:
40
+ """Lists the supported models.
41
+
42
+ Returns:
43
+ list[dict[str, Any]]: A list of dictionaries containing the model information.
44
+ """
45
+ return [asdict(model) for model in cls._list_supported_models()]
46
+
47
+ @classmethod
48
+ def _get_worker_class(cls) -> Type[TextEmbeddingWorker[NumpyArray]]:
49
+ return TokensEmbeddingWorker
50
+
51
+ def _post_process_onnx_output(
52
+ self, output: OnnxOutputContext, **kwargs: Any
53
+ ) -> Iterable[NumpyArray]:
54
+ # Size: (batch_size, sequence_length, hidden_size)
55
+ embeddings = output.model_output
56
+ # Size: (batch_size, sequence_length)
57
+ assert output.attention_mask is not None
58
+ masks = output.attention_mask
59
+
60
+ # For each document we only select those embeddings that are not masked out
61
+ for i in range(embeddings.shape[0]):
62
+ yield embeddings[i, masks[i] == 1]
63
+
64
+ def embed(
65
+ self,
66
+ documents: Union[str, Iterable[str]],
67
+ batch_size: int = 256,
68
+ parallel: Optional[int] = None,
69
+ **kwargs: Any,
70
+ ) -> Iterable[NumpyArray]:
71
+ yield from super().embed(documents, batch_size=batch_size, parallel=parallel, **kwargs)
72
+
73
+
74
+ class TokensEmbeddingWorker(TextEmbeddingWorker[NumpyArray]):
75
+ def init_embedding(
76
+ self, model_name: str, cache_dir: str, **kwargs: Any
77
+ ) -> TokenEmbeddingsModel:
78
+ return TokenEmbeddingsModel(
79
+ model_name=model_name,
80
+ cache_dir=cache_dir,
81
+ threads=1,
82
+ **kwargs,
83
+ )
@@ -95,11 +95,12 @@ class ColPali(LateInteractionMultimodalEmbeddingBase, OnnxMultimodalModel[NumpyA
95
95
  self.model_description = self._get_model_description(model_name)
96
96
  self.cache_dir = str(define_cache_dir(cache_dir))
97
97
 
98
+ self._specific_model_path = specific_model_path
98
99
  self._model_dir = self.download_model(
99
100
  self.model_description,
100
101
  self.cache_dir,
101
102
  local_files_only=self._local_files_only,
102
- specific_model_path=specific_model_path,
103
+ specific_model_path=self._specific_model_path,
103
104
  )
104
105
  self.mask_token_id = None
105
106
  self.pad_token_id = None
@@ -174,7 +175,7 @@ class ColPali(LateInteractionMultimodalEmbeddingBase, OnnxMultimodalModel[NumpyA
174
175
  ) -> dict[str, NumpyArray]:
175
176
  onnx_input["input_ids"] = np.array(
176
177
  [
177
- self.QUERY_MARKER_TOKEN_ID + input_ids[2:].tolist()
178
+ self.QUERY_MARKER_TOKEN_ID + input_ids[2:].tolist() # type: ignore[index]
178
179
  for input_ids in onnx_input["input_ids"]
179
180
  ]
180
181
  )
@@ -235,6 +236,8 @@ class ColPali(LateInteractionMultimodalEmbeddingBase, OnnxMultimodalModel[NumpyA
235
236
  providers=self.providers,
236
237
  cuda=self.cuda,
237
238
  device_ids=self.device_ids,
239
+ local_files_only=self._local_files_only,
240
+ specific_model_path=self._specific_model_path,
238
241
  **kwargs,
239
242
  )
240
243
 
@@ -268,6 +271,8 @@ class ColPali(LateInteractionMultimodalEmbeddingBase, OnnxMultimodalModel[NumpyA
268
271
  providers=self.providers,
269
272
  cuda=self.cuda,
270
273
  device_ids=self.device_ids,
274
+ local_files_only=self._local_files_only,
275
+ specific_model_path=self._specific_model_path,
271
276
  **kwargs,
272
277
  )
273
278
 
@@ -83,6 +83,40 @@ class LateInteractionMultimodalEmbedding(LateInteractionMultimodalEmbeddingBase)
83
83
  "Please check the supported models using `LateInteractionMultimodalEmbedding.list_supported_models()`"
84
84
  )
85
85
 
86
+ @property
87
+ def embedding_size(self) -> int:
88
+ """Get the embedding size of the current model"""
89
+ if self._embedding_size is None:
90
+ self._embedding_size = self.get_embedding_size(self.model_name)
91
+ return self._embedding_size
92
+
93
+ @classmethod
94
+ def get_embedding_size(cls, model_name: str) -> int:
95
+ """Get the embedding size of the passed model
96
+
97
+ Args:
98
+ model_name (str): The name of the model to get embedding size for.
99
+
100
+ Returns:
101
+ int: The size of the embedding.
102
+
103
+ Raises:
104
+ ValueError: If the model name is not found in the supported models.
105
+ """
106
+ descriptions = cls._list_supported_models()
107
+ embedding_size: Optional[int] = None
108
+ for description in descriptions:
109
+ if description.model.lower() == model_name.lower():
110
+ embedding_size = description.dim
111
+ break
112
+ if embedding_size is None:
113
+ model_names = [description.model for description in descriptions]
114
+ raise ValueError(
115
+ f"Embedding size for model {model_name} was None. "
116
+ f"Available model names: {model_names}"
117
+ )
118
+ return embedding_size
119
+
86
120
  def embed_text(
87
121
  self,
88
122
  documents: Union[str, Iterable[str]],
@@ -19,6 +19,7 @@ class LateInteractionMultimodalEmbeddingBase(ModelManagement[DenseModelDescripti
19
19
  self.cache_dir = cache_dir
20
20
  self.threads = threads
21
21
  self._local_files_only = kwargs.pop("local_files_only", False)
22
+ self._embedding_size: Optional[int] = None
22
23
 
23
24
  def embed_text(
24
25
  self,
@@ -65,3 +66,13 @@ class LateInteractionMultimodalEmbeddingBase(ModelManagement[DenseModelDescripti
65
66
  List of embeddings, one per image
66
67
  """
67
68
  raise NotImplementedError()
69
+
70
+ @classmethod
71
+ def get_embedding_size(cls, model_name: str) -> int:
72
+ """Returns embedding size of the chosen model."""
73
+ raise NotImplementedError("Subclasses must implement this method")
74
+
75
+ @property
76
+ def embedding_size(self) -> int:
77
+ """Returns embedding size for the current model"""
78
+ raise NotImplementedError("Subclasses must implement this method")
@@ -120,6 +120,8 @@ class OnnxMultimodalModel(OnnxModel[T]):
120
120
  providers: Optional[Sequence[OnnxProvider]] = None,
121
121
  cuda: bool = False,
122
122
  device_ids: Optional[list[int]] = None,
123
+ local_files_only: bool = False,
124
+ specific_model_path: Optional[str] = None,
123
125
  **kwargs: Any,
124
126
  ) -> Iterable[T]:
125
127
  is_small = False
@@ -146,6 +148,8 @@ class OnnxMultimodalModel(OnnxModel[T]):
146
148
  "model_name": model_name,
147
149
  "cache_dir": cache_dir,
148
150
  "providers": providers,
151
+ "local_files_only": local_files_only,
152
+ "specific_model_path": specific_model_path,
149
153
  **kwargs,
150
154
  }
151
155
 
@@ -183,6 +187,8 @@ class OnnxMultimodalModel(OnnxModel[T]):
183
187
  providers: Optional[Sequence[OnnxProvider]] = None,
184
188
  cuda: bool = False,
185
189
  device_ids: Optional[list[int]] = None,
190
+ local_files_only: bool = False,
191
+ specific_model_path: Optional[str] = None,
186
192
  **kwargs: Any,
187
193
  ) -> Iterable[T]:
188
194
  is_small = False
@@ -209,6 +215,8 @@ class OnnxMultimodalModel(OnnxModel[T]):
209
215
  "model_name": model_name,
210
216
  "cache_dir": cache_dir,
211
217
  "providers": providers,
218
+ "local_files_only": local_files_only,
219
+ "specific_model_path": specific_model_path,
212
220
  **kwargs,
213
221
  }
214
222
 
@@ -131,11 +131,12 @@ class OnnxTextCrossEncoder(TextCrossEncoderBase, OnnxCrossEncoderModel):
131
131
 
132
132
  self.model_description = self._get_model_description(model_name)
133
133
  self.cache_dir = str(define_cache_dir(cache_dir))
134
+ self._specific_model_path = specific_model_path
134
135
  self._model_dir = self.download_model(
135
136
  self.model_description,
136
137
  self.cache_dir,
137
138
  local_files_only=self._local_files_only,
138
- specific_model_path=specific_model_path,
139
+ specific_model_path=self._specific_model_path,
139
140
  )
140
141
 
141
142
  if not self.lazy_load:
@@ -189,6 +190,8 @@ class OnnxTextCrossEncoder(TextCrossEncoderBase, OnnxCrossEncoderModel):
189
190
  providers=self.providers,
190
191
  cuda=self.cuda,
191
192
  device_ids=self.device_ids,
193
+ local_files_only=self._local_files_only,
194
+ specific_model_path=self._specific_model_path,
192
195
  **kwargs,
193
196
  )
194
197
 
@@ -196,7 +199,9 @@ class OnnxTextCrossEncoder(TextCrossEncoderBase, OnnxCrossEncoderModel):
196
199
  def _get_worker_class(cls) -> Type[TextRerankerWorker]:
197
200
  return TextCrossEncoderWorker
198
201
 
199
- def _post_process_onnx_output(self, output: OnnxOutputContext) -> Iterable[float]:
202
+ def _post_process_onnx_output(
203
+ self, output: OnnxOutputContext, **kwargs: Any
204
+ ) -> Iterable[float]:
200
205
  return (float(elem) for elem in output.model_output)
201
206
 
202
207
 
@@ -94,6 +94,8 @@ class OnnxCrossEncoderModel(OnnxModel[float]):
94
94
  providers: Optional[Sequence[OnnxProvider]] = None,
95
95
  cuda: bool = False,
96
96
  device_ids: Optional[list[int]] = None,
97
+ local_files_only: bool = False,
98
+ specific_model_path: Optional[str] = None,
97
99
  **kwargs: Any,
98
100
  ) -> Iterable[float]:
99
101
  is_small = False
@@ -120,6 +122,8 @@ class OnnxCrossEncoderModel(OnnxModel[float]):
120
122
  "model_name": model_name,
121
123
  "cache_dir": cache_dir,
122
124
  "providers": providers,
125
+ "local_files_only": local_files_only,
126
+ "specific_model_path": specific_model_path,
123
127
  **kwargs,
124
128
  }
125
129
 
@@ -133,7 +137,18 @@ class OnnxCrossEncoderModel(OnnxModel[float]):
133
137
  for batch in pool.ordered_map(iter_batch(pairs, batch_size), **params):
134
138
  yield from self._post_process_onnx_output(batch) # type: ignore
135
139
 
136
- def _post_process_onnx_output(self, output: OnnxOutputContext) -> Iterable[float]:
140
+ def _post_process_onnx_output(
141
+ self, output: OnnxOutputContext, **kwargs: Any
142
+ ) -> Iterable[float]:
143
+ """Post-process the ONNX model output to convert it into a usable format.
144
+
145
+ Args:
146
+ output (OnnxOutputContext): The raw output from the ONNX model.
147
+ **kwargs: Additional keyword arguments that may be needed by specific implementations.
148
+
149
+ Returns:
150
+ Iterable[float]: Post-processed output as an iterable of float values.
151
+ """
137
152
  raise NotImplementedError("Subclasses must implement this method")
138
153
 
139
154
  def _preprocess_onnx_input(