Visual Document Retrieval
PEFT
Safetensors
vidore
multimodal_embedding
multilingual_embedding
Text-to-Visual Document (T→VD) retrieval
Instructions to use Metric-AI/ColQwen2.5-3b-multilingual-v1.0 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use Metric-AI/ColQwen2.5-3b-multilingual-v1.0 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Integrate with Sentence Transformers via MultiVectorEncoder
Browse files- 1_Dense/config.json +8 -0
- 1_Dense/model.safetensors +3 -0
- 2_Normalize/config.json +4 -0
- 3_MultiVectorMask/config.json +5 -0
- README.md +64 -0
- additional_chat_templates/sentence_transformers.jinja +22 -0
- chat_template.jinja +7 -0
- chat_template.json +0 -3
- config_sentence_transformers.json +18 -0
- modules.json +26 -0
- processor_config.json +3 -0
- sentence_bert_config.json +30 -0
- tokenizer_config.json +1 -0
1_Dense/config.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"in_features": 2048,
|
| 3 |
+
"out_features": 128,
|
| 4 |
+
"bias": true,
|
| 5 |
+
"activation_function": "torch.nn.modules.linear.Identity",
|
| 6 |
+
"module_input_name": "token_embeddings",
|
| 7 |
+
"module_output_name": "token_embeddings"
|
| 8 |
+
}
|
1_Dense/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:75e5f5783ba184514e1bf9657296dbe12d78853233f16b4098271350738a235a
|
| 3 |
+
size 1049248
|
2_Normalize/config.json
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"module_input_name": "token_embeddings",
|
| 3 |
+
"module_output_name": "token_embeddings"
|
| 4 |
+
}
|
3_MultiVectorMask/config.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"skiplist_words": [],
|
| 3 |
+
"skiplist_tasks": [],
|
| 4 |
+
"keep_only_token_ids": null
|
| 5 |
+
}
|
README.md
CHANGED
|
@@ -20,6 +20,8 @@ tags:
|
|
| 20 |
- multimodal_embedding
|
| 21 |
- multilingual_embedding
|
| 22 |
- Text-to-Visual Document (T→VD) retrieval
|
|
|
|
|
|
|
| 23 |
library_name: peft
|
| 24 |
pipeline_tag: visual-document-retrieval
|
| 25 |
---
|
|
@@ -85,6 +87,68 @@ KeyError: 'qwen2_5_vl'
|
|
| 85 |
|
| 86 |
## Usage
|
| 87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
```python
|
| 89 |
import torch
|
| 90 |
from PIL import Image
|
|
|
|
| 20 |
- multimodal_embedding
|
| 21 |
- multilingual_embedding
|
| 22 |
- Text-to-Visual Document (T→VD) retrieval
|
| 23 |
+
- sentence-transformers
|
| 24 |
+
- multi-vector
|
| 25 |
library_name: peft
|
| 26 |
pipeline_tag: visual-document-retrieval
|
| 27 |
---
|
|
|
|
| 87 |
|
| 88 |
## Usage
|
| 89 |
|
| 90 |
+
### Using Sentence Transformers
|
| 91 |
+
|
| 92 |
+
This checkpoint can be used as a multi-vector (ColBERT-style late interaction) retriever with Sentence Transformers via the `MultiVectorEncoder`:
|
| 93 |
+
|
| 94 |
+
```bash
|
| 95 |
+
pip install "sentence-transformers[image]>=6.0.0"
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
```python
|
| 99 |
+
from sentence_transformers import MultiVectorEncoder
|
| 100 |
+
|
| 101 |
+
model = MultiVectorEncoder("Metric-AI/ColQwen2.5-3b-multilingual-v1.0")
|
| 102 |
+
|
| 103 |
+
queries = [
|
| 104 |
+
"What is the variable represented on the y-axis of the graph?",
|
| 105 |
+
"Total outlay is maximum in which year?",
|
| 106 |
+
]
|
| 107 |
+
images = [
|
| 108 |
+
"https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc1.jpg",
|
| 109 |
+
"https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc2.jpg",
|
| 110 |
+
"https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc3.jpg",
|
| 111 |
+
"https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc4.jpg",
|
| 112 |
+
]
|
| 113 |
+
|
| 114 |
+
query_embeddings = model.encode_query(queries)
|
| 115 |
+
document_embeddings = model.encode_document(images)
|
| 116 |
+
print(f"Query 0 shape: {tuple(query_embeddings[0].shape)}")
|
| 117 |
+
print(f"Document 0 shape: {tuple(document_embeddings[0].shape)}")
|
| 118 |
+
# Query 0 shape: (25, 128)
|
| 119 |
+
# Document 0 shape: (4115, 128)
|
| 120 |
+
|
| 121 |
+
# MaxSim late-interaction scoring (rows = queries, columns = images)
|
| 122 |
+
scores = model.similarity(query_embeddings, document_embeddings)
|
| 123 |
+
print(scores)
|
| 124 |
+
# tensor([[15.6797, 12.8027, 12.3555, 12.2031],
|
| 125 |
+
# [ 8.9121, 15.5352, 9.7109, 8.1387]])
|
| 126 |
+
```
|
| 127 |
+
|
| 128 |
+
`encode_query` applies the `Query: ` prefix and the ten `<|endoftext|>` augmentation tokens, `encode_document` applies the visual prompt, and both apply the 128-dimensional projection, the L2 normalization and the padding mask. Documents can be file paths, URLs or `PIL.Image` objects, and both methods accept a `batch_size`.
|
| 129 |
+
|
| 130 |
+
The scores above come from the plain load, which uses the base checkpoint's `bfloat16` weights. Loading options are forwarded through `model_kwargs`:
|
| 131 |
+
|
| 132 |
+
```python
|
| 133 |
+
model = MultiVectorEncoder(
|
| 134 |
+
"Metric-AI/ColQwen2.5-3b-multilingual-v1.0",
|
| 135 |
+
model_kwargs={"dtype": "float32", "attn_implementation": "sdpa", "device_map": "cuda:0"},
|
| 136 |
+
)
|
| 137 |
+
```
|
| 138 |
+
|
| 139 |
+
Note that `preprocessor_config.json` in this repository keeps the stock Qwen2.5-VL `max_pixels` of 12845056, so a full page turns into roughly 4000 to 5000 visual tokens rather than the 768 patches mentioned above. Pass `processor_kwargs={"max_pixels": 768 * 28 * 28}` to cap it, which is the Sentence Transformers equivalent of `ColQwen2_5_Processor.from_pretrained(..., max_num_visual_tokens=768)`.
|
| 140 |
+
|
| 141 |
+
### Using ColPali Engine
|
| 142 |
+
|
| 143 |
+
> [!WARNING]
|
| 144 |
+
> Current `colpali-engine` no longer sends the `Query: ` prefix that this checkpoint was trained
|
| 145 |
+
> with. It was dropped from `ColQwen2_5_Processor` in 0.3.11
|
| 146 |
+
> ([illuin-tech/colpali#280](https://github.com/illuin-tech/colpali/pull/280)). The Sentence
|
| 147 |
+
> Transformers configuration in this repository reproduces the original training-time format, so
|
| 148 |
+
> its query embeddings differ slightly from current `colpali-engine` output. Install
|
| 149 |
+
> `colpali-engine<0.3.11`, or set `processor.query_prefix = "Query: "` after loading, to get the
|
| 150 |
+
> training-time format from the snippet below.
|
| 151 |
+
|
| 152 |
```python
|
| 153 |
import torch
|
| 154 |
from PIL import Image
|
additional_chat_templates/sentence_transformers.jinja
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{%- if task is defined and task == 'query' -%}
|
| 2 |
+
{%- for message in messages -%}
|
| 3 |
+
{%- for content in message['content'] -%}
|
| 4 |
+
{%- if content['type'] == 'text' -%}
|
| 5 |
+
{{- 'Query: ' + content['text'] -}}
|
| 6 |
+
{%- for _ in range(10) -%}
|
| 7 |
+
{{- '<|endoftext|>' -}}
|
| 8 |
+
{%- endfor -%}
|
| 9 |
+
{%- endif -%}
|
| 10 |
+
{%- endfor -%}
|
| 11 |
+
{%- endfor -%}
|
| 12 |
+
{%- else -%}
|
| 13 |
+
{%- for message in messages -%}
|
| 14 |
+
{%- for content in message['content'] -%}
|
| 15 |
+
{%- if content['type'] == 'image' -%}
|
| 16 |
+
{{- '<|im_start|>user\n<|vision_start|><|image_pad|><|vision_end|>Describe the image.<|im_end|><|endoftext|>' -}}
|
| 17 |
+
{%- elif content['type'] == 'text' -%}
|
| 18 |
+
{{- content['text'] -}}
|
| 19 |
+
{%- endif -%}
|
| 20 |
+
{%- endfor -%}
|
| 21 |
+
{%- endfor -%}
|
| 22 |
+
{%- endif -%}
|
chat_template.jinja
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{% set image_count = namespace(value=0) %}{% set video_count = namespace(value=0) %}{% for message in messages %}{% if loop.first and message['role'] != 'system' %}<|im_start|>system
|
| 2 |
+
You are a helpful assistant.<|im_end|>
|
| 3 |
+
{% endif %}<|im_start|>{{ message['role'] }}
|
| 4 |
+
{% if message['content'] is string %}{{ message['content'] }}<|im_end|>
|
| 5 |
+
{% else %}{% for content in message['content'] %}{% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}{% set image_count.value = image_count.value + 1 %}{% if add_vision_id %}Picture {{ image_count.value }}: {% endif %}<|vision_start|><|image_pad|><|vision_end|>{% elif content['type'] == 'video' or 'video' in content %}{% set video_count.value = video_count.value + 1 %}{% if add_vision_id %}Video {{ video_count.value }}: {% endif %}<|vision_start|><|video_pad|><|vision_end|>{% elif 'text' in content %}{{ content['text'] }}{% endif %}{% endfor %}<|im_end|>
|
| 6 |
+
{% endif %}{% endfor %}{% if add_generation_prompt %}<|im_start|>assistant
|
| 7 |
+
{% endif %}
|
chat_template.json
DELETED
|
@@ -1,3 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"chat_template": "{% set image_count = namespace(value=0) %}{% set video_count = namespace(value=0) %}{% for message in messages %}{% if loop.first and message['role'] != 'system' %}<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n{% endif %}<|im_start|>{{ message['role'] }}\n{% if message['content'] is string %}{{ message['content'] }}<|im_end|>\n{% else %}{% for content in message['content'] %}{% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}{% set image_count.value = image_count.value + 1 %}{% if add_vision_id %}Picture {{ image_count.value }}: {% endif %}<|vision_start|><|image_pad|><|vision_end|>{% elif content['type'] == 'video' or 'video' in content %}{% set video_count.value = video_count.value + 1 %}{% if add_vision_id %}Video {{ video_count.value }}: {% endif %}<|vision_start|><|video_pad|><|vision_end|>{% elif 'text' in content %}{{ content['text'] }}{% endif %}{% endfor %}<|im_end|>\n{% endif %}{% endfor %}{% if add_generation_prompt %}<|im_start|>assistant\n{% endif %}"
|
| 3 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
config_sentence_transformers.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"__version__": {
|
| 3 |
+
"sentence_transformers": "6.0.0"
|
| 4 |
+
},
|
| 5 |
+
"default_prompt_name": null,
|
| 6 |
+
"model_type": "MultiVectorEncoder",
|
| 7 |
+
"requirements": {
|
| 8 |
+
"transformers": {
|
| 9 |
+
"specifier": ">=5.15",
|
| 10 |
+
"reason": "Older versions ignore the key_mapping, which silently randomizes the adapter weights."
|
| 11 |
+
}
|
| 12 |
+
},
|
| 13 |
+
"prompts": {
|
| 14 |
+
"document": "",
|
| 15 |
+
"query": ""
|
| 16 |
+
},
|
| 17 |
+
"similarity_fn_name": null
|
| 18 |
+
}
|
modules.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[
|
| 2 |
+
{
|
| 3 |
+
"idx": 0,
|
| 4 |
+
"name": "0",
|
| 5 |
+
"path": "",
|
| 6 |
+
"type": "sentence_transformers.base.modules.transformer.Transformer"
|
| 7 |
+
},
|
| 8 |
+
{
|
| 9 |
+
"idx": 1,
|
| 10 |
+
"name": "1",
|
| 11 |
+
"path": "1_Dense",
|
| 12 |
+
"type": "sentence_transformers.base.modules.dense.Dense"
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"idx": 2,
|
| 16 |
+
"name": "2",
|
| 17 |
+
"path": "2_Normalize",
|
| 18 |
+
"type": "sentence_transformers.base.modules.normalize.Normalize"
|
| 19 |
+
},
|
| 20 |
+
{
|
| 21 |
+
"idx": 3,
|
| 22 |
+
"name": "3",
|
| 23 |
+
"path": "3_MultiVectorMask",
|
| 24 |
+
"type": "sentence_transformers.multi_vector_encoder.modules.multi_vector_mask.MultiVectorMask"
|
| 25 |
+
}
|
| 26 |
+
]
|
processor_config.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"processor_class": "Qwen2_5_VLProcessor"
|
| 3 |
+
}
|
sentence_bert_config.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"transformer_task": "feature-extraction",
|
| 3 |
+
"modality_config": {
|
| 4 |
+
"text": {
|
| 5 |
+
"method": "forward",
|
| 6 |
+
"method_output_name": "last_hidden_state"
|
| 7 |
+
},
|
| 8 |
+
"image": {
|
| 9 |
+
"method": "forward",
|
| 10 |
+
"method_output_name": "last_hidden_state"
|
| 11 |
+
},
|
| 12 |
+
"message": {
|
| 13 |
+
"method": "forward",
|
| 14 |
+
"method_output_name": "last_hidden_state",
|
| 15 |
+
"format": "structured"
|
| 16 |
+
}
|
| 17 |
+
},
|
| 18 |
+
"module_output_name": "token_embeddings",
|
| 19 |
+
"unpad_inputs": false,
|
| 20 |
+
"model_kwargs": {
|
| 21 |
+
"key_mapping": {
|
| 22 |
+
"^model\\.": "language_model."
|
| 23 |
+
}
|
| 24 |
+
},
|
| 25 |
+
"processing_kwargs": {
|
| 26 |
+
"chat_template": {
|
| 27 |
+
"chat_template": "sentence_transformers"
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
}
|
tokenizer_config.json
CHANGED
|
@@ -202,6 +202,7 @@
|
|
| 202 |
"extra_special_tokens": {},
|
| 203 |
"model_max_length": 131072,
|
| 204 |
"pad_token": "<|endoftext|>",
|
|
|
|
| 205 |
"processor_class": "ColQwen2_5Processor",
|
| 206 |
"split_special_tokens": false,
|
| 207 |
"tokenizer_class": "Qwen2Tokenizer",
|
|
|
|
| 202 |
"extra_special_tokens": {},
|
| 203 |
"model_max_length": 131072,
|
| 204 |
"pad_token": "<|endoftext|>",
|
| 205 |
+
"padding_side": "left",
|
| 206 |
"processor_class": "ColQwen2_5Processor",
|
| 207 |
"split_special_tokens": false,
|
| 208 |
"tokenizer_class": "Qwen2Tokenizer",
|