mlboydaisuke commited on
Commit
deb1271
·
verified ·
1 Parent(s): 4cde495

Mirror of mlboydaisuke/ColModernVBERT-CoreAI

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,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ > **Mirror** of [`mlboydaisuke/ColModernVBERT-CoreAI`](https://huggingface.co/mlboydaisuke/ColModernVBERT-CoreAI) — the canonical repo ([CoreAI Model Zoo](https://github.com/john-rocky/coreai-model-zoo)). Updates land there first.
18
+
19
+
20
+ # ColModernVBERT — Core AI
21
+
22
+ **The zoo's first visual document retriever and first late-interaction (ColBERT / MaxSim)
23
+ multi-vector model**, running as static `.aimodel` graphs on Apple Silicon (Mac GPU / iPhone).
24
+ A Core AI port of [`ModernVBERT/colmodernvbert`](https://huggingface.co/ModernVBERT/colmodernvbert)
25
+ (MIT) — a compact 250M visual document retriever: a **ModernBERT-150M bidirectional text
26
+ encoder** + **SigLIP2 vision encoder** (pixel-shuffle ×4) with a `custom_text_proj` head that
27
+ emits a **per-token L2-normalized 128-d multi-vector**. Retrieval is **late interaction**: you
28
+ encode a text query and a page *image* into token-level vectors and score them with **MaxSim**
29
+ (`score = Σ_q max_d ⟨E_q, E_d⟩`). No OCR — the page is matched as a picture, so tables, charts
30
+ and complex layouts are first-class.
31
+
32
+ This completes the on-device RAG trifecta alongside the text
33
+ [Qwen3-Embedding](https://huggingface.co/mlboydaisuke/Qwen3-Embedding-0.6B-CoreAI) (text→text
34
+ dense) and [Qwen3-Reranker](https://huggingface.co/mlboydaisuke/Qwen3-Reranker-0.6B-CoreAI)
35
+ (cross-encoder): **embed → rerank → visual-retrieval**, all on device.
36
+
37
+ <!-- gen-cards:use-it begin id=colmodernvbert (managed by scripts/gen-cards — edit cards.json / QuickStart.swift, not this block) -->
38
+ ## Use it
39
+
40
+ ▶️ **Run it (source)** — the [DocSearch runner](https://github.com/john-rocky/coreai-kit/tree/main/Examples/DocSearch)
41
+ (visual page search over bundled sample pages; the GUI (iPhone) adds tiled where-it-matched highlights):
42
+
43
+ ```bash
44
+ git clone https://github.com/john-rocky/coreai-kit
45
+ open coreai-kit/Examples/DocSearch/DocSearch.xcodeproj
46
+ # → Run, then pick "ColModernVBERT" in the model picker
47
+
48
+ # agents / headless (macOS):
49
+ cd coreai-kit/Examples/DocSearch
50
+ swift run docsearch-cli --model colmodernvbert --query "monthly revenue trend"
51
+ ```
52
+
53
+ 💻 **Build with it** — complete; the glue is kit API, copy-paste runs:
54
+
55
+ ```swift
56
+ import CoreAIKitEmbeddings
57
+
58
+ let retriever = try await VisualDocumentRetriever(
59
+ catalog: "colmodernvbert")
60
+ var corpus: [VisualDocumentRetriever.PageEmbedding] = []
61
+ for url in pages {
62
+ corpus.append(try await retriever.encode(page: ImageFile.load(url).cgImage))
63
+ }
64
+ let hits = try await retriever.retrieve(query: query, over: corpus, topK: pages.count)
65
+ // hits: pages ranked by MaxSim, best match first — no OCR, pages are matched as pictures
66
+ ```
67
+
68
+ The take-home is [`Examples/DocSearch/Sources/QuickStart.swift`](https://github.com/john-rocky/coreai-kit/blob/main/Examples/DocSearch/Sources/QuickStart.swift)
69
+ — this exact code as one typed function, no UI; the CLI is an argument shell over it, and
70
+ the GUI drives the same `VisualDocumentRetriever(catalog:)` with tiled per-page encoding.
71
+ Encode your corpus once and keep the `PageEmbedding`s — scoring a query is then host-side
72
+ MaxSim, no model call per page. `encodeTiled(page:)` localizes *where* a query matched.
73
+
74
+ **Integration checklist**
75
+
76
+ - SPM: `https://github.com/john-rocky/coreai-kit` → product **CoreAIKitEmbeddings**
77
+ - Info.plist: `NSPhotoLibraryUsageDescription` — only if you use PhotosPicker to import pages
78
+ - Entitlements: none needed
79
+ - First run downloads the model — 0.7 GB (Mac) / 0.7 GB (iPhone) — then it loads from the
80
+ local cache (Application Support; progress via the `downloadProgress` callback)
81
+ - Measure in Release — Debug is ~3× slower on per-token host work
82
+ <!-- gen-cards:use-it end -->
83
+
84
+ ## Two encoders (two graphs)
85
+
86
+ | graph | input | output | fp16 size |
87
+ |---|---|---|---|
88
+ | **query** | `input_ids [1,32] i32`, `attention_mask [1,32] i32` | `query_embeddings [1,32,128]` | 298 MB |
89
+ | **doc** | `pixel_values [1,1,3,512,512]`, `pixel_attention_mask [1,1,512,512] i32` | `doc_embeddings [1,89,128]` | 407 MB |
90
+
91
+ Both are single bidirectional forwards — no KV cache, no generation. The per-token L2-norm and
92
+ the `attention_mask` masking are baked in-graph; **MaxSim runs on the host** (a tiny matmul +
93
+ max + sum). Each bundle directory holds one `*.aimodel` plus a `tokenizer/` folder.
94
+
95
+ - **query**: right-pad the tokenized query to the 32-token grid (queries are short; ModernBERT's
96
+ sliding-window(128) sees the full sequence → full attention). Slice to the real token count
97
+ before MaxSim.
98
+ - **doc**: a **single 512×512 tile** ("global image") layout — the text template (CLS + image
99
+ markers + 64 `<image>` placeholders + SEP) is baked as a graph constant, so the only runtime
100
+ inputs are the pixels. Preprocess the page like Idefics3: resize so the longest edge ≤ 512,
101
+ pad to 512×512, rescale ×1/255, normalize with mean/std = 0.5, and build the
102
+ `pixel_attention_mask` (1 for real pixels, 0 for padding).
103
+
104
+ > **Single-tile v1.** This release ships the single 512px global-image document path: lightweight,
105
+ > iPhone-friendly, and accurate on typical pages. The model's full high-resolution mode (split a
106
+ > page into multiple 512px tiles + the global image, 800+ doc tokens) is a planned follow-up for
107
+ > dense small-print documents.
108
+
109
+ ## Repo layout
110
+
111
+ ```
112
+ query/ colmodernvbert-query_float16_s32_static.aimodel + tokenizer/ (298 MB, fp16 — iPhone)
113
+ doc/ colmodernvbert-doc_float16_s89_static.aimodel (407 MB, fp16 — iPhone)
114
+ fp32/query/ colmodernvbert-query_float32_s32_static.aimodel + tokenizer/ (595 MB — Mac)
115
+ fp32/doc/ colmodernvbert-doc_float32_s89_static.aimodel (813 MB — Mac)
116
+ README.md · reference_query.json · reference_doc.json · test_doc.png
117
+ ```
118
+
119
+ Each `query/` and `doc/` directory is a complete bundle root (one `.aimodel`, plus `tokenizer/`
120
+ on the query side). fp16 ships for iPhone (~705 MB for both encoders); fp32 is for Mac / max
121
+ precision.
122
+
123
+ ## On-device (CoreAIKit)
124
+
125
+ ```swift
126
+ import CoreAIKitEmbeddings
127
+
128
+ // Downloads query/ + doc/ (fp16) from this repo, or uses a sideloaded copy if present.
129
+ let retriever = try await VisualDocumentRetriever() // .colModernVBERTQuery / .colModernVBERTDoc
130
+
131
+ // Encode a page as tiles (reliable spatial grounding), rank queries, and locate the match.
132
+ let page = try await retriever.encodeTiled(page: cgImage, rows: 6, cols: 4)
133
+ let q = try await retriever.encode(query: "total revenue in the third quarter")
134
+ let score = retriever.score(query: q, tiledPage: page) // MaxSim, page ranking
135
+ let rect = retriever.bestTile(query: q, tiledPage: page) // normalized region to highlight
136
+ ```
137
+
138
+ See [`Examples/DocSearch`](https://github.com/john-rocky/coreai-kit/tree/main/Examples/DocSearch)
139
+ for a full iPhone demo (bundled + imported documents, query → ranked pages → highlighted region).
140
+
141
+ ## Parity (Core AI engine vs. PyTorch reference, M4 Max GPU)
142
+
143
+ Per-token cosine of the 128-d multi-vectors against the `colpali_engine` PyTorch model:
144
+
145
+ | encoder | float32 | float16 |
146
+ |---|---|---|
147
+ | query | min/mean **1.000000** | min 0.999997 / mean 0.999999 |
148
+ | doc | min/mean **1.000000** | min 0.999994 / mean 0.999998 |
149
+
150
+ End-to-end retrieval: the host **MaxSim reproduces `processor.score` exactly** (max |Δ| = 0.0000),
151
+ the engine ranking matches the PyTorch ranking on every clear-margin query, and the single-tile
152
+ engine retrieves the intended page **3/3** on a rendered-text corpus.
153
+
154
+ ## License
155
+
156
+ MIT, inherited from [`ModernVBERT/colmodernvbert`](https://huggingface.co/ModernVBERT/colmodernvbert).
157
+ See the upstream model and paper *ModernVBERT: Towards Smaller Visual Document Retrievers*
158
+ ([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