xiaoxiaoshadiao commited on
Commit
3977f25
·
verified ·
1 Parent(s): 93827af

Add Sentence Transformers MultiVectorEncoder integration

Browse files
1_Dense/config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "in_features": 4096,
3
+ "out_features": 4096,
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:5b0dc39705e9cfd9610dd3cdeaa0c6ac0540c5780e5f08d860e259f4854c887f
3
+ size 67125416
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,3 @@
 
 
 
 
1
+ {
2
+ "skiplist_words": []
3
+ }
README.md CHANGED
@@ -13,6 +13,7 @@ tags:
13
  - vidore
14
  - document-retrieval
15
  - multimodal
 
16
  datasets:
17
  - vidore/vidore_benchmark
18
  - vidore/vidore_benchmark_v2
@@ -165,7 +166,9 @@ Protocol `paired-all-pages-dedup+process_queries+ndcg2r-20260827` ($\text{MVT} =
165
 
166
  ## ⚡ Quick Start
167
 
168
- ### Installation
 
 
169
 
170
  ```bash
171
  git clone https://github.com/Tencent/EVIE.git
@@ -174,7 +177,7 @@ pip install -r requirements.txt
174
  export PYTHONPATH="$(pwd)/colpali${PYTHONPATH:+:$PYTHONPATH}"
175
  ```
176
 
177
- ### Python Inference
178
 
179
  ```python
180
  import torch
@@ -210,6 +213,52 @@ scores = processor.score(query_embeddings, image_embeddings)
210
  print("Late-interaction MaxSim Relevance Score:", scores)
211
  ```
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  ---
214
 
215
  ## 📂 Repository Layout
@@ -218,6 +267,8 @@ print("Late-interaction MaxSim Relevance Score:", scores)
218
  Evie-8B/
219
  ├── model.safetensors # EVIE-8B weights (safetensors)
220
  ├── config.json # Model configuration (4096D)
 
 
221
  ├── infer.py # Standalone inference & scoring CLI
222
  ├── colpali/ # ColQwen3.5 inference engine
223
  ├── code/shared/ # 138-task eval harness
 
13
  - vidore
14
  - document-retrieval
15
  - multimodal
16
+ - sentence-transformers
17
  datasets:
18
  - vidore/vidore_benchmark
19
  - vidore/vidore_benchmark_v2
 
166
 
167
  ## ⚡ Quick Start
168
 
169
+ ### ColPali Engine
170
+
171
+ #### Installation
172
 
173
  ```bash
174
  git clone https://github.com/Tencent/EVIE.git
 
177
  export PYTHONPATH="$(pwd)/colpali${PYTHONPATH:+:$PYTHONPATH}"
178
  ```
179
 
180
+ #### Python Inference
181
 
182
  ```python
183
  import torch
 
213
  print("Late-interaction MaxSim Relevance Score:", scores)
214
  ```
215
 
216
+ ### Sentence Transformers
217
+
218
+ Load EVIE with [Sentence Transformers](https://www.sbert.net/) to encode queries and document images and compute MaxSim scores. Bidirectional attention is configured automatically.
219
+
220
+ ```bash
221
+ pip install -U "sentence-transformers[image]>=6.0.0"
222
+ ```
223
+
224
+ ```python
225
+ from sentence_transformers import MultiVectorEncoder
226
+
227
+ model = MultiVectorEncoder("tencent/EVIE-8B")
228
+
229
+ queries = [
230
+ "What is the variable represented on the y-axis of the graph?",
231
+ "Total outlay is maximum in which year?",
232
+ ]
233
+ documents = [
234
+ "https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc1.jpg",
235
+ "https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc2.jpg",
236
+ "https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc3.jpg",
237
+ "https://huggingface.co/datasets/sentence-transformers/example-documents/resolve/main/doc4.jpg",
238
+ ]
239
+
240
+ query_embeddings = model.encode_query(queries)
241
+ document_embeddings = model.encode_document(documents, batch_size=1)
242
+ print(query_embeddings[0].shape, document_embeddings[0].shape)
243
+ # torch.Size([23, 4096]) torch.Size([3161, 4096])
244
+
245
+ scores = model.similarity(query_embeddings, document_embeddings)
246
+ print(scores)
247
+ # tensor([[14.3594, 6.1758, 4.5137, 3.2979],
248
+ # [ 1.8079, 10.9180, 1.9668, 1.9541]])
249
+ ```
250
+
251
+ Documents can be URLs, local image paths, or `PIL.Image` objects. The output contains 4096-dimensional token embeddings. Scores can vary slightly with dtype and attention backend.
252
+
253
+ The default page budget allows up to 16,384 visual tokens. Encoding images one at a time reduces peak memory use. To use the 1,024-token budget from the evaluation protocol above, set the image processor's pixel budget:
254
+
255
+ ```python
256
+ model = MultiVectorEncoder(
257
+ "tencent/EVIE-8B",
258
+ processor_kwargs={"size": {"longest_edge": 1024 * 32 * 32, "shortest_edge": 65536}},
259
+ )
260
+ ```
261
+
262
  ---
263
 
264
  ## 📂 Repository Layout
 
267
  Evie-8B/
268
  ├── model.safetensors # EVIE-8B weights (safetensors)
269
  ├── config.json # Model configuration (4096D)
270
+ ├── 1_Dense/ # Sentence Transformers 4096D projection
271
+ ├── modules.json # MultiVectorEncoder module graph
272
  ├── infer.py # Standalone inference & scoring CLI
273
  ├── colpali/ # ColQwen3.5 inference engine
274
  ├── code/shared/ # 138-task eval harness
additional_chat_templates/sentence_transformers.jinja ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- for message in messages -%}
2
+ {%- set ns = namespace(has_image=false, text='') -%}
3
+ {%- if message['content'] is string -%}
4
+ {%- set ns.text = message['content'] -%}
5
+ {%- else -%}
6
+ {%- for item in message['content'] -%}
7
+ {%- if 'image' in item or 'image_url' in item or item.type == 'image' -%}
8
+ {%- set ns.has_image = true -%}
9
+ {%- elif 'text' in item -%}
10
+ {%- set ns.text = ns.text + item.text -%}
11
+ {%- endif -%}
12
+ {%- endfor -%}
13
+ {%- endif -%}
14
+ {%- if ns.has_image -%}
15
+ {{- '<|im_start|>user\n<|vision_start|><|image_pad|><|vision_end|>Describe the image.<|im_end|><|endoftext|>' -}}
16
+ {%- else -%}
17
+ {{- ns.text + '<|endoftext|>' * 10 -}}
18
+ {%- endif -%}
19
+ {%- endfor -%}
config_sentence_transformers.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "__version__": {
3
+ "sentence_transformers": "6.0.0"
4
+ },
5
+ "model_type": "MultiVectorEncoder",
6
+ "similarity_fn_name": "maxsim",
7
+ "prompts": {},
8
+ "default_prompt_name": null
9
+ }
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.sentence_transformer.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 CHANGED
@@ -25,7 +25,7 @@
25
  },
