mlboydaisuke commited on
Commit
2175916
·
verified ·
1 Parent(s): 8a18bfa

ColModernVBERT -> Core AI: query + doc encoders (fp16/fp32), visual document retrieval (late-interaction / MaxSim)

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ doc/colmodernvbert-doc_float16_s89_static.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
37
+ fp32/doc/colmodernvbert-doc_float32_s89_static.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
38
+ fp32/query/colmodernvbert-query_float32_s32_static.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
39
+ query/colmodernvbert-query_float16_s32_static.aimodel/main.mlirb filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ library_name: coreai
4
+ pipeline_tag: visual-document-retrieval
5
+ tags:
6
+ - core-ai
7
+ - apple
8
+ - on-device
9
+ - visual-document-retrieval
10
+ - late-interaction
11
+ - colbert
12
+ - colpali
13
+ - retrieval
14
+ base_model: ModernVBERT/colmodernvbert
15
+ ---
16
+
17
+ # ColModernVBERT — Core AI
18
+
19
+ **The zoo's first visual document retriever and first late-interaction (ColBERT / MaxSim)
20
+ multi-vector model**, running as static `.aimodel` graphs on Apple Silicon (Mac GPU / iPhone).
21
+ A Core AI port of [`ModernVBERT/colmodernvbert`](https://huggingface.co/ModernVBERT/colmodernvbert)
22
+ (MIT) — a compact 250M visual document retriever: a **ModernBERT-150M bidirectional text
23
+ encoder** + **SigLIP2 vision encoder** (pixel-shuffle ×4) with a `custom_text_proj` head that
24
+ emits a **per-token L2-normalized 128-d multi-vector**. Retrieval is **late interaction**: you
25
+ encode a text query and a page *image* into token-level vectors and score them with **MaxSim**
26
+ (`score = Σ_q max_d ⟨E_q, E_d⟩`). No OCR — the page is matched as a picture, so tables, charts
27
+ and complex layouts are first-class.
28
+
29
+ This completes the on-device RAG trifecta alongside the text
30
+ [Qwen3-Embedding](https://huggingface.co/mlboydaisuke/Qwen3-Embedding-0.6B-CoreAI) (text→text
31
+ dense) and [Qwen3-Reranker](https://huggingface.co/mlboydaisuke/Qwen3-Reranker-0.6B-CoreAI)
32
+ (cross-encoder): **embed → rerank → visual-retrieval**, all on device.
33
+
34
+ ## Two encoders (two graphs)
35
+
36
+ | graph | input | output | fp16 size |
37
+ |---|---|---|---|
38
+ | **query** | `input_ids [1,32] i32`, `attention_mask [1,32] i32` | `query_embeddings [1,32,128]` | 298 MB |
39
+ | **doc** | `pixel_values [1,1,3,512,512]`, `pixel_attention_mask [1,1,512,512] i32` | `doc_embeddings [1,89,128]` | 407 MB |
40
+
41
+ Both are single bidirectional forwards — no KV cache, no generation. The per-token L2-norm and
42
+ the `attention_mask` masking are baked in-graph; **MaxSim runs on the host** (a tiny matmul +
43
+ max + sum). Each bundle directory holds one `*.aimodel` plus a `tokenizer/` folder.
44
+
45
+ - **query**: right-pad the tokenized query to the 32-token grid (queries are short; ModernBERT's
46
+ sliding-window(128) sees the full sequence → full attention). Slice to the real token count
47
+ before MaxSim.
48
+ - **doc**: a **single 512×512 tile** ("global image") layout — the text template (CLS + image
49
+ markers + 64 `<image>` placeholders + SEP) is baked as a graph constant, so the only runtime
50
+ inputs are the pixels. Preprocess the page like Idefics3: resize so the longest edge ≤ 512,
51
+ pad to 512×512, rescale ×1/255, normalize with mean/std = 0.5, and build the
52
+ `pixel_attention_mask` (1 for real pixels, 0 for padding).
53
+
54
+ > **Single-tile v1.** This release ships the single 512px global-image document path: lightweight,
55
+ > iPhone-friendly, and accurate on typical pages. The model's full high-resolution mode (split a
56
+ > page into multiple 512px tiles + the global image, 800+ doc tokens) is a planned follow-up for
57
+ > dense small-print documents.
58
+
59
+ ## Repo layout
60
+
61
+ ```
62
+ query/ colmodernvbert-query_float16_s32_static.aimodel + tokenizer/ (298 MB, fp16 — iPhone)
63
+ doc/ colmodernvbert-doc_float16_s89_static.aimodel (407 MB, fp16 — iPhone)
64
+ fp32/query/ colmodernvbert-query_float32_s32_static.aimodel + tokenizer/ (595 MB — Mac)
65
+ fp32/doc/ colmodernvbert-doc_float32_s89_static.aimodel (813 MB — Mac)
66
+ README.md · reference_query.json · reference_doc.json · test_doc.png
67
+ ```
68
+
69
+ Each `query/` and `doc/` directory is a complete bundle root (one `.aimodel`, plus `tokenizer/`
70
+ on the query side). fp16 ships for iPhone (~705 MB for both encoders); fp32 is for Mac / max
71
+ precision.
72
+
73
+ ## On-device (CoreAIKit)
74
+
75
+ ```swift
76
+ import CoreAIKitEmbeddings
77
+
78
+ // Downloads query/ + doc/ (fp16) from this repo, or uses a sideloaded copy if present.
79
+ let retriever = try await VisualDocumentRetriever() // .colModernVBERTQuery / .colModernVBERTDoc
80
+
81
+ // Encode a page as tiles (reliable spatial grounding), rank queries, and locate the match.
82
+ let page = try await retriever.encodeTiled(page: cgImage, rows: 6, cols: 4)
83
+ let q = try await retriever.encode(query: "total revenue in the third quarter")
84
+ let score = retriever.score(query: q, tiledPage: page) // MaxSim, page ranking
85
+ let rect = retriever.bestTile(query: q, tiledPage: page) // normalized region to highlight
86
+ ```
87
+
88
+ See [`Examples/DocSearch`](https://github.com/john-rocky/coreai-kit/tree/main/Examples/DocSearch)
89
+ for a full iPhone demo (bundled + imported documents, query → ranked pages → highlighted region).
90
+
91
+ ## Parity (Core AI engine vs. PyTorch reference, M4 Max GPU)
92
+
93
+ Per-token cosine of the 128-d multi-vectors against the `colpali_engine` PyTorch model:
94
+
95
+ | encoder | float32 | float16 |
96
+ |---|---|---|
97
+ | query | min/mean **1.000000** | min 0.999997 / mean 0.999999 |
98
+ | doc | min/mean **1.000000** | min 0.999994 / mean 0.999998 |
99
+
100
+ End-to-end retrieval: the host **MaxSim reproduces `processor.score` exactly** (max |Δ| = 0.0000),
101
+ the engine ranking matches the PyTorch ranking on every clear-margin query, and the single-tile
102
+ engine retrieves the intended page **3/3** on a rendered-text corpus.
103
+
104
+ ## License
105
+
106
+ MIT, inherited from [`ModernVBERT/colmodernvbert`](https://huggingface.co/ModernVBERT/colmodernvbert).
107
+ See the upstream model and paper *ModernVBERT: Towards Smaller Visual Document Retrievers*
108
+ ([arXiv:2510.01149](https://arxiv.org/abs/2510.01149)).
doc/colmodernvbert-doc_float16_s89_static.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ ZE��?��5�PT!�DIv�k�+��3��wK
doc/colmodernvbert-doc_float16_s89_static.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5a45f482e93fcee4bd3595501d5421f7444976916bb92beea6d033c1ed19774b
3
+ size 426703966
doc/colmodernvbert-doc_float16_s89_static.aimodel/metadata.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "description" : "ColModernVBERT visual document retriever (document\/image encoder, single 512px tile): SigLIP2 vision + pixel-shuffle x4 -> ModernBERT-150M -> custom_text_proj(768->128) -> per-token L2-normalized 128-d multi-vector for ColBERT-style late-interaction (MaxSim). https:\/\/huggingface.co\/ModernVBERT\/colmodernvbert",
3
+ "creationDate" : "20260624T025647Z",
4
+ "license" : "MIT",
5
+ "assetVersion" : "2.0",
6
+ "author" : "ModernVBERT (Illuin Technology \/ ETH)"
7
+ }
fp32/doc/colmodernvbert-doc_float32_s89_static.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ sYL�vJ�^��c��H\|�g��<;?�l
fp32/doc/colmodernvbert-doc_float32_s89_static.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7359114cfd76184a835ea911b163adee98485c7ca667bfaa3c120f3b3fbc1e6c
3
+ size 852898790
fp32/doc/colmodernvbert-doc_float32_s89_static.aimodel/metadata.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "description" : "ColModernVBERT visual document retriever (document\/image encoder, single 512px tile): SigLIP2 vision + pixel-shuffle x4 -> ModernBERT-150M -> custom_text_proj(768->128) -> per-token L2-normalized 128-d multi-vector for ColBERT-style late-interaction (MaxSim). https:\/\/huggingface.co\/ModernVBERT\/colmodernvbert",
3
+ "license" : "MIT",
4
+ "assetVersion" : "2.0",
5
+ "author" : "ModernVBERT (Illuin Technology \/ ETH)",
6
+ "creationDate" : "20260624T025601Z"
7
+ }
fp32/query/colmodernvbert-query_float32_s32_static.aimodel/main.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ V�z��BL%�/9B�,0�J���Ľme� �Y�
fp32/query/colmodernvbert-query_float32_s32_static.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1156c67a95a0424c25972f143942ba2c309d4ac1be9f1cc4bd6d65e40cdf59c8
3
+ size 624058345
fp32/query/colmodernvbert-query_float32_s32_static.aimodel/metadata.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "assetVersion" : "2.0",
3
+ "license" : "MIT",
4
+ "author" : "ModernVBERT (Illuin Technology \/ ETH)",
5
+ "description" : "ColModernVBERT visual document retriever (query\/text encoder): ModernBERT-150M bidirectional backbone -> custom_text_proj Linear(768->128) -> per-token L2-normalized 128-d multi-vector for ColBERT-style late-interaction (MaxSim) retrieval. Source: https:\/\/huggingface.co\/ModernVBERT\/colmodernvbert",
6
+ "creationDate" : "20260624T024133Z"
7
+ }
fp32/query/tokenizer/chat_template.jinja ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ <|begin_of_text|>{% for message in messages %}{{message['role'] | capitalize}}{% if message['content'][0]['type'] == 'image' %}{{':'}}{% else %}{{': '}}{% endif %}{% for line in message['content'] %}{% if line['type'] == 'text' %}{{line['text']}}{% elif line['type'] == 'image' %}{{ '<image>' }}{% endif %}{% endfor %}<end_of_utterance>
2
+ {% endfor %}{% if add_generation_prompt %}{{ 'Assistant:' }}{% endif %}
fp32/query/tokenizer/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
fp32/query/tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": true,
4
+ "cls_token": "[CLS]",
5
+ "extra_special_tokens": [
6
+ "<fake_token_around_image>",
7
+ "<image>",
8
+ "<end_of_utterance>"
9
+ ],
10
+ "is_local": false,
11
+ "legacy": false,
12
+ "local_files_only": false,
13
+ "mask_token": "[MASK]",
14
+ "max_length": 8192,
15
+ "model_input_names": [
16
+ "input_ids",
17
+ "attention_mask",
18
+ "pixel_values",
19
+ "pixel_attention_mask"
20
+ ],
21
+ "model_max_length": 8192,
22
+ "pad_to_multiple_of": null,
23
+ "pad_token": "[PAD]",
24
+ "pad_token_type_id": 0,
25
+ "padding_side": "left",
26
+ "processor_class": "ColModernVBertProcessor",
27
+ "sep_token": "[SEP]",
28
+ "stride": 0,
29
+ "tokenizer_class": "TokenizersBackend",
30
+ "truncation_side": "right",
31
+ "truncation_strategy": "longest_first",
32
+ "unk_token": "[UNK]"
33
+ }
query/colmodernvbert-query_float16_s32_static.aimodel/main.hash ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ I
2
+ 9���kc�_��}��6�b�&����e�t�n�
query/colmodernvbert-query_float16_s32_static.aimodel/main.mlirb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:490a399f909e6b6306cc5fc8d87ddecf3618c462c226b191a2a1659f74fc6e98
3
+ size 312212955
query/colmodernvbert-query_float16_s32_static.aimodel/metadata.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "assetVersion" : "2.0",
3
+ "creationDate" : "20260624T024253Z",
4
+ "license" : "MIT",
5
+ "author" : "ModernVBERT (Illuin Technology \/ ETH)",
6
+ "description" : "ColModernVBERT visual document retriever (query\/text encoder): ModernBERT-150M bidirectional backbone -> custom_text_proj Linear(768->128) -> per-token L2-normalized 128-d multi-vector for ColBERT-style late-interaction (MaxSim) retrieval. Source: https:\/\/huggingface.co\/ModernVBERT\/colmodernvbert"
7
+ }
query/tokenizer/chat_template.jinja ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ <|begin_of_text|>{% for message in messages %}{{message['role'] | capitalize}}{% if message['content'][0]['type'] == 'image' %}{{':'}}{% else %}{{': '}}{% endif %}{% for line in message['content'] %}{% if line['type'] == 'text' %}{{line['text']}}{% elif line['type'] == 'image' %}{{ '<image>' }}{% endif %}{% endfor %}<end_of_utterance>
2
+ {% endfor %}{% if add_generation_prompt %}{{ 'Assistant:' }}{% endif %}
query/tokenizer/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
query/tokenizer/tokenizer_config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "clean_up_tokenization_spaces": true,
4
+ "cls_token": "[CLS]",
5
+ "extra_special_tokens": [
6
+ "<fake_token_around_image>",
7
+ "<image>",
8
+ "<end_of_utterance>"
9
+ ],
10
+ "is_local": false,
11
+ "legacy": false,
12
+ "local_files_only": false,
13
+ "mask_token": "[MASK]",
14
+ "max_length": 8192,
15
+ "model_input_names": [
16
+ "input_ids",
17
+ "attention_mask",
18
+ "pixel_values",
19
+ "pixel_attention_mask"
20
+ ],
21
+ "model_max_length": 8192,
22
+ "pad_to_multiple_of": null,
23
+ "pad_token": "[PAD]",
24
+ "pad_token_type_id": 0,
25
+ "padding_side": "left",
26
+ "processor_class": "ColModernVBertProcessor",
27
+ "sep_token": "[SEP]",
28
+ "stride": 0,
29
+ "tokenizer_class": "TokenizersBackend",
30
+ "truncation_side": "right",
31
+ "truncation_strategy": "longest_first",
32
+ "unk_token": "[UNK]"
33
+ }
reference_doc.json ADDED
The diff for this file is too large to render. See raw diff
 
reference_query.json ADDED
The diff for this file is too large to render. See raw diff
 
test_doc.png ADDED