feat-rename-vector-type-0622 (#21)
Browse files- feat: avoid the redundant words in the variables (7f10796af034d90842575c6a877c3ef8b8d0b212)
- feat: use enum for the vector type (e7230645cd96df2626c429031ef6d9761c595ab5)
- Merge branch 'main' into pr/21 (085e2ed8f55f14e4ea5a67596d41bf50026ee9f3)
- refactor: rename vector_type to output_format (96925c43b3978bb6de3d3ab0ebfb27701d625f1a)
- feat: rename the VectorType (669c42abab2468a13298a192ff96826e6d8394f1)
- feat: fix the default values (bb1572174c755b90eb888cb78c496db2c3a8ecf4)
- feat: replace the output_format with a boolean flag (1ffab4f0c4c3d022d3c4e3555fd7bcc362262c1f)
- feat: avoid validating return_multivector (fe4c51b73e21a2ac2f1ff293337a3cac82517e88)
- feat: return a list when the input is a list (f7df96abf5c4741c0e88f6b30b347bb7191f7596)
- modeling_jina_embeddings_v4.py +19 -24
@@ -31,7 +31,6 @@ class PromptType(str, Enum):
|
|
31 |
|
32 |
|
33 |
PREFIX_DICT = {"query": "Query", "passage": "Passage"}
|
34 |
-
VECTOR_TYPES = ["single_vector", "multi_vector"]
|
35 |
|
36 |
|
37 |
class JinaEmbeddingsV4Processor(Qwen2_5_VLProcessor):
|
@@ -284,8 +283,9 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
284 |
attention_mask (torch.Tensor): The attention mask tensor.
|
285 |
Returns:
|
286 |
JinaEmbeddingsV4ModelOutput:
|
287 |
-
|
288 |
-
|
|
|
289 |
"""
|
290 |
# Forward pass through the VLM
|
291 |
hidden_states = self.get_last_hidden_states(
|
@@ -320,7 +320,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
320 |
task_label: Union[str, List[str]],
|
321 |
processor_fn: Callable,
|
322 |
desc: str,
|
323 |
-
|
324 |
return_numpy: bool = False,
|
325 |
batch_size: int = 32,
|
326 |
truncate_dim: Optional[int] = None,
|
@@ -340,7 +340,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
340 |
device_type=torch.device(self.device).type, dtype=torch.bfloat16
|
341 |
):
|
342 |
embeddings = self(**batch, task_label=task_label)
|
343 |
-
if
|
344 |
embeddings = embeddings.single_vec_emb
|
345 |
if truncate_dim is not None:
|
346 |
embeddings = embeddings[:, :truncate_dim]
|
@@ -357,7 +357,6 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
357 |
|
358 |
def _validate_encoding_params(
|
359 |
self,
|
360 |
-
vector_type: Optional[str] = None,
|
361 |
truncate_dim: Optional[int] = None,
|
362 |
prompt_name: Optional[str] = None,
|
363 |
) -> Dict[str, Any]:
|
@@ -374,14 +373,6 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
374 |
else PREFIX_DICT["query"]
|
375 |
)
|
376 |
|
377 |
-
vector_type = vector_type or "single_vector"
|
378 |
-
if vector_type not in VECTOR_TYPES:
|
379 |
-
raise ValueError(
|
380 |
-
f"Invalid vector_type: {vector_type}. Must be one of {VECTOR_TYPES}."
|
381 |
-
)
|
382 |
-
else:
|
383 |
-
encode_kwargs["vector_type"] = vector_type
|
384 |
-
|
385 |
truncate_dim = truncate_dim or self.config.truncate_dim
|
386 |
if truncate_dim is not None and truncate_dim not in self.config.matryoshka_dims:
|
387 |
raise ValueError(
|
@@ -413,7 +404,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
413 |
task: Optional[str] = None,
|
414 |
max_length: int = 8192,
|
415 |
batch_size: int = 8,
|
416 |
-
|
417 |
return_numpy: bool = False,
|
418 |
truncate_dim: Optional[int] = None,
|
419 |
prompt_name: Optional[str] = None,
|
@@ -425,7 +416,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
425 |
texts: text or list of text strings to encode
|
426 |
max_length: Maximum token length for text processing
|
427 |
batch_size: Number of texts to process at once
|
428 |
-
|
429 |
return_numpy: Whether to return numpy arrays instead of torch tensors
|
430 |
truncate_dim: Dimension to truncate embeddings to (128, 256, 512, or 1024)
|
431 |
prompt_name: Type of text being encoded ('query' or 'passage')
|
@@ -434,9 +425,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
434 |
List of text embeddings as tensors or numpy arrays when encoding multiple texts, or single text embedding as tensor when encoding a single text
|
435 |
"""
|
436 |
prompt_name = prompt_name or "query"
|
437 |
-
encode_kwargs = self._validate_encoding_params(
|
438 |
-
vector_type, truncate_dim, prompt_name
|
439 |
-
)
|
440 |
|
441 |
task = self._validate_task(task)
|
442 |
|
@@ -446,6 +435,8 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
446 |
prefix=encode_kwargs.pop("prefix"),
|
447 |
)
|
448 |
|
|
|
|
|
449 |
if isinstance(texts, str):
|
450 |
texts = [texts]
|
451 |
|
@@ -454,12 +445,13 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
454 |
processor_fn=processor_fn,
|
455 |
desc="Encoding texts...",
|
456 |
task_label=task,
|
|
|
457 |
return_numpy=return_numpy,
|
458 |
batch_size=batch_size,
|
459 |
**encode_kwargs,
|
460 |
)
|
461 |
|
462 |
-
return embeddings if
|
463 |
|
464 |
def _load_images_if_needed(
|
465 |
self, images: List[Union[str, Image.Image]]
|
@@ -480,7 +472,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
480 |
images: Union[str, Image.Image, List[Union[str, Image.Image]]],
|
481 |
task: Optional[str] = None,
|
482 |
batch_size: int = 8,
|
483 |
-
|
484 |
return_numpy: bool = False,
|
485 |
truncate_dim: Optional[int] = None,
|
486 |
max_pixels: Optional[int] = None,
|
@@ -491,7 +483,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
491 |
Args:
|
492 |
images: image(s) to encode, can be PIL Image(s), URL(s), or local file path(s)
|
493 |
batch_size: Number of images to process at once
|
494 |
-
|
495 |
return_numpy: Whether to return numpy arrays instead of torch tensors
|
496 |
truncate_dim: Dimension to truncate embeddings to (128, 256, 512, or 1024)
|
497 |
max_pixels: Maximum number of pixels to process per image
|
@@ -504,9 +496,11 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
504 |
self.processor.image_processor.max_pixels = (
|
505 |
max_pixels # change during encoding
|
506 |
)
|
507 |
-
encode_kwargs = self._validate_encoding_params(
|
508 |
task = self._validate_task(task)
|
509 |
|
|
|
|
|
510 |
# Convert single image to list
|
511 |
if isinstance(images, (str, Image.Image)):
|
512 |
images = [images]
|
@@ -518,6 +512,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
518 |
desc="Encoding images...",
|
519 |
task_label=task,
|
520 |
batch_size=batch_size,
|
|
|
521 |
return_numpy=return_numpy,
|
522 |
**encode_kwargs,
|
523 |
)
|
@@ -525,7 +520,7 @@ class JinaEmbeddingsV4Model(Qwen2_5_VLForConditionalGeneration):
|
|
525 |
if max_pixels:
|
526 |
self.processor.image_processor.max_pixels = default_max_pixels
|
527 |
|
528 |
-
return embeddings if
|
529 |
|
530 |
@classmethod
|
531 |
def from_pretrained(
|
|
|
31 |
|
32 |
|
33 |
PREFIX_DICT = {"query": "Query", "passage": "Passage"}
|
|
|
34 |
|
35 |
|
36 |
class JinaEmbeddingsV4Processor(Qwen2_5_VLProcessor):
|
|
|
283 |
attention_mask (torch.Tensor): The attention mask tensor.
|
284 |
Returns:
|
285 |
JinaEmbeddingsV4ModelOutput:
|
286 |
+
vlm_last_hidden_states (torch.Tensor, optional): Last hidden states of the VLM.
|
287 |
+
single_vec_emb (torch.Tensor, optional): Single-vector embeddings.
|
288 |
+
multi_vec_emb (torch.Tensor, optional): Multi-vector embeddings.
|
289 |
"""
|
290 |
# Forward pass through the VLM
|
291 |
hidden_states = self.get_last_hidden_states(
|
|
|
320 |
task_label: Union[str, List[str]],
|
321 |
processor_fn: Callable,
|
322 |
desc: str,
|
323 |
+
return_multivector: bool = False,
|
324 |
return_numpy: bool = False,
|
325 |
batch_size: int = 32,
|
326 |
truncate_dim: Optional[int] = None,
|
|
|
340 |
device_type=torch.device(self.device).type, dtype=torch.bfloat16
|
341 |
):
|
342 |
embeddings = self(**batch, task_label=task_label)
|
343 |
+
if not return_multivector:
|
344 |
embeddings = embeddings.single_vec_emb
|
345 |
if truncate_dim is not None:
|
346 |
embeddings = embeddings[:, :truncate_dim]
|
|
|
357 |
|
358 |
def _validate_encoding_params(
|
359 |
self,
|
|
|
360 |
truncate_dim: Optional[int] = None,
|
361 |
prompt_name: Optional[str] = None,
|
362 |
) -> Dict[str, Any]:
|
|
|
373 |
else PREFIX_DICT["query"]
|
374 |
)
|
375 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
376 |
truncate_dim = truncate_dim or self.config.truncate_dim
|
377 |
if truncate_dim is not None and truncate_dim not in self.config.matryoshka_dims:
|
378 |
raise ValueError(
|
|
|
404 |
task: Optional[str] = None,
|
405 |
max_length: int = 8192,
|
406 |
batch_size: int = 8,
|
407 |
+
return_multivector: bool = False,
|
408 |
return_numpy: bool = False,
|
409 |
truncate_dim: Optional[int] = None,
|
410 |
prompt_name: Optional[str] = None,
|
|
|
416 |
texts: text or list of text strings to encode
|
417 |
max_length: Maximum token length for text processing
|
418 |
batch_size: Number of texts to process at once
|
419 |
+
return_multivector: Whether to return multi-vector embeddings instead of single-vector embeddings
|
420 |
return_numpy: Whether to return numpy arrays instead of torch tensors
|
421 |
truncate_dim: Dimension to truncate embeddings to (128, 256, 512, or 1024)
|
422 |
prompt_name: Type of text being encoded ('query' or 'passage')
|
|
|
425 |
List of text embeddings as tensors or numpy arrays when encoding multiple texts, or single text embedding as tensor when encoding a single text
|
426 |
"""
|
427 |
prompt_name = prompt_name or "query"
|
428 |
+
encode_kwargs = self._validate_encoding_params(truncate_dim=truncate_dim, prompt_name=prompt_name)
|
|
|
|
|
429 |
|
430 |
task = self._validate_task(task)
|
431 |
|
|
|
435 |
prefix=encode_kwargs.pop("prefix"),
|
436 |
)
|
437 |
|
438 |
+
return_list = isinstance(texts, list)
|
439 |
+
|
440 |
if isinstance(texts, str):
|
441 |
texts = [texts]
|
442 |
|
|
|
445 |
processor_fn=processor_fn,
|
446 |
desc="Encoding texts...",
|
447 |
task_label=task,
|
448 |
+
return_multivector=return_multivector,
|
449 |
return_numpy=return_numpy,
|
450 |
batch_size=batch_size,
|
451 |
**encode_kwargs,
|
452 |
)
|
453 |
|
454 |
+
return embeddings if return_list else embeddings[0]
|
455 |
|
456 |
def _load_images_if_needed(
|
457 |
self, images: List[Union[str, Image.Image]]
|
|
|
472 |
images: Union[str, Image.Image, List[Union[str, Image.Image]]],
|
473 |
task: Optional[str] = None,
|
474 |
batch_size: int = 8,
|
475 |
+
return_multivector: bool = False,
|
476 |
return_numpy: bool = False,
|
477 |
truncate_dim: Optional[int] = None,
|
478 |
max_pixels: Optional[int] = None,
|
|
|
483 |
Args:
|
484 |
images: image(s) to encode, can be PIL Image(s), URL(s), or local file path(s)
|
485 |
batch_size: Number of images to process at once
|
486 |
+
return_multivector: Whether to return multi-vector embeddings instead of single-vector embeddings
|
487 |
return_numpy: Whether to return numpy arrays instead of torch tensors
|
488 |
truncate_dim: Dimension to truncate embeddings to (128, 256, 512, or 1024)
|
489 |
max_pixels: Maximum number of pixels to process per image
|
|
|
496 |
self.processor.image_processor.max_pixels = (
|
497 |
max_pixels # change during encoding
|
498 |
)
|
499 |
+
encode_kwargs = self._validate_encoding_params(truncate_dim=truncate_dim)
|
500 |
task = self._validate_task(task)
|
501 |
|
502 |
+
return_list = isinstance(images, list)
|
503 |
+
|
504 |
# Convert single image to list
|
505 |
if isinstance(images, (str, Image.Image)):
|
506 |
images = [images]
|
|
|
512 |
desc="Encoding images...",
|
513 |
task_label=task,
|
514 |
batch_size=batch_size,
|
515 |
+
return_multivector=return_multivector,
|
516 |
return_numpy=return_numpy,
|
517 |
**encode_kwargs,
|
518 |
)
|
|
|
520 |
if max_pixels:
|
521 |
self.processor.image_processor.max_pixels = default_max_pixels
|
522 |
|
523 |
+
return embeddings if return_list else embeddings[0]
|
524 |
|
525 |
@classmethod
|
526 |
def from_pretrained(
|