26
  "temporal_patch_size": 2
27
  },
28
- "processor_class": "ColQwen3_5Processor",
29
  "video_processor": {
30
  "do_convert_rgb": true,
31
  "do_normalize": true,
 
25
  },
26
  "temporal_patch_size": 2
27
  },
28
+ "processor_class": "Qwen3VLProcessor",
29
  "video_processor": {
30
  "do_convert_rgb": true,
31
  "do_normalize": true,
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
+ "config_kwargs": {
21
+ "text_config": {
22
+ "is_causal": false
23
+ }
24
+ },
25
+ "processing_kwargs": {
26
+ "chat_template": {
27
+ "chat_template": "sentence_transformers"
28
+ }
29
+ }
30
+ }
tokenizer_config.json CHANGED
@@ -21,7 +21,8 @@
21
  },
22
  "pad_token": "<|endoftext|>",
23
  "pretokenize_regex": "(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?[\\p{L}\\p{M}]+|\\p{N}| ?[^\\s\\p{L}\\p{M}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+",
24
- "processor_class": "ColQwen3_5Processor",
 
25
  "split_special_tokens": false,
26
  "tokenizer_class": "Qwen2Tokenizer",
27
  "unk_token": null,
 
21
  },
22
  "pad_token": "<|endoftext|>",
23
  "pretokenize_regex": "(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?[\\p{L}\\p{M}]+|\\p{N}| ?[^\\s\\p{L}\\p{M}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+",
24
+ "processor_class": "Qwen3VLProcessor",
25
+ "padding_side": "left",
26
  "split_special_tokens": false,
27
  "tokenizer_class": "Qwen2Tokenizer",
28
  "unk_token": null,