beaupi commited on
Commit
30c6883
·
verified ·
1 Parent(s): 06a740d

Upload granite-vision-4.1-4b-oQ8 via oMLX

Browse files
README.md ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ license: apache-2.0
5
+ pipeline_tag: image-text-to-text
6
+ library_name: transformers
7
+ ---
8
+
9
+ # Granite-Vision-4.1-4B
10
+
11
+ **Model Summary:**
12
+ Granite Vision 4.1 4B is a vision-language model (VLM) that delivers frontier-level
13
+ performance on structured document extraction tasks — chart extraction, table extraction,
14
+ and semantic key-value pair extraction — in a compact 4B parameter footprint, providing
15
+ a lightweight alternative to much larger frontier models for these tasks:
16
+
17
+ - **Chart extraction:** Converting charts into structured, machine-readable formats (Chart2CSV, Chart2Summary, and Chart2Code)
18
+ - **Table extraction:** Accurately extracting tables with complex layouts from document images to JSON, HTML, or OTSL
19
+ - **Semantic Key-Value Pair (KVP) extraction:** Extracting values based on key names and descriptions across diverse document layouts
20
+
21
+ The model is finetuned on top of [Granite-4.1-3B](https://huggingface.co/ibm-granite/granite-4.1-3b), with a 3.4B LLM and 0.6B Vision Encoder and Projectors. See
22
+ [Model Architecture](#model-architecture) for details.
23
+
24
+ The methodology and data (ChartNet) used for this model are described in the paper [ChartNet: A Million-Scale, High-Quality Multimodal Dataset for Robust Chart Understanding](https://huggingface.co/papers/2603.27064).
25
+
26
+ While our focus is on specialized document extraction tasks, the current model preserves and extends the
27
+ capabilities of Granite Vision 4.0 3B, ensuring that existing users can adopt it seamlessly with no changes to their workflow.
28
+ It continues to support vision‑language tasks such as producing detailed natural‑language descriptions from images (image‑to‑text).
29
+ The model can be used standalone and integrates seamlessly
30
+ with [Docling](https://github.com/docling-project/docling) to enhance document processing pipelines
31
+ with deep visual understanding capabilities.
32
+
33
+ - **Developer:** IBM Research
34
+ - **GitHub Repository:** https://github.com/ibm-granite
35
+ - **Release Date:** April 29th, 2026
36
+ - **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0)
37
+
38
+ ## Supported Tasks
39
+
40
+ The model supports specialized extraction tasks, each activated by a simple task tag in
41
+ the user message. The chat template automatically expands tags into the full prompt — no
42
+ need to write verbose instructions.
43
+
44
+ | Tag | Task | Output |
45
+ |-----|------|--------|
46
+ | `<chart2csv>` | Chart to CSV | CSV table with headers and numeric values |
47
+ | `<chart2code>` | Chart to Python code | Python code that recreates the chart |
48
+ | `<chart2summary>` | Chart to summary | Natural-language description of the chart |
49
+ | `<tables_json>` | Table extraction (JSON) | Structured JSON with dimensions and cells |
50
+ | `<tables_html>` | Table extraction (HTML) | HTML `<table>` markup |
51
+ | `<tables_otsl>` | Table extraction (OTSL) | OTSL markup with cell/merge tags |
52
+ | KVP (see prompt instructions below) | Schema based Key-Value pairs extraction | JSON with nested dictionaries and arrays |
53
+
54
+
55
+ ## Model Performance
56
+
57
+ ### Benchmark Results
58
+
59
+ Granite Vision 4.1 4B provides a lightweight alternative to frontier models on structured document extraction
60
+ benchmarks, delivering comparable performance at a fraction of the parameter count.
61
+
62
+ <img src="bench_all_benchmarks.png" width="80%">
63
+
64
+ #### Chart Extraction
65
+
66
+ We evaluate chart extraction using the human-verified test-set from [ChartNet](https://huggingface.co/datasets/ibm-granite/ChartNet).
67
+ Models are scored by LLM-as-a-judge (GPT4o) comparing predictions against ground truth.
68
+ We report average scores (0–100) on Chart2CSV and Chart2Summary tasks.
69
+
70
+ <div style="display: flex; gap: 10px;">
71
+ <img src="bench_c2c.png" width="49%">
72
+ <img src="bench_c2s.png" width="49%">
73
+ </div>
74
+
75
+ #### Table Extraction
76
+
77
+ To benchmark table extraction, we construct a unified evaluation suite spanning multiple datasets and settings to assess end-to-end table extraction capabilities of vision-language models:
78
+
79
+ 1. **[TableVQA-Extract](https://github.com/naver-ai/tablevqabench)** — Converts the original visual table QA benchmark into a cropped table extraction task.
80
+ 2. **[OmniDocBench-tables](https://github.com/opendatalab/OmniDocBench)** — A document parsing benchmark over diverse PDF types with detailed annotations for layout, text, formulas, and tables. We use the subset of pages that contain one or more tables to evaluate table extraction in full-page settings.
81
+ 3. **[PubTablesV2](https://huggingface.co/datasets/kensho/PubTables-v2)** — A large-scale table extraction benchmark evaluated in both cropped-table and full-page document settings.
82
+
83
+ To unify evaluation, we replace each dataset’s original annotations (e.g., Q&A pairs) with a single instruction: *extract the table(s) from the image in HTML format*, using the corresponding HTML as ground truth. For full-page inputs, only tabular elements are considered; when multiple tables appear, they are aggregated into a Python list.
84
+
85
+ We report results using **TEDS** ([Tree-Edit Distance-based Similarity](https://arxiv.org/abs/2208.00385)), which measures structural and content similarity between predicted and ground-truth HTML tables.
86
+
87
+ Results are presented separately for cropped-table and full-page settings to highlight performance across controlled and realistic document scenarios.
88
+
89
+ <div style="display: flex; gap: 10px;">
90
+ <img src="bench_tvqa.png" width="49%">
91
+ <img src="bench_omni.png" width="49%">
92
+ </div>
93
+ <div style="display: flex; gap: 10px;">
94
+ <img src="bench_pubcrop.png" width="49%">
95
+ <img src="bench_pubfull.png" width="49%">
96
+ </div>
97
+
98
+ #### Key-Value Pair (KVP) Extraction
99
+
100
+ We evaluate on [VAREX](https://udibarzi.github.io/varex-bench/), a benchmark for
101
+ multimodal structured extraction from documents. Granite Vision 4.1 4B achieves
102
+ 94.4% exact-match accuracy (zero-shot), competitive with much larger frontier models
103
+ (view results [here](https://udibarzi.github.io/varex-bench/#leaderboard)).
104
+
105
+ <div style="display: flex; gap: 10px;">
106
+ <img src="bench_varex.png" width="60%">
107
+ </div>
108
+
109
+ ### Setup
110
+
111
+ Tested with python=3.11
112
+ ```shell
113
+ pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu128
114
+ pip install transformers>=5.6.2 peft>=0.19.1 tokenizers>=0.22.2 pillow>=12.2.0
115
+ ```
116
+
117
+ ## Usage with Transformers
118
+
119
+
120
+ ```python
121
+ import re
122
+ from io import StringIO
123
+
124
+ import pandas as pd
125
+ import torch
126
+ from transformers import AutoProcessor, AutoModelForImageTextToText
127
+ from PIL import Image
128
+ from huggingface_hub import hf_hub_download
129
+
130
+ model_id = "ibm-granite/granite-vision-4.1-4b"
131
+ device = "cuda" if torch.cuda.is_available() else "cpu"
132
+
133
+ processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
134
+ model = AutoModelForImageTextToText.from_pretrained(
135
+ model_id,
136
+ trust_remote_code=True,
137
+ dtype=torch.bfloat16,
138
+ device_map=device
139
+ ).eval()
140
+
141
+
142
+ def run_inference(model, processor, images, prompts):
143
+ """Run batched inference on image+prompt pairs (one image per prompt)."""
144
+ conversations = [
145
+ [{"role": "user", "content": [
146
+ {"type": "image"},
147
+ {"type": "text", "text": prompt},
148
+ ]}]
149
+ for prompt in prompts
150
+ ]
151
+ texts = [
152
+ processor.apply_chat_template(conv, tokenize=False, add_generation_prompt=True)
153
+ for conv in conversations
154
+ ]
155
+ inputs = processor(
156
+ text=texts, images=images, return_tensors="pt", padding=True, do_pad=True
157
+ ).to(model.device)
158
+ outputs = model.generate(
159
+ **inputs,
160
+ max_new_tokens=4096,
161
+ use_cache=True
162
+ )
163
+ results = []
164
+ for i in range(len(prompts)):
165
+ gen = outputs[i, inputs["input_ids"].shape[1]:]
166
+ results.append(processor.decode(gen, skip_special_tokens=True))
167
+ return results
168
+
169
+
170
+ def display_table(text):
171
+ """Pretty-print CSV (possibly wrapped in ```csv```) or HTML table content via pandas."""
172
+ m = re.search(r"```csv\s*
173
+ (.*?)```", text, re.DOTALL)
174
+ if m:
175
+ df = pd.read_csv(StringIO(m.group(1)))
176
+ print(df.to_string(index=False))
177
+ elif "<table" in text.lower():
178
+ df = pd.read_html(StringIO(text))[0]
179
+ print(df.to_string(index=False))
180
+ else:
181
+ print(text)
182
+ ```
183
+
184
+ ### Chart and Table Tasks
185
+
186
+ You can pass tags and the chat template handles the rest:
187
+
188
+ ```python
189
+ chart_path = hf_hub_download(repo_id=model_id, filename="chart.jpg")
190
+ table_path = hf_hub_download(repo_id=model_id, filename="table.png")
191
+ chart_img = Image.open(chart_path).convert("RGB")
192
+ table_img = Image.open(table_path).convert("RGB")
193
+
194
+ # Batched chart tasks
195
+ chart_prompts = ["<chart2csv>", "<chart2summary>", "<chart2code>"]
196
+ chart_results = run_inference(model, processor, [chart_img] * len(chart_prompts), chart_prompts)
197
+ for prompt, result in zip(chart_prompts, chart_results):
198
+ print(f"{prompt}:")
199
+ display_table(result)
200
+ print()
201
+
202
+ # Batched table tasks
203
+ table_prompts = ["<tables_html>", "<tables_otsl>"]
204
+ table_results = run_inference(model, processor, [table_img] * len(table_prompts), table_prompts)
205
+ for prompt, result in zip(table_prompts, table_results):
206
+ print(f"{prompt}:")
207
+ display_table(result)
208
+ print()
209
+ ```
210
+
211
+ ### Key-Value Pair Extraction (KVP)
212
+
213
+ For KVP extraction use the [VAREX](https://github.com/udibarzi/varex-bench) prompt format. Provide a JSON Schema describing the fields to extract and the model will return a JSON object with the extracted values.
214
+
215
+ ```python
216
+ import json
217
+
218
+ invoice_path = hf_hub_download(repo_id=model_id, filename="invoice.png")
219
+ invoice_img = Image.open(invoice_path).convert("RGB")
220
+ schema = {
221
+ "type": "object",
222
+ "properties": {
223
+ "invoice_date": {"type": "string", "description": "The date the invoice was issued"},
224
+ "order_number": {"type": "string", "description": "The unique identifier for the order"},
225
+ "seller_tax_id": {"type": "string", "description": "The tax identification number of the seller"},
226
+ }
227
+ }
228
+
229
+ prompt = f"""Extract structured data from this document.
230
+ Return a JSON object matching this schema:
231
+
232
+ {json.dumps(schema, indent=2)}
233
+
234
+ Return null for fields you cannot find.
235
+ Return ONLY valid JSON.
236
+ Return an instance of the JSON with extracted values, not the schema itself."""
237
+
238
+ result = run_inference(model, processor, [invoice_img], [prompt])[0]
239
+ print(result)
240
+ ```
241
+
242
+
243
+
244
+ ## Usage with vLLM
245
+
246
+ Granite Vision 4.1 is supported natively in vLLM as of commit
247
+ [bde0efd](https://github.com/vllm-project/vllm/commit/bde0efdbb78a57dc10375e8d0686cf862332192c).
248
+ Until an official release ships, install vLLM from source:
249
+
250
+ ```bash
251
+ git clone https://github.com/vllm-project/vllm.git
252
+ cd vllm
253
+ pip install -e ".[cuda]"
254
+ ```
255
+
256
+ ### Serving
257
+
258
+ ```bash
259
+ vllm serve ibm-granite/granite-vision-4.1-4b \
260
+ --host 0.0.0.0 --port 8000
261
+ ```
262
+
263
+ ### Client example
264
+
265
+ Query the running server using the OpenAI-compatible API:
266
+
267
+ ```python
268
+ import base64
269
+ from openai import OpenAI
270
+ from huggingface_hub import hf_hub_download
271
+ from PIL import Image
272
+
273
+ model_id = "ibm-granite/granite-vision-4.1-4b"
274
+ client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
275
+
276
+ def run_inference(client, model_id, image_path, tag):
277
+ with open(image_path, "rb") as f:
278
+ image_b64 = base64.b64encode(f.read()).decode("utf-8")
279
+ messages = [
280
+ {"role": "user", "content": [
281
+ {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_b64}"}},
282
+ {"type": "text", "text": tag},
283
+ ]}
284
+ ]
285
+ response = client.chat.completions.create(
286
+ model=model_id, messages=messages, max_tokens=4096, temperature=0,
287
+ )
288
+ return response.choices[0].message.content
289
+
290
+ chart_path = hf_hub_download(repo_id=model_id, filename="chart.jpg")
291
+ table_path = hf_hub_download(repo_id=model_id, filename="table.png")
292
+
293
+ # Chart tasks
294
+ for tag in ["<chart2csv>", "<chart2summary>", "<chart2code>"]:
295
+ result = run_inference(client, model_id, chart_path, tag)
296
+ print(f"{tag}:
297
+ {result}
298
+ ")
299
+
300
+ # Table tasks
301
+ for tag in ["<tables_json>", "<tables_html>", "<tables_otsl>"]:
302
+ result = run_inference(client, model_id, table_path, tag)
303
+ print(f"{tag}:
304
+ {result}
305
+ ")
306
+ ```
307
+
308
+
309
+ ## Usage with Docling
310
+
311
+ [Docling](https://github.com/docling-project/docling) integrates Granite Vision for document conversion pipelines:
312
+
313
+ - [Table extraction](https://github.com/docling-project/docling/blob/v2.90.0/docs/examples/granite_vision_table_structure.py) — uses Granite Vision to extract the layout and content of detected tables.
314
+ - [Chart data extraction](https://github.com/docling-project/docling/blob/v2.90.0/docs/examples/chart_extraction.py) — uses Granite Vision to extract structured data from bar, pie, and line charts (`pip install docling[granite_vision]`)
315
+
316
+
317
+ ## Training Data
318
+
319
+ The model was fine-tuned on a curated mixture of extraction-focused datasets spanning
320
+ chart understanding, complex table parsing, and document KVP extraction, supplemented
321
+ by the general-purpose [Granite Vision instruction-following dataset](https://arxiv.org/abs/2502.09927) for broad visual understanding.
322
+
323
+ Chart understanding data was created through a novel code‑guided augmentation methodology that produces diverse,
324
+ semantically aligned chart samples containing rendering code, chart images, underlying data CSVs, and natural‑language summaries.
325
+ Using this pipeline, we are also releasing [ChartNet](https://huggingface.co/datasets/ibm-granite/ChartNet), a comprehensive million‑scale multimodal dataset enriched with real‑world,
326
+ human‑annotated, safety, and grounding subsets. The dataset and its methodology are detailed in the paper [ChartNet: A Million-Scale, High-Quality Multimodal Dataset for Robust Chart Understanding](https://huggingface.co/papers/2603.27064).
327
+
328
+ ## Model Architecture
329
+
330
+ 1. **SigLIP2 Vision encoder:** `google/siglip2-so400m-patch16-384`. Input images are tiled into 384×384 patches (with a base downscaled view always included), and each tile is encoded independently. The vision encoder is finetuned with LoRA adapters during training. The chechpoint provides the weights with merged adapters.
331
+ 2. **Window Q-Former projectors:** Visual features are compressed 4× using windowed Q-Former projectors: each 4×4 patch window is reduced to 2×2 tokens via cross-attention, where the queries are initialized from a downsampled version of the window features. This reduces the visual token count fed to the LLM.
332
+ 3. **Feature injection:** A variant of [Deepstack](https://arxiv.org/abs/2406.04334) where visual features are additively injected into the LLM hidden states at multiple layers through two complementary mechanisms:
333
+ - *LayerDeepstack:* Features from 4 vision encoder depths are each projected and injected into a different LLM layer. The Q-Former queries are initialized from downsampled features. The mapping is reversed — the deepest (most semantic) vision features feed the earliest LLM layers, providing strong semantic grounding from the start.
334
+ - *SpatialDeepstack:* The deepest vision features at full resolution are split into 4 complementary spatial groups. Each group's Q-Former queries are initialized from the corresponding spatial subset, and injected at a separate later LLM layer, providing fine-grained spatial detail.
335
+
336
+ In total, **8 vision-to-LLM injection points** distribute visual information across the network for stronger visual grounding.
337
+ 4. **Language model:** Granite-4.1 (3B) with LoRA (rank 256) across all self-attention projections and MLP layers. The chechpoint provides the weights with merged adapters.
338
+
339
+ **Supported input:** English instructions and images (PNG, JPEG).
340
+
341
+
342
+ ## Infrastructure
343
+
344
+ Granite 4.1 Vision was trained on IBM's Blue Vela supercomputing cluster, outfitted with
345
+ NVIDIA H100 GPUs. The training was done on 32 GPUs for approximately 200 hours.
346
+
347
+
348
+ ## Ethical Considerations and Limitations
349
+
350
+ The use of vision-language models involves certain risks that should be considered before
351
+ deployment:
352
+ - **Task scope:** The model is specifically designed for structured extraction tasks and
353
+ may not generalize well to open-ended vision-language tasks.
354
+ - **Hallucination:** As with all generative models, outputs should be validated before
355
+ use in automated pipelines, particularly for high-stakes document processing.
356
+ - **Language:** The model is trained on English instructions only and may produce
357
+ degraded results for documents in other languages.
358
+
359
+ To enhance safety in enterprise deployments, we recommend using Granite 4.1 Vision
360
+ alongside [Granite Guardian](https://huggingface.co/ibm-granite/granite-guardian-4.1-8b),
361
+ a model designed to detect and flag risks in inputs and outputs across key dimensions
362
+ outlined in the IBM AI Risk Atlas.
363
+
364
+
365
+ ## Resources
366
+ - ⭐️ Learn about the latest updates with Granite: https://www.ibm.com/granite
367
+ - 🚀 Get started with tutorials, best practices, and prompt engineering advice: https://www.ibm.com/granite/docs/
368
+ - 💡 Granite learning resources: https://ibm.biz/granite-learning-resources
369
+
370
+
371
+ ## Citation
372
+
373
+ ```bibtex
374
+ @misc{granite-vision-4.1-4b,
375
+ title={Granite 4.1 Vision},
376
+ author={IBM Granite Vision Team},
377
+ year={2026},
378
+ url={https://huggingface.co/ibm-granite/granite-vision-4.1-4b}
379
+ }
380
+
381
+ @article{kondic2026chartnet,
382
+ title={ChartNet: A Million-Scale, High-Quality Multimodal Dataset for Robust Chart Understanding},
383
+ author={Kondic, Jovana and Li, Pengyuan and Joshi, Dhiraj and Sanchez, Isaac and Wiesel, Ben and Abedin, Shafiq and Alfassy, Amit and Schwartz, Eli and Caraballo, Daniel and Cinar, Yagmur Gizem and Scheidegger, Florian and Ross, Steven I. and Weidele, Daniel Karl I. and Hua, Hang and Arutyunova, Ekaterina and Herzig, Roei and He, Zexue and Wang, Zihan and Yu, Xinyue and Zhao, Yunfei and Jiang, Sicong and Liu, Minghao and Lin, Qunshu and Staar, Peter and Lastras, Luis and Oliva, Aude and Feris, Rogerio},
384
+ journal={arXiv preprint arXiv:2603.27064},
385
+ year={2026}
386
+ }
387
+ ```
added_tokens.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "<image>": 100352
3
+ }
chat_template.jinja ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {#- ===== Task tag prompt constants ===== -#}
2
+ {%- set chart2code_prompt = "Generate code that recreates the chart as best as possible." -%}
3
+ {%- set chart2csv_prompt = "Please examine this chart image. Consider you are a data visualization expert, and extract the data into a CSV table.\n\nYour CSV should:\n- Include a header row with clear column names\n- Represent all data series/categories shown in the chart\n- Use numeric values that match the chart as closely as possible\n\nOutput only the CSV data, nothing else." -%}
4
+ {%- set chart2summary_prompt = "Can you describe this chart image?" -%}
5
+ {%- set tables_json_prompt = "Identify and extract the table schema\n Extract the schema of all the tables in the image sorted according to the reading order.\nThe output must be a valid JSON object containing a list of dictionaries with the following structure:\n\n {\n \"dimensions\": {\n \"rows\": <number of data rows (excluding header rows)>,\n \"columns\": <number of columns>,\n \"header_rows\": <number of header rows>,\n \"total_rows\": <total number of rows including headers>\n },\n \"cells\": [\n {\n \"row\": <row index starting at 1>,\n \"col\": <column index starting at 1>,\n \"colspan\": <number of columns spanned>,\n \"rowspan\": <number of rows spanned>,\n \"type\": \"<'header' or 'data'>\",\n \"header_level\": <header nesting level if type=header, else omit or null>,\n \"content\": \"<string content of the cell>\"\n },\n ...\n ]\n }" -%}
6
+ {%- set tables_html_prompt = "Identify and extract the table schema\n Extract the schema of all the tables in the image sorted according to the reading order.\nThe output must be a list of valid HTML tables" -%}
7
+ {%- set tables_otsl_prompt = "Identify and extract the table schema\n Extract the schema of all the tables in the image sorted according to the reading order.\nThe output must be a list of valid OTSL objects, each consists of the following fields: \n <fcel> - a cell with content in it\n <ecel> - an empty cell\n <lcel> - a cell that is merged with the cell to its left\n <ucel> - a cell that is merged with the cell above it\n <xcel> - a cell that is merged with both the cell above it and the cell to its left\n <nl> - a new line\n <ched> - a column header\n <otsl> - the beginning of the OTSL table\n </otsl> - the end of the OTSL table\n\n An example for an output:\n [\n <otsl><ched>first table header1<ched>first table header2<nl><fcel>data1<fcel>data2<nl><fcel>data with horizontal span<lcel><nl><fcel>data with vertical span<ecel><nl><ucel><fcel>data3<nl></otsl>,\n <otsl><ched>second table header1<ched>second table header2<nl><fcel>data1<fcel>data2<nl><fcel>data with horizontal span<lcel><nl><fcel>data with vertical span<ecel><nl><ucel><fcel>data3<nl></otsl>\n ]" -%}
8
+
9
+
10
+ {#- ===== Tag expansion dispatcher ===== -#}
11
+ {%- macro expand_tags(text) -%}
12
+ {%- set has_image = "<image>" in text -%}
13
+ {#- Determine image position: prefix if <image> appears before the tag, suffix if after -#}
14
+ {%- if has_image -%}
15
+ {%- set img_idx = text.index("<image>") -%}
16
+ {%- if "<chart2code>" in text -%}{%- set tag_idx = text.index("<chart2code>") -%}
17
+ {%- elif "<chart2csv>" in text -%}{%- set tag_idx = text.index("<chart2csv>") -%}
18
+ {%- elif "<chart2summary>" in text -%}{%- set tag_idx = text.index("<chart2summary>") -%}
19
+ {%- elif "<tables_json>" in text -%}{%- set tag_idx = text.index("<tables_json>") -%}
20
+ {%- elif "<tables_html>" in text -%}{%- set tag_idx = text.index("<tables_html>") -%}
21
+ {%- elif "<tables_otsl>" in text -%}{%- set tag_idx = text.index("<tables_otsl>") -%}
22
+ {%- else -%}{%- set tag_idx = 999999 -%}
23
+ {%- endif -%}
24
+ {%- set img_prefix = "<image>\n" if img_idx < tag_idx else "" -%}
25
+ {%- set img_suffix = "<image>\n" if img_idx >= tag_idx else "" -%}
26
+ {%- else -%}
27
+ {%- set img_prefix = "" -%}
28
+ {%- set img_suffix = "" -%}
29
+ {%- endif -%}
30
+ {%- if "<chart2code>" in text -%}
31
+ {{- img_prefix + chart2code_prompt + img_suffix -}}
32
+ {%- elif "<chart2csv>" in text -%}
33
+ {{- img_prefix + chart2csv_prompt + img_suffix -}}
34
+ {%- elif "<chart2summary>" in text -%}
35
+ {{- img_prefix + chart2summary_prompt + img_suffix -}}
36
+ {%- elif "<tables_json>" in text -%}
37
+ {{- img_prefix + tables_json_prompt + img_suffix -}}
38
+ {%- elif "<tables_html>" in text -%}
39
+ {{- img_prefix + tables_html_prompt + img_suffix -}}
40
+ {%- elif "<tables_otsl>" in text -%}
41
+ {{- img_prefix + tables_otsl_prompt + img_suffix -}}
42
+ {%- else -%}
43
+ {{- text -}}
44
+ {%- endif -%}
45
+ {%- endmacro -%}
46
+
47
+ {#- ===== Original chat template ===== -#}
48
+ {% macro render_content(x) %}
49
+ {%- if x is string %}
50
+ {{ x }}
51
+ {%- else %}
52
+ {%- for chunk in x %}
53
+ {%- if chunk['type'] == 'text' -%}
54
+ {{ chunk['text']}}
55
+ {%- elif chunk['type'] == 'image' -%}
56
+ {{- "<image>
57
+ " }}
58
+ {%- endif -%}
59
+ {%- endfor -%}
60
+ {%- endif -%}
61
+ {% endmacro %}
62
+
63
+ {%- set tools_system_message_prefix = 'You are a helpful assistant with access to the following tools. You may call one or more tools to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>' %}
64
+ {%- set tools_system_message_suffix = '\n</tools>\n\nFor each tool call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call>. If a tool does not exist in the provided list of tools, notify the user that you do not have the ability to fulfill the request.' %}
65
+ {%- set documents_system_message_prefix = 'You are a helpful assistant with access to the following documents. You may use one or more documents to assist with the user query.\n\nYou are given a list of documents within <documents></documents> XML tags:\n<documents>' %}
66
+ {%- set documents_system_message_suffix = '\n</documents>\n\nWrite the response to the user\'s input by strictly aligning with the facts in the provided documents. If the information needed to answer the question is not available in the documents, inform the user that the question cannot be answered based on the available data.' %}
67
+ {%- set g4_default_system_message = 'You are a helpful assistant. Please ensure responses are professional, accurate, and safe.' %}
68
+ {%- if available_tools is defined and available_tools %}
69
+ {%- set tools = available_tools %}
70
+ {%- endif %}
71
+ {%- set ns = namespace(tools_system_message=tools_system_message_prefix,
72
+ documents_system_message=documents_system_message_prefix,
73
+ default_system_message=g4_default_system_message,
74
+ system_message=''
75
+ ) %}
76
+ {%- if tools %}
77
+ {%- for tool in tools %}
78
+ {%- set ns.tools_system_message = ns.tools_system_message + '\n' + (tool | tojson) %}
79
+ {%- endfor %}
80
+ {%- set ns.tools_system_message = ns.tools_system_message + tools_system_message_suffix %}
81
+ {%- else %}
82
+ {%- set ns.tools_system_message = '' %}
83
+ {%- endif %}
84
+ {%- if documents %}
85
+ {%- for document in documents %}
86
+ {%- set ns.documents_system_message = ns.documents_system_message + '\n' + (document | tojson) %}
87
+ {%- endfor %}
88
+ {%- set ns.documents_system_message = ns.documents_system_message + documents_system_message_suffix %}
89
+ {%- else %}
90
+ {%- set ns.documents_system_message = '' %}
91
+ {%- endif %}
92
+ {%- if messages[0].role == 'system' %}
93
+ {%- if messages[0].content is string %}
94
+ {%- set ns.system_message = messages[0].content %}
95
+ {%- elif messages[0].content is iterable %}
96
+ {%- for entry in messages[0].content %}
97
+ {%- if entry.type== 'text' %}
98
+ {%- if ns.system_message != '' %}
99
+ {%- set ns.system_message = ns.system_message + '\n' %}
100
+ {%- endif %}
101
+ {%- set ns.system_message = ns.system_message + entry.text %}
102
+ {%- endif %}
103
+ {%- endfor %}
104
+ {%- endif %}
105
+ {%- if tools and documents %}
106
+ {%- set ns.system_message = ns.system_message + '\n\n' + ns.tools_system_message + '\n\n' + ns.documents_system_message %}
107
+ {%- elif tools %}
108
+ {%- set ns.system_message = ns.system_message + '\n\n' + ns.tools_system_message %}
109
+ {%- elif documents %}
110
+ {%- set ns.system_message = ns.system_message + '\n\n' + ns.documents_system_message %}
111
+ {%- endif %}
112
+ {%- else %}
113
+ {%- if tools and documents %}
114
+ {%- set ns.system_message = ns.tools_system_message + '\n\n' + ns.documents_system_message %}
115
+ {%- elif tools %}
116
+ {%- set ns.system_message = ns.tools_system_message %}
117
+ {%- elif documents %}
118
+ {%- set ns.system_message = ns.documents_system_message %}
119
+ {%- endif %}
120
+ {%- endif %}
121
+ {%- if ns.system_message %}
122
+ {{- '<|start_of_role|>system<|end_of_role|>' + ns.system_message + '<|end_of_text|>\n' }}
123
+ {%- else %}
124
+ {{- '<|start_of_role|>system<|end_of_role|>' + ns.default_system_message + '<|end_of_text|>\n' }}
125
+ {%- endif %}
126
+ {%- for message in messages %}
127
+ {%- set content = namespace(val='') %}
128
+ {%- if render_content(message['content']) is string %}
129
+ {%- set content.val = render_content(message['content']) %}
130
+ {%- else %}
131
+ {%- if render_content(message['content']) is iterable %}
132
+ {%- for entry in render_content(message['content']) %}
133
+ {%- if entry.type== 'text' %}
134
+ {%- if content.val != '' %}
135
+ {%- set content.val = content.val + '\n' %}
136
+ {%- endif %}
137
+ {%- set content.val = content.val + entry.text %}
138
+ {%- endif %}
139
+ {%- endfor %}
140
+ {%- endif %}
141
+ {%- endif %}
142
+ {%- if (message.role == 'user') or (message.role == 'system' and not loop.first) %}
143
+ {{- '<|start_of_role|>' + message.role + '<|end_of_role|>' + expand_tags(content.val) + '<|end_of_text|>\n' }}
144
+ {%- elif message.role == 'assistant' %}
145
+ {{- '<|start_of_role|>' + message.role + '<|end_of_role|>' + content.val }}
146
+ {%- if message.tool_calls %}
147
+ {%- for tool_call in message.tool_calls %}
148
+ {%- if (loop.first and content.val) or (not loop.first) %}
149
+ {{- '\n' }}
150
+ {%- endif %}
151
+ {%- if tool_call.function %}
152
+ {%- set tool_call = tool_call.function %}
153
+ {%- endif %}
154
+ {{- '<tool_call>\n{"name": "' }}
155
+ {{- tool_call.name }}
156
+ {{- '", "arguments": ' }}
157
+ {%- if tool_call.arguments is string %}
158
+ {{- tool_call.arguments }}
159
+ {%- else %}
160
+ {{- tool_call.arguments | tojson }}
161
+ {%- endif %}
162
+ {{- '}\n</tool_call>' }}
163
+ {%- endfor %}
164
+ {%- endif %}
165
+ {{- '<|end_of_text|>\n' }}
166
+ {%- elif message.role == 'tool' %}
167
+ {%- if loop.first or (messages[loop.index0 - 1].role != 'tool') %}
168
+ {{- '<|start_of_role|>user<|end_of_role|>' }}
169
+ {%- endif %}
170
+ {{- '\n<tool_response>\n' }}
171
+ {{- content.val }}
172
+ {{- '\n</tool_response>' }}
173
+ {%- if loop.last or (messages[loop.index0 + 1].role != 'tool') %}
174
+ {{- '<|end_of_text|>\n' }}
175
+ {%- endif %}
176
+ {%- endif %}
177
+ {%- endfor %}
178
+ {%- if add_generation_prompt %}
179
+ {{- '<|start_of_role|>assistant<|end_of_role|>' }}
180
+ {%- endif %}
config.json ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Granite4VisionForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration.Granite4VisionConfig",
7
+ "AutoModel": "modeling.Granite4VisionForConditionalGeneration",
8
+ "AutoModelForVision2Seq": "modeling.Granite4VisionForConditionalGeneration",
9
+ "AutoModelForImageTextToText": "modeling.Granite4VisionForConditionalGeneration",
10
+ "AutoProcessor": "processing.Granite4VisionProcessor"
11
+ },
12
+ "spatial_target_layers": [
13
+ 12,
14
+ 15,
15
+ 18,
16
+ 21
17
+ ],
18
+ "spatial_stride": 2,
19
+ "spatial_vision_layer": -1,
20
+ "downsample_rate": "4/8",
21
+ "dtype": "bfloat16",
22
+ "image_grid_pinpoints": [
23
+ [
24
+ 384,
25
+ 384
26
+ ],
27
+ [
28
+ 384,
29
+ 768
30
+ ],
31
+ [
32
+ 384,
33
+ 1152
34
+ ],
35
+ [
36
+ 384,
37
+ 1536
38
+ ],
39
+ [
40
+ 384,
41
+ 1920
42
+ ],
43
+ [
44
+ 384,
45
+ 2304
46
+ ],
47
+ [
48
+ 384,
49
+ 2688
50
+ ],
51
+ [
52
+ 384,
53
+ 3072
54
+ ],
55
+ [
56
+ 384,
57
+ 3456
58
+ ],
59
+ [
60
+ 384,
61
+ 3840
62
+ ],
63
+ [
64
+ 768,
65
+ 384
66
+ ],
67
+ [
68
+ 768,
69
+ 768
70
+ ],
71
+ [
72
+ 768,
73
+ 1152
74
+ ],
75
+ [
76
+ 768,
77
+ 1536
78
+ ],
79
+ [
80
+ 768,
81
+ 1920
82
+ ],
83
+ [
84
+ 1152,
85
+ 384
86
+ ],
87
+ [
88
+ 1152,
89
+ 768
90
+ ],
91
+ [
92
+ 1152,
93
+ 1152
94
+ ],
95
+ [
96
+ 1536,
97
+ 384
98
+ ],
99
+ [
100
+ 1536,
101
+ 768
102
+ ],
103
+ [
104
+ 1920,
105
+ 384
106
+ ],
107
+ [
108
+ 1920,
109
+ 768
110
+ ],
111
+ [
112
+ 2304,
113
+ 384
114
+ ],
115
+ [
116
+ 2688,
117
+ 384
118
+ ],
119
+ [
120
+ 3072,
121
+ 384
122
+ ],
123
+ [
124
+ 3456,
125
+ 384
126
+ ],
127
+ [
128
+ 3840,
129
+ 384
130
+ ]
131
+ ],
132
+ "image_seq_length": 576,
133
+ "image_token_index": 100352,
134
+ "initializer_range": 0.02,
135
+ "model_type": "granite4_vision",
136
+ "projector_dropout": 0.1,
137
+ "projector_hidden_act": "gelu",
138
+ "text_config": {
139
+ "architectures": [
140
+ "GraniteForCausalLM"
141
+ ],
142
+ "attention_bias": false,
143
+ "attention_dropout": 0.0,
144
+ "attention_multiplier": 0.015625,
145
+ "bos_token_id": 100257,
146
+ "embedding_multiplier": 12.0,
147
+ "eos_token_id": 100257,
148
+ "hidden_act": "silu",
149
+ "hidden_size": 2560,
150
+ "initializer_range": 0.1,
151
+ "intermediate_size": 8192,
152
+ "logits_scaling": 10.0,
153
+ "max_position_embeddings": 131072,
154
+ "mlp_bias": false,
155
+ "model_type": "granite",
156
+ "num_attention_heads": 40,
157
+ "num_hidden_layers": 40,
158
+ "num_key_value_heads": 8,
159
+ "pad_token_id": 100256,
160
+ "residual_multiplier": 0.22,
161
+ "rms_norm_eps": 1e-05,
162
+ "rope_scaling": null,
163
+ "rope_theta": 10000000,
164
+ "tie_word_embeddings": true,
165
+ "torch_dtype": "bfloat16",
166
+ "transformers_version": "4.53.3",
167
+ "use_cache": true,
168
+ "vocab_size": 100353
169
+ },
170
+ "tie_word_embeddings": true,
171
+ "transformers_version": "4.57.3",
172
+ "use_spatial_sampling": true,
173
+ "use_image_newline_parameter": true,
174
+ "vision_config": {
175
+ "attention_dropout": 0.0,
176
+ "hidden_act": "gelu_pytorch_tanh",
177
+ "hidden_size": 1152,
178
+ "image_size": 384,
179
+ "intermediate_size": 4304,
180
+ "layer_norm_eps": 1e-06,
181
+ "model_type": "siglip_vision_model",
182
+ "num_attention_heads": 16,
183
+ "num_channels": 3,
184
+ "num_hidden_layers": 27,
185
+ "patch_size": 16
186
+ },
187
+ "vision_feature_select_strategy": "full",
188
+ "deepstack_layer_map": [
189
+ [
190
+ -19,
191
+ 9
192
+ ],
193
+ [
194
+ -13,
195
+ 6
196
+ ],
197
+ [
198
+ -7,
199
+ 3
200
+ ],
201
+ [
202
+ -1,
203
+ 0
204
+ ]
205
+ ],
206
+ "eos_token_id": 100257,
207
+ "quantization": {
208
+ "group_size": 64,
209
+ "bits": 8,
210
+ "mode": "affine"
211
+ },
212
+ "quantization_config": {
213
+ "group_size": 64,
214
+ "bits": 8,
215
+ "mode": "affine"
216
+ }
217
+ }
configuration.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+ import logging
3
+ from transformers import LlavaNextConfig
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+
8
+ class Granite4VisionConfig(LlavaNextConfig):
9
+ model_type = "granite4_vision"
10
+ def __init__(
11
+ self,
12
+ downsample_rate=None,
13
+ use_image_newline_parameter=True,
14
+ deepstack_layer_map: Optional[list] = None,
15
+ use_spatial_sampling: bool = False,
16
+ spatial_stride: int = 2,
17
+ spatial_vision_layer: int = -1,
18
+ spatial_target_layers: Optional[list] = None,
19
+ projector_dropout=0.1,
20
+ **kwargs
21
+ ):
22
+ self.downsample_rate = downsample_rate
23
+ self.use_image_newline_parameter = use_image_newline_parameter
24
+ self.projector_dropout = projector_dropout
25
+
26
+ # Deepstack layer map: list of (vision_layer_idx, llm_layer_idx) tuples.
27
+ # Features from each vision layer are extracted, downsampled, and injected
28
+ # at the corresponding LLM layer during forward pass.
29
+ # e.g., [(-25, 12), (-17, 8), (-9, 4), (-1, 0)]
30
+ if deepstack_layer_map is not None:
31
+ self.deepstack_layer_map = [(int(v), int(l)) for v, l in deepstack_layer_map]
32
+ assert len(self.deepstack_layer_map) == len(set(self.deepstack_layer_map)), "expecting no duplicates"
33
+ else:
34
+ self.deepstack_layer_map = None
35
+
36
+ # Spatial sampling: extracts 4 groups from a single vision layer using
37
+ # spatial offset sampling (top-left, top-right, bottom-left, bottom-right
38
+ # of each 2x2 block), each injected at a different LLM layer.
39
+ self.use_spatial_sampling = use_spatial_sampling
40
+ self.spatial_stride = spatial_stride
41
+ self.spatial_vision_layer = spatial_vision_layer
42
+ self.spatial_target_layers = spatial_target_layers or [0, 10, 20, 30]
43
+
44
+ super().__init__(**kwargs)
downsampling.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from torch import nn
3
+ import math
4
+ from fractions import Fraction
5
+ from transformers.models.blip_2.configuration_blip_2 import Blip2QFormerConfig
6
+ from transformers.models.blip_2.modeling_blip_2 import Blip2QFormerModel
7
+
8
+
9
+ class InterpolateDownsampler:
10
+ """Spatial downsampling via area interpolation."""
11
+ def __init__(self, config, mode="area"):
12
+ self.orig_image_side = config.vision_config.image_size // config.vision_config.patch_size
13
+ self.new_image_side = int(self.orig_image_side * Fraction(config.downsample_rate))
14
+ self.mode = mode
15
+
16
+ def __call__(self, image_features):
17
+ batch_size, _, dim = image_features.size()
18
+ up_shape = [batch_size] + [self.orig_image_side] * 2 + [dim]
19
+ large_image_permuted = image_features.view(up_shape).permute(0,3,1,2)
20
+ small_image_permuted = torch.nn.functional.interpolate(
21
+ large_image_permuted, size=(self.new_image_side, self.new_image_side),
22
+ mode=self.mode,
23
+ )
24
+ final = small_image_permuted.permute(0,2,3,1).flatten(1,2)
25
+ return final
26
+
27
+
28
+ class SpatialOffsetDownsampler:
29
+ """
30
+ Downsampler that samples one position from each 2x2 block across the image.
31
+ Maintains full spatial coverage while creating local continuity.
32
+ """
33
+ def __init__(self, config, offset=0):
34
+ """
35
+ Args:
36
+ config: Model configuration
37
+ offset: Integer offset (0, 1, 2, or 3) for position within each 2x2 block
38
+ 0: top-left, 1: top-right, 2: bottom-left, 3: bottom-right
39
+ """
40
+ self.orig_image_side = config.vision_config.image_size // config.vision_config.patch_size
41
+ self.new_image_side = self.orig_image_side // 2
42
+ self.offset = offset
43
+ self.offsets = [(0, 0), (0, 1), (1, 0), (1, 1)]
44
+ self.offset_h, self.offset_w = self.offsets[offset]
45
+
46
+ def __call__(self, image_features):
47
+ batch_size, seq_len, hidden_dim = image_features.shape
48
+ features_2d = image_features.reshape(batch_size, self.orig_image_side, self.orig_image_side, hidden_dim)
49
+
50
+ n_blocks = self.new_image_side
51
+ features_blocks = features_2d.reshape(
52
+ batch_size, n_blocks, 2, n_blocks, 2, hidden_dim
53
+ )
54
+
55
+ sampled = features_blocks[:, :, self.offset_h, :, self.offset_w, :]
56
+ sampled = sampled.reshape(batch_size, -1, hidden_dim)
57
+
58
+ return sampled
59
+
60
+
61
+ class WindowQFormerDownsampler(nn.Module):
62
+ """Window-based QFormer downsampler that processes image patches in windows."""
63
+ def __init__(self, config, spatial_offset=None):
64
+ super().__init__()
65
+ llm_hidden_size = config.text_config.hidden_size
66
+ vision_hidden_size = config.vision_config.hidden_size
67
+
68
+ self.dropout = nn.Dropout(config.projector_dropout)
69
+
70
+ if spatial_offset is not None:
71
+ self.downsampler = SpatialOffsetDownsampler(config, offset=spatial_offset)
72
+ else:
73
+ self.downsampler = InterpolateDownsampler(config)
74
+
75
+ configuration = Blip2QFormerConfig(
76
+ hidden_size=vision_hidden_size,
77
+ num_attention_heads=vision_hidden_size // 64,
78
+ intermediate_size=3072,
79
+ num_hidden_layers=1,
80
+ encoder_hidden_size=vision_hidden_size,
81
+ cross_attention_frequency=1,
82
+ max_position_embeddings=2048,
83
+ use_qformer_text_input=False,
84
+ )
85
+ self.qformer = Blip2QFormerModel(configuration)
86
+
87
+ self.image_side = config.vision_config.image_size // config.vision_config.patch_size
88
+ q, w = config.downsample_rate.split("/")
89
+ self.query_side, self.window_side = int(q), int(w)
90
+ self.query_length = self.query_side ** 2
91
+ embed_std = 1 / math.sqrt(vision_hidden_size)
92
+ self.norm = nn.LayerNorm(vision_hidden_size, eps=1e-6)
93
+ self.query = nn.Parameter(torch.randn(1, self.query_length, vision_hidden_size) * embed_std)
94
+ self.image_positions = nn.Parameter(torch.randn(1, self.window_side ** 2, vision_hidden_size) * embed_std)
95
+ self.out_linear = nn.Linear(vision_hidden_size, llm_hidden_size, bias=True)
96
+
97
+ def _win(self, x, side, win):
98
+ """
99
+ (B, side*side, C) raster -> (B*n*n, win*win, C) where n=side//win
100
+ windows are raster-ordered, and tokens inside each window are raster-ordered.
101
+ """
102
+ B, _, C = x.shape
103
+ n = side // win
104
+ return (
105
+ x.view(B, side, side, C)
106
+ .view(B, n, win, n, win, C)
107
+ .transpose(2, 3) # (B, n, n, win, win, C)
108
+ .flatten(0, 2) # (B*n*n, win, win, C)
109
+ .flatten(1, 2) # (B*n*n, win*win, C)
110
+ )
111
+
112
+ def _unwin(self, xw, n, win):
113
+ """
114
+ (B*n*n, win*win, C) -> (B, (n*win)^2, C) raster
115
+ """
116
+ Bnn, _, C = xw.shape
117
+ assert Bnn % (n * n) == 0
118
+ B = Bnn // (n * n)
119
+ side = n * win
120
+ return (
121
+ xw.view(B, n, n, win, win, C)
122
+ .transpose(2, 3) # (B, n, win, n, win, C)
123
+ .contiguous()
124
+ .view(B, side, side, C)
125
+ .flatten(1, 2)
126
+ )
127
+
128
+ def forward(self, image_features):
129
+ B, HW, C = image_features.shape
130
+ assert HW == self.image_side * self.image_side
131
+ n = self.image_side // self.window_side
132
+ image_features = self.norm(image_features)
133
+ enc = self._win(image_features, self.image_side, self.window_side)
134
+
135
+ downsampled = self.downsampler(image_features)
136
+
137
+ new_side = n * self.query_side
138
+ downsampled_w = self._win(downsampled, new_side, self.query_side)
139
+
140
+ query_embeds = self.query + downsampled_w
141
+ encoder_embeds = self.dropout(enc + self.image_positions)
142
+ out_w = self.qformer(
143
+ query_embeds=query_embeds,
144
+ encoder_hidden_states=encoder_embeds,
145
+ return_dict=True,
146
+ ).last_hidden_state
147
+
148
+ out = self._unwin(out_w, n=n, win=self.query_side)
149
+
150
+ out = self.dropout(out)
151
+ return self.out_linear(out)
generation_config.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 100257,
4
+ "eos_token_id": 100257,
5
+ "pad_token_id": 100256,
6
+ "transformers_version": "4.57.3"
7
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d9d4a2d2bcbf82ea2e2ee68351b852a79051c8c3c715c7299ac637463741de0c
3
+ size 4649181308
modeling.py ADDED
@@ -0,0 +1,550 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from fractions import Fraction
3
+ from typing import Optional, Union
4
+
5
+ import numpy as np
6
+ import torch
7
+ from torch import nn
8
+ import transformers
9
+ from transformers import (
10
+ AutoModel,
11
+ LlavaNextForConditionalGeneration,
12
+ )
13
+
14
+ _V5 = int(transformers.__version__.split(".")[0]) >= 5
15
+ from transformers.masking_utils import create_causal_mask
16
+ from transformers.cache_utils import Cache, DynamicCache
17
+ from transformers.modeling_flash_attention_utils import FlashAttentionKwargs
18
+ from transformers.models.llava_next.modeling_llava_next import (
19
+ LlavaNextCausalLMOutputWithPast,
20
+ LlavaNextModelOutputWithPast,
21
+ LlavaNextPreTrainedModel,
22
+ get_anyres_image_grid_shape,
23
+ image_size_to_num_patches,
24
+ unpad_image,
25
+ )
26
+ from transformers.processing_utils import Unpack
27
+ from transformers.utils import TransformersKwargs, can_return_tuple, logging
28
+
29
+ from .configuration import Granite4VisionConfig
30
+ from .downsampling import WindowQFormerDownsampler
31
+
32
+ logger = logging.get_logger(__name__)
33
+
34
+
35
+ class Granite4VisionForConditionalGeneration(LlavaNextForConditionalGeneration):
36
+ config_class = Granite4VisionConfig
37
+
38
+ def __init__(self, config: Granite4VisionConfig):
39
+ LlavaNextPreTrainedModel.__init__(self, config)
40
+
41
+ self.model = Granite4VisionModel(config)
42
+
43
+ self.lm_head = nn.Linear(
44
+ config.text_config.hidden_size, config.text_config.vocab_size, bias=False
45
+ )
46
+
47
+ self.post_init()
48
+
49
+ def generate(self, *args, **kwargs) -> torch.LongTensor:
50
+ # When loaded with a LoRA adapter, disable the adapter for text-only
51
+ # inputs (no pixel_values) so the base LLM runs standalone.
52
+ pixel_values = kwargs.get("pixel_values", None)
53
+ if hasattr(self, "_hf_peft_config_loaded") and self._hf_peft_config_loaded:
54
+ if pixel_values is not None:
55
+ self.enable_adapters()
56
+ else:
57
+ self.disable_adapters()
58
+ return super().generate(*args, **kwargs)
59
+
60
+ @can_return_tuple
61
+ def forward(
62
+ self,
63
+ input_ids: Optional[torch.LongTensor] = None,
64
+ pixel_values: Optional[torch.FloatTensor] = None,
65
+ image_sizes: Optional[torch.LongTensor] = None,
66
+ attention_mask: Optional[torch.Tensor] = None,
67
+ position_ids: Optional[torch.LongTensor] = None,
68
+ past_key_values: Optional[Cache] = None,
69
+ inputs_embeds: Optional[torch.FloatTensor] = None,
70
+ vision_feature_layer: Optional[Union[int, list[int]]] = None,
71
+ vision_feature_select_strategy: Optional[str] = None,
72
+ labels: Optional[torch.LongTensor] = None,
73
+ use_cache: Optional[bool] = None,
74
+ output_attentions: Optional[bool] = None,
75
+ output_hidden_states: Optional[bool] = None,
76
+ logits_to_keep: Union[int, torch.Tensor] = 0,
77
+ **kwargs: Unpack[TransformersKwargs],
78
+ ) -> Union[tuple, LlavaNextCausalLMOutputWithPast]:
79
+ cache_position = kwargs.pop("cache_position", None)
80
+
81
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
82
+ output_hidden_states = (
83
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
84
+ )
85
+ vision_feature_layer = (
86
+ vision_feature_layer if vision_feature_layer is not None else self.config.vision_feature_layer
87
+ )
88
+ vision_feature_select_strategy = (
89
+ vision_feature_select_strategy
90
+ if vision_feature_select_strategy is not None
91
+ else self.config.vision_feature_select_strategy
92
+ )
93
+
94
+ model_kwargs = dict(
95
+ pixel_values=pixel_values,
96
+ image_sizes=image_sizes,
97
+ vision_feature_layer=vision_feature_layer,
98
+ vision_feature_select_strategy=vision_feature_select_strategy,
99
+ attention_mask=attention_mask,
100
+ position_ids=position_ids,
101
+ past_key_values=past_key_values,
102
+ inputs_embeds=inputs_embeds,
103
+ use_cache=use_cache,
104
+ output_attentions=output_attentions,
105
+ output_hidden_states=output_hidden_states,
106
+ return_dict=True,
107
+ )
108
+ if not _V5:
109
+ model_kwargs["cache_position"] = cache_position
110
+ outputs = self.model(input_ids, **model_kwargs, **kwargs)
111
+
112
+ hidden_states = outputs.last_hidden_state
113
+
114
+ loss = None
115
+ logits = self.lm_head(hidden_states)
116
+ logits = logits / self.config.text_config.logits_scaling
117
+ if labels is not None:
118
+ loss = self.loss_function(
119
+ logits,
120
+ labels,
121
+ vocab_size=self.config.text_config.vocab_size,
122
+ **kwargs,
123
+ )
124
+
125
+ if isinstance(logits_to_keep, int) and logits_to_keep > 0:
126
+ logits = logits[:, -logits_to_keep:, :]
127
+
128
+ return LlavaNextCausalLMOutputWithPast(
129
+ loss=loss,
130
+ logits=logits,
131
+ past_key_values=outputs.past_key_values,
132
+ hidden_states=outputs.hidden_states,
133
+ attentions=outputs.attentions,
134
+ image_hidden_states=outputs.image_hidden_states,
135
+ )
136
+
137
+ def prepare_inputs_for_generation(
138
+ self,
139
+ input_ids,
140
+ past_key_values=None,
141
+ inputs_embeds=None,
142
+ pixel_values=None,
143
+ image_sizes=None,
144
+ attention_mask=None,
145
+ cache_position=None,
146
+ logits_to_keep=None,
147
+ **kwargs,
148
+ ):
149
+ if _V5:
150
+ is_first = kwargs.get("is_first_iteration", False)
151
+ model_inputs = super().prepare_inputs_for_generation(
152
+ input_ids,
153
+ past_key_values=past_key_values,
154
+ inputs_embeds=inputs_embeds,
155
+ attention_mask=attention_mask,
156
+ logits_to_keep=logits_to_keep,
157
+ **kwargs,
158
+ )
159
+ else:
160
+ is_first = cache_position[0] == 0 if cache_position is not None else True
161
+ model_inputs = super().prepare_inputs_for_generation(
162
+ input_ids,
163
+ past_key_values=past_key_values,
164
+ inputs_embeds=inputs_embeds,
165
+ attention_mask=attention_mask,
166
+ cache_position=cache_position,
167
+ logits_to_keep=logits_to_keep,
168
+ **kwargs,
169
+ )
170
+ if is_first:
171
+ model_inputs["pixel_values"] = pixel_values
172
+ model_inputs["image_sizes"] = image_sizes
173
+
174
+ return model_inputs
175
+
176
+
177
+ class Granite4VisionModel(LlavaNextPreTrainedModel):
178
+ config_class = Granite4VisionConfig
179
+
180
+ def __init__(self, config: Granite4VisionConfig):
181
+ super().__init__(config)
182
+ self.vision_tower = AutoModel.from_config(config.vision_config)
183
+ self.spatial_projectors = None
184
+
185
+ assert config.deepstack_layer_map is not None
186
+ assert config.downsample_rate is not None
187
+
188
+ self.downsample_rate = config.downsample_rate
189
+
190
+ # Deepstack projectors: one per (vision_layer, llm_layer) pair
191
+ self.layerwise_projectors = nn.ModuleList([
192
+ WindowQFormerDownsampler(config)
193
+ for _ in range(len(config.deepstack_layer_map))
194
+ ])
195
+
196
+ # Spatial sampling projectors: 4 offset groups (TL, TR, BL, BR)
197
+ if config.use_spatial_sampling:
198
+ self.spatial_projectors = nn.ModuleList([
199
+ WindowQFormerDownsampler(config, spatial_offset=i)
200
+ for i in range(4)
201
+ ])
202
+
203
+ self.image_newline = None
204
+ if config.use_image_newline_parameter:
205
+ embed_std = 1 / math.sqrt(config.text_config.hidden_size)
206
+ self.image_newline = nn.Parameter(torch.randn(config.text_config.hidden_size, dtype=self.dtype) * embed_std)
207
+
208
+ self.vocab_size = config.text_config.vocab_size
209
+ self.language_model = AutoModel.from_config(config.text_config)
210
+ self.pad_token_id = getattr(self.config, "pad_token_id", None) or -1
211
+ self.post_init()
212
+
213
+ def get_input_embeddings(self):
214
+ return self.language_model.get_input_embeddings()
215
+
216
+ def set_input_embeddings(self, value):
217
+ self.language_model.set_input_embeddings(value)
218
+
219
+ def set_decoder(self, decoder):
220
+ self.language_model = decoder
221
+
222
+ def get_decoder(self):
223
+ return self.language_model
224
+
225
+ def pack_and_unpad_image_features(self, image_features, image_sizes, vision_feature_select_strategy, image_newline=None):
226
+ """
227
+ Reshape, unpad and then pack each image_feature into a single image_features tensor containing all visual vectors.
228
+
229
+ Args:
230
+ image_features (`list[torch.Tensor]` of length num_images, each of shape `(num_patches, image_length, embed_dim)`)
231
+ List of image feature tensor, each contains all the visual feature of all patches.
232
+ image_sizes (`torch.Tensor` of shape `(num_images, 2)`)
233
+ Actual image size of each images (H, W).
234
+ vision_feature_select_strategy (`str`)
235
+ The feature selection strategy used to select the vision feature from the vision backbone.
236
+ image_newline (`torch.Tensor` of shape `(embed_dim)`)
237
+ New line embedding vector.
238
+ Returns:
239
+ image_features (`torch.Tensor` of shape `(all_feat_len, embed_dim)`)
240
+ feature_lens (`list[int]`)
241
+ token length of each image in image_features
242
+ """
243
+ new_image_features = []
244
+ feature_lens = []
245
+ for image_idx, image_feature in enumerate(image_features):
246
+ if image_feature.shape[0] > 1:
247
+ base_image_feature = image_feature[0]
248
+ image_feature = image_feature[1:]
249
+ height = width = self.config.vision_config.image_size // self.config.vision_config.patch_size
250
+
251
+ num_patch_height, num_patch_width = get_anyres_image_grid_shape(
252
+ image_sizes[image_idx],
253
+ self.config.image_grid_pinpoints,
254
+ self.config.vision_config.image_size,
255
+ )
256
+ if self.layerwise_projectors is not None:
257
+ ds_rate = Fraction(self.downsample_rate)
258
+ height = int(height * ds_rate)
259
+ width = int(width * ds_rate)
260
+
261
+ if (
262
+ np.prod(image_feature.shape) % (num_patch_height * num_patch_width * height * width) != 0
263
+ and vision_feature_select_strategy == "default"
264
+ ):
265
+ logger.warning_once(
266
+ "Image feature shape does not line up with the provided patch size. "
267
+ "You may be using the `default` vision_feature_select_strategy with a"
268
+ " visual encoder that does not have CLS."
269
+ )
270
+
271
+ image_feature = image_feature.view(num_patch_height, num_patch_width, height, width, -1)
272
+ image_feature = image_feature.permute(4, 0, 2, 1, 3).contiguous()
273
+ image_feature = image_feature.flatten(1, 2).flatten(2, 3)
274
+ image_feature = unpad_image(image_feature, image_sizes[image_idx])
275
+ if image_newline is not None:
276
+ image_feature = torch.cat(
277
+ (
278
+ image_feature,
279
+ image_newline[:, None, None]
280
+ .expand(*image_feature.shape[:-1], 1)
281
+ .to(image_feature.device, image_feature.dtype),
282
+ ),
283
+ dim=-1,
284
+ )
285
+ image_feature = image_feature.flatten(1, 2).transpose(0, 1)
286
+ image_feature = torch.cat((base_image_feature, image_feature), dim=0)
287
+ else:
288
+ image_feature = image_feature[0]
289
+ if image_newline is not None:
290
+ image_feature = torch.cat((image_feature, image_newline[None].to(image_feature)), dim=0)
291
+ new_image_features.append(image_feature)
292
+ feature_lens.append(image_feature.size(0))
293
+ feature_lens = torch.tensor(feature_lens, dtype=torch.long, device=image_features[0].device)
294
+ return new_image_features, feature_lens
295
+
296
+ def get_image_features(
297
+ self,
298
+ pixel_values: torch.FloatTensor,
299
+ image_sizes: torch.Tensor,
300
+ vision_feature_layer: Optional[Union[int, list[int]]] = None,
301
+ vision_feature_select_strategy: Optional[str] = None,
302
+ ):
303
+ """
304
+ Extract image features via deepstack (multi-layer) and spatial sampling projections.
305
+
306
+ Runs the vision tower once, then:
307
+ 1. Deepstack: for each (vision_layer, llm_layer) in deepstack_layer_map,
308
+ extracts features from that vision layer, downsamples via interpolation + QFormer,
309
+ and pairs them with the target LLM layer.
310
+ 2. Spatial: if enabled, extracts the spatial_vision_layer and creates 4 spatial
311
+ offset groups (TL, TR, BL, BR), each targeting a different LLM layer.
312
+
313
+ Args:
314
+ pixel_values: Image tensors of shape (batch, num_patches, C, H, W) or (N, C, H, W).
315
+ image_sizes: Actual image sizes (num_images, 2).
316
+ vision_feature_layer: Unused (kept for API compatibility).
317
+ vision_feature_select_strategy: "default" (remove CLS) or "full".
318
+ Returns:
319
+ List of (llm_layer_idx, packed_features) tuples for injection during forward pass.
320
+ """
321
+ vision_feature_select_strategy = (
322
+ vision_feature_select_strategy
323
+ if vision_feature_select_strategy is not None
324
+ else self.config.vision_feature_select_strategy
325
+ )
326
+
327
+ image_num_patches = [
328
+ image_size_to_num_patches(
329
+ image_size=imsize,
330
+ grid_pinpoints=self.config.image_grid_pinpoints,
331
+ patch_size=self.config.vision_config.image_size,
332
+ )
333
+ for imsize in image_sizes
334
+ ]
335
+
336
+ if pixel_values.dim() == 5:
337
+ _pixel_values_list = [pix_val[:num_patch] for pix_val, num_patch in zip(pixel_values, image_num_patches)]
338
+ pixel_values = torch.cat(_pixel_values_list, dim=0)
339
+ elif pixel_values.dim() != 4:
340
+ raise ValueError(f"pixel_values of shape {pixel_values.shape}, expect to be of 4 or 5 dimensions")
341
+
342
+ vision_outputs = self.vision_tower(pixel_values, output_hidden_states=True)
343
+
344
+ # Deepstack features: extract from multiple vision layers, downsample via interpolation
345
+ all_features = []
346
+ for projection_idx, (vision_layer, llm_layer) in enumerate(self.config.deepstack_layer_map):
347
+ selected_feature = vision_outputs.hidden_states[vision_layer]
348
+
349
+ if vision_feature_select_strategy == "default":
350
+ selected_feature = selected_feature[:, 1:]
351
+
352
+ projected_features = self.layerwise_projectors[projection_idx](selected_feature)
353
+ projected_features = torch.split(projected_features, image_num_patches, dim=0)
354
+
355
+ packed_features, _ = self.pack_and_unpad_image_features(
356
+ projected_features,
357
+ image_sizes,
358
+ vision_feature_select_strategy=vision_feature_select_strategy,
359
+ image_newline=self.image_newline,
360
+ )
361
+
362
+ all_features.append((llm_layer, packed_features))
363
+
364
+ # Spatial features: extract 4 offset groups from a single vision layer
365
+ if self.config.use_spatial_sampling:
366
+ spatial_feature = vision_outputs.hidden_states[self.config.spatial_vision_layer]
367
+
368
+ if vision_feature_select_strategy == "default":
369
+ spatial_feature = spatial_feature[:, 1:]
370
+
371
+ for group_idx, llm_layer in enumerate(self.config.spatial_target_layers):
372
+ projected_group = self.spatial_projectors[group_idx](spatial_feature)
373
+ projected_group_split = torch.split(projected_group, image_num_patches, dim=0)
374
+
375
+ packed_group, _ = self.pack_and_unpad_image_features(
376
+ projected_group_split,
377
+ image_sizes,
378
+ vision_feature_select_strategy=vision_feature_select_strategy,
379
+ image_newline=self.image_newline,
380
+ )
381
+
382
+ all_features.append((llm_layer, packed_group))
383
+
384
+ return all_features
385
+
386
+ def get_image_token_mask(
387
+ self, input_ids: torch.LongTensor, inputs_embeds: torch.FloatTensor, image_features: torch.FloatTensor
388
+ ):
389
+ """
390
+ Build a boolean mask over inputs_embeds marking positions of <image> tokens,
391
+ and verify that the count matches the number of image feature vectors.
392
+ """
393
+ if input_ids is None:
394
+ special_image_mask = inputs_embeds == self.get_input_embeddings()(
395
+ torch.tensor(self.config.image_token_id, dtype=torch.long, device=inputs_embeds.device)
396
+ )
397
+ special_image_mask = special_image_mask.all(-1)
398
+ else:
399
+ special_image_mask = input_ids == self.config.image_token_id
400
+
401
+ n_image_tokens = special_image_mask.sum()
402
+ special_image_mask = special_image_mask.unsqueeze(-1).expand_as(inputs_embeds).to(inputs_embeds.device)
403
+ if inputs_embeds[special_image_mask].numel() != image_features.numel():
404
+ raise ValueError(
405
+ f"Image features and image tokens do not match: tokens: {n_image_tokens}, features {image_features.shape[0]}"
406
+ )
407
+ return special_image_mask
408
+
409
+ @can_return_tuple
410
+ def forward(
411
+ self,
412
+ input_ids: Optional[torch.LongTensor] = None,
413
+ pixel_values: Optional[torch.FloatTensor] = None,
414
+ image_sizes: Optional[torch.LongTensor] = None,
415
+ attention_mask: Optional[torch.Tensor] = None,
416
+ position_ids: Optional[torch.LongTensor] = None,
417
+ past_key_values: Optional[Cache] = None,
418
+ inputs_embeds: Optional[torch.FloatTensor] = None,
419
+ vision_feature_layer: Optional[Union[int, list[int]]] = None,
420
+ vision_feature_select_strategy: Optional[str] = None,
421
+ use_cache: Optional[bool] = None,
422
+ output_attentions: Optional[bool] = None,
423
+ output_hidden_states: Optional[bool] = None,
424
+ return_dict: Optional[bool] = None,
425
+ **kwargs: Unpack[FlashAttentionKwargs],
426
+ ) -> Union[tuple, LlavaNextModelOutputWithPast]:
427
+ cache_position = kwargs.pop("cache_position", None)
428
+ output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
429
+ output_hidden_states = (
430
+ output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
431
+ )
432
+ return_dict = return_dict if return_dict is not None else self.config.return_dict
433
+ vision_feature_layer = (
434
+ vision_feature_layer if vision_feature_layer is not None else self.config.vision_feature_layer
435
+ )
436
+ vision_feature_select_strategy = (
437
+ vision_feature_select_strategy
438
+ if vision_feature_select_strategy is not None
439
+ else self.config.vision_feature_select_strategy
440
+ )
441
+
442
+ if (input_ids is None) ^ (inputs_embeds is not None):
443
+ raise ValueError("You must specify exactly one of input_ids or inputs_embeds")
444
+
445
+ if inputs_embeds is None:
446
+ inputs_embeds = self.get_input_embeddings()(input_ids)
447
+
448
+ # Extract deepstack + spatial features and prepare for layer-by-layer injection
449
+ deepstack_features = []
450
+ vision_mask = None
451
+ image_features = None
452
+ if pixel_values is not None and pixel_values.size(0) > 0:
453
+ image_features = self.get_image_features(
454
+ pixel_values,
455
+ image_sizes,
456
+ vision_feature_layer=vision_feature_layer,
457
+ vision_feature_select_strategy=vision_feature_select_strategy,
458
+ )
459
+
460
+ for idx, (llm_layer_idx, packed_features) in enumerate(image_features):
461
+ concat_features = torch.cat(packed_features, dim=0).to(
462
+ inputs_embeds.device, inputs_embeds.dtype
463
+ )
464
+ if idx == 0:
465
+ vision_mask = self.get_image_token_mask(
466
+ input_ids, inputs_embeds=inputs_embeds, image_features=concat_features
467
+ )
468
+ inputs_embeds = inputs_embeds.masked_fill(vision_mask, 0.0)
469
+ deepstack_features.append((llm_layer_idx, concat_features))
470
+
471
+ # Custom forward pass with vision injection at specific LLM layers
472
+ hidden_states = inputs_embeds * self.language_model.embedding_multiplier
473
+
474
+ if use_cache and past_key_values is None:
475
+ past_key_values = DynamicCache(config=self.language_model.config)
476
+
477
+ if cache_position is None:
478
+ past_seen_tokens = past_key_values.get_seq_length() if past_key_values is not None else 0
479
+ cache_position = torch.arange(
480
+ past_seen_tokens, past_seen_tokens + inputs_embeds.shape[1], device=inputs_embeds.device
481
+ )
482
+ if position_ids is None:
483
+ position_ids = cache_position.unsqueeze(0)
484
+
485
+ # v4: input_embeds (positional), cache_position required
486
+ # v5: inputs_embeds (keyword), cache_position deprecated, past_key_values keyword-only
487
+ # v5 renamed input_embeds -> inputs_embeds; cache_position kept for BC
488
+ embeds_key = "inputs_embeds" if _V5 else "input_embeds"
489
+ mask_kwargs = dict(
490
+ config=self.language_model.config,
491
+ attention_mask=attention_mask,
492
+ cache_position=cache_position,
493
+ past_key_values=past_key_values,
494
+ position_ids=position_ids,
495
+ )
496
+ mask_kwargs[embeds_key] = inputs_embeds
497
+ causal_mask = create_causal_mask(**mask_kwargs)
498
+
499
+ position_embeddings = self.language_model.rotary_emb(hidden_states, position_ids)
500
+
501
+ all_hidden_states = () if output_hidden_states else None
502
+ all_self_attns = () if output_attentions else None
503
+
504
+ # v4: decoder_layer returns tuple (hidden_states, [attn_weights]), takes output_attentions/cache_position
505
+ # v5: decoder_layer returns bare tensor
506
+ layer_kwargs = dict(
507
+ attention_mask=causal_mask,
508
+ position_ids=position_ids,
509
+ past_key_values=past_key_values,
510
+ use_cache=use_cache,
511
+ position_embeddings=position_embeddings,
512
+ )
513
+ if not _V5:
514
+ layer_kwargs["output_attentions"] = output_attentions
515
+ layer_kwargs["cache_position"] = cache_position
516
+
517
+ # Layer-by-layer forward with vision injection
518
+ for layer_idx, decoder_layer in enumerate(self.language_model.layers):
519
+ # Inject vision features at this layer if configured
520
+ for target_layer, features_for_layer in deepstack_features:
521
+ if layer_idx == target_layer:
522
+ hidden_states = hidden_states.masked_scatter(
523
+ vision_mask,
524
+ (hidden_states[vision_mask] + features_for_layer.flatten()).view(-1)
525
+ )
526
+
527
+ if output_hidden_states:
528
+ all_hidden_states += (hidden_states,)
529
+
530
+ layer_result = decoder_layer(hidden_states, **layer_kwargs, **kwargs)
531
+ if _V5:
532
+ hidden_states = layer_result
533
+ else:
534
+ hidden_states = layer_result[0]
535
+ if output_attentions:
536
+ all_self_attns += (layer_result[1],)
537
+
538
+ hidden_states = self.language_model.norm(hidden_states)
539
+
540
+ if output_hidden_states:
541
+ all_hidden_states += (hidden_states,)
542
+
543
+
544
+ return LlavaNextModelOutputWithPast(
545
+ last_hidden_state=hidden_states,
546
+ past_key_values=past_key_values if use_cache else None,
547
+ hidden_states=all_hidden_states,
548
+ attentions=all_self_attns,
549
+ image_hidden_states=image_features if pixel_values is not None else None,
550
+ )
preprocessor_config.json ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "crop_size": {
3
+ "height": 384,
4
+ "width": 384
5
+ },
6
+ "do_center_crop": true,
7
+ "do_convert_rgb": true,
8
+ "do_normalize": true,
9
+ "do_pad": true,
10
+ "do_rescale": true,
11
+ "do_resize": true,
12
+ "image_grid_pinpoints": [
13
+ [
14
+ 384,
15
+ 384
16
+ ],
17
+ [
18
+ 384,
19
+ 768
20
+ ],
21
+ [
22
+ 384,
23
+ 1152
24
+ ],
25
+ [
26
+ 384,
27
+ 1536
28
+ ],
29
+ [
30
+ 384,
31
+ 1920
32
+ ],
33
+ [
34
+ 384,
35
+ 2304
36
+ ],
37
+ [
38
+ 384,
39
+ 2688
40
+ ],
41
+ [
42
+ 384,
43
+ 3072
44
+ ],
45
+ [
46
+ 384,
47
+ 3456
48
+ ],
49
+ [
50
+ 384,
51
+ 3840
52
+ ],
53
+ [
54
+ 768,
55
+ 384
56
+ ],
57
+ [
58
+ 768,
59
+ 768
60
+ ],
61
+ [
62
+ 768,
63
+ 1152
64
+ ],
65
+ [
66
+ 768,
67
+ 1536
68
+ ],
69
+ [
70
+ 768,
71
+ 1920
72
+ ],
73
+ [
74
+ 1152,
75
+ 384
76
+ ],
77
+ [
78
+ 1152,
79
+ 768
80
+ ],
81
+ [
82
+ 1152,
83
+ 1152
84
+ ],
85
+ [
86
+ 1536,
87
+ 384
88
+ ],
89
+ [
90
+ 1536,
91
+ 768
92
+ ],
93
+ [
94
+ 1920,
95
+ 384
96
+ ],
97
+ [
98
+ 1920,
99
+ 768
100
+ ],
101
+ [
102
+ 2304,
103
+ 384
104
+ ],
105
+ [
106
+ 2688,
107
+ 384
108
+ ],
109
+ [
110
+ 3072,
111
+ 384
112
+ ],
113
+ [
114
+ 3456,
115
+ 384
116
+ ],
117
+ [
118
+ 3840,
119
+ 384
120
+ ]
121
+ ],
122
+ "image_mean": [
123
+ 0.5,
124
+ 0.5,
125
+ 0.5
126
+ ],
127
+ "image_processor_type": "LlavaNextImageProcessor",
128
+ "image_std": [
129
+ 0.5,
130
+ 0.5,
131
+ 0.5
132
+ ],
133
+ "processor_class": "Granite4VisionProcessor",
134
+ "auto_map": {
135
+ "AutoProcessor": "processing.Granite4VisionProcessor"
136
+ },
137
+ "resample": 3,
138
+ "rescale_factor": 0.00392156862745098,
139
+ "size": {
140
+ "height": 384,
141
+ "width": 384
142
+ }
143
+ }
processing.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fractions import Fraction
2
+
3
+ from transformers import LlavaNextProcessor
4
+ from transformers.image_processing_utils import select_best_resolution
5
+
6
+
7
+
8
+ class Granite4VisionProcessor(LlavaNextProcessor):
9
+ model_type = "granite4_vision"
10
+
11
+ def __init__(
12
+ self,
13
+ image_processor=None,
14
+ tokenizer=None,
15
+ patch_size=None,
16
+ vision_feature_select_strategy=None,
17
+ chat_template=None,
18
+ image_token="<image>", # set the default and let users change if they have peculiar special tokens in rare cases
19
+ num_additional_image_tokens=0,
20
+ downsample_rate=None,
21
+ **kwargs,
22
+ ):
23
+ super().__init__(image_processor=image_processor,
24
+ tokenizer=tokenizer,
25
+ patch_size=patch_size,
26
+ vision_feature_select_strategy=vision_feature_select_strategy,
27
+ chat_template=chat_template,
28
+ image_token=image_token,
29
+ num_additional_image_tokens=num_additional_image_tokens,
30
+ )
31
+ self.downsample_rate = downsample_rate
32
+
33
+ def _get_number_of_features(self, orig_height: int, orig_width: int, height: int, width: int) -> int:
34
+ image_grid_pinpoints = self.image_processor.image_grid_pinpoints
35
+
36
+ height_best_resolution, width_best_resolution = select_best_resolution(
37
+ [orig_height, orig_width], image_grid_pinpoints
38
+ )
39
+ scale_height, scale_width = height_best_resolution // height, width_best_resolution // width
40
+
41
+ patches_height = height // self.patch_size
42
+ patches_width = width // self.patch_size
43
+ if self.downsample_rate is not None:
44
+ ds_rate = Fraction(self.downsample_rate)
45
+ patches_height = int(patches_height * ds_rate)
46
+ patches_width = int(patches_width * ds_rate)
47
+
48
+ unpadded_features, newline_features = self._get_unpadded_features(
49
+ orig_height, orig_width, patches_height, patches_width, scale_height, scale_width
50
+ )
51
+ # The base patch covers the entire image (+1 for the CLS)
52
+ base_features = patches_height * patches_width + self.num_additional_image_tokens
53
+ num_image_tokens = unpadded_features + newline_features + base_features
54
+ return num_image_tokens
special_tokens_map.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<image>"
4
+ ],
5
+ "bos_token": {
6
+ "content": "<|end_of_text|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false
11
+ },
12
+ "eos_token": {
13
+ "content": "<|end_of_text|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false
18
+ },
19
+ "pad_token": {
20
+ "content": "<|pad|>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false
25
+ },
26
+ "unk_token": {
27
+ "content": "<|unk|>",
28
+ "lstrip": false,
29
+ "normalized": false,
30
+ "rstrip": false,
31
+ "single_word": false
32
+ }
33
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,796 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "100256": {
6
+ "content": "<|pad|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "100257": {
14
+ "content": "<|end_of_text|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "100258": {
22
+ "content": "<|fim_prefix|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": false
28
+ },
29
+ "100259": {
30
+ "content": "<|fim_middle|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": false
36
+ },
37
+ "100260": {
38
+ "content": "<|fim_suffix|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": false
44
+ },
45
+ "100261": {
46
+ "content": "<|fim_pad|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": false
52
+ },
53
+ "100262": {
54
+ "content": "<|filename|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": false
60
+ },
61
+ "100263": {
62
+ "content": "<|reponame|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": false
68
+ },
69
+ "100264": {
70
+ "content": "<|start_of_role|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "100265": {
78
+ "content": "<|end_of_role|>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "100266": {
86
+ "content": "<|unused_1|>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "100267": {
94
+ "content": "<|start_of_plugin|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "100268": {
102
+ "content": "<|end_of_plugin|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "100269": {
110
+ "content": "<|unk|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "100270": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "100271": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "100272": {
134
+ "content": "<tool_response>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "100273": {
142
+ "content": "</tool_response>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "100274": {
150
+ "content": "<think>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "100275": {
158
+ "content": "</think>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "100276": {
166
+ "content": "<think_on>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": true
172
+ },
173
+ "100277": {
174
+ "content": "<think_off>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": true
180
+ },
181
+ "100278": {
182
+ "content": "<schema>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": true
188
+ },
189
+ "100279": {
190
+ "content": "</schema>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": true
196
+ },
197
+ "100280": {
198
+ "content": "<tools>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": true
204
+ },
205
+ "100281": {
206
+ "content": "</tools>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": true
212
+ },
213
+ "100282": {
214
+ "content": "<documents>",
215
+ "lstrip": false,
216
+ "normalized": false,
217
+ "rstrip": false,
218
+ "single_word": false,
219
+ "special": true
220
+ },
221
+ "100283": {
222
+ "content": "</documents>",
223
+ "lstrip": false,
224
+ "normalized": false,
225
+ "rstrip": false,
226
+ "single_word": false,
227
+ "special": true
228
+ },
229
+ "100284": {
230
+ "content": "<|unused_15|>",
231
+ "lstrip": false,
232
+ "normalized": false,
233
+ "rstrip": false,
234
+ "single_word": false,
235
+ "special": true
236
+ },
237
+ "100285": {
238
+ "content": "<|unused_16|>",
239
+ "lstrip": false,
240
+ "normalized": false,
241
+ "rstrip": false,
242
+ "single_word": false,
243
+ "special": true
244
+ },
245
+ "100286": {
246
+ "content": "<|unused_17|>",
247
+ "lstrip": false,
248
+ "normalized": false,
249
+ "rstrip": false,
250
+ "single_word": false,
251
+ "special": true
252
+ },
253
+ "100287": {
254
+ "content": "<|unused_18|>",
255
+ "lstrip": false,
256
+ "normalized": false,
257
+ "rstrip": false,
258
+ "single_word": false,
259
+ "special": true
260
+ },
261
+ "100288": {
262
+ "content": "<|unused_19|>",
263
+ "lstrip": false,
264
+ "normalized": false,
265
+ "rstrip": false,
266
+ "single_word": false,
267
+ "special": true
268
+ },
269
+ "100289": {
270
+ "content": "<|unused_20|>",
271
+ "lstrip": false,
272
+ "normalized": false,
273
+ "rstrip": false,
274
+ "single_word": false,
275
+ "special": true
276
+ },
277
+ "100290": {
278
+ "content": "<|unused_21|>",
279
+ "lstrip": false,
280
+ "normalized": false,
281
+ "rstrip": false,
282
+ "single_word": false,
283
+ "special": true
284
+ },
285
+ "100291": {
286
+ "content": "<|unused_22|>",
287
+ "lstrip": false,
288
+ "normalized": false,
289
+ "rstrip": false,
290
+ "single_word": false,
291
+ "special": true
292
+ },
293
+ "100292": {
294
+ "content": "<|unused_23|>",
295
+ "lstrip": false,
296
+ "normalized": false,
297
+ "rstrip": false,
298
+ "single_word": false,
299
+ "special": true
300
+ },
301
+ "100293": {
302
+ "content": "<|unused_24|>",
303
+ "lstrip": false,
304
+ "normalized": false,
305
+ "rstrip": false,
306
+ "single_word": false,
307
+ "special": true
308
+ },
309
+ "100294": {
310
+ "content": "<|unused_25|>",
311
+ "lstrip": false,
312
+ "normalized": false,
313
+ "rstrip": false,
314
+ "single_word": false,
315
+ "special": true
316
+ },
317
+ "100295": {
318
+ "content": "<|unused_26|>",
319
+ "lstrip": false,
320
+ "normalized": false,
321
+ "rstrip": false,
322
+ "single_word": false,
323
+ "special": true
324
+ },
325
+ "100296": {
326
+ "content": "<|unused_27|>",
327
+ "lstrip": false,
328
+ "normalized": false,
329
+ "rstrip": false,
330
+ "single_word": false,
331
+ "special": true
332
+ },
333
+ "100297": {
334
+ "content": "<|unused_28|>",
335
+ "lstrip": false,
336
+ "normalized": false,
337
+ "rstrip": false,
338
+ "single_word": false,
339
+ "special": true
340
+ },
341
+ "100298": {
342
+ "content": "<|unused_29|>",
343
+ "lstrip": false,
344
+ "normalized": false,
345
+ "rstrip": false,
346
+ "single_word": false,
347
+ "special": true
348
+ },
349
+ "100299": {
350
+ "content": "<|unused_30|>",
351
+ "lstrip": false,
352
+ "normalized": false,
353
+ "rstrip": false,
354
+ "single_word": false,
355
+ "special": true
356
+ },
357
+ "100300": {
358
+ "content": "<|unused_31|>",
359
+ "lstrip": false,
360
+ "normalized": false,
361
+ "rstrip": false,
362
+ "single_word": false,
363
+ "special": true
364
+ },
365
+ "100301": {
366
+ "content": "<|unused_32|>",
367
+ "lstrip": false,
368
+ "normalized": false,
369
+ "rstrip": false,
370
+ "single_word": false,
371
+ "special": true
372
+ },
373
+ "100302": {
374
+ "content": "<|unused_33|>",
375
+ "lstrip": false,
376
+ "normalized": false,
377
+ "rstrip": false,
378
+ "single_word": false,
379
+ "special": true
380
+ },
381
+ "100303": {
382
+ "content": "<|unused_34|>",
383
+ "lstrip": false,
384
+ "normalized": false,
385
+ "rstrip": false,
386
+ "single_word": false,
387
+ "special": true
388
+ },
389
+ "100304": {
390
+ "content": "<|unused_35|>",
391
+ "lstrip": false,
392
+ "normalized": false,
393
+ "rstrip": false,
394
+ "single_word": false,
395
+ "special": true
396
+ },
397
+ "100305": {
398
+ "content": "<|unused_36|>",
399
+ "lstrip": false,
400
+ "normalized": false,
401
+ "rstrip": false,
402
+ "single_word": false,
403
+ "special": true
404
+ },
405
+ "100306": {
406
+ "content": "<|unused_37|>",
407
+ "lstrip": false,
408
+ "normalized": false,
409
+ "rstrip": false,
410
+ "single_word": false,
411
+ "special": true
412
+ },
413
+ "100307": {
414
+ "content": "<|unused_38|>",
415
+ "lstrip": false,
416
+ "normalized": false,
417
+ "rstrip": false,
418
+ "single_word": false,
419
+ "special": true
420
+ },
421
+ "100308": {
422
+ "content": "<|unused_39|>",
423
+ "lstrip": false,
424
+ "normalized": false,
425
+ "rstrip": false,
426
+ "single_word": false,
427
+ "special": true
428
+ },
429
+ "100309": {
430
+ "content": "<|unused_40|>",
431
+ "lstrip": false,
432
+ "normalized": false,
433
+ "rstrip": false,
434
+ "single_word": false,
435
+ "special": true
436
+ },
437
+ "100310": {
438
+ "content": "<|unused_41|>",
439
+ "lstrip": false,
440
+ "normalized": false,
441
+ "rstrip": false,
442
+ "single_word": false,
443
+ "special": true
444
+ },
445
+ "100311": {
446
+ "content": "<|unused_42|>",
447
+ "lstrip": false,
448
+ "normalized": false,
449
+ "rstrip": false,
450
+ "single_word": false,
451
+ "special": true
452
+ },
453
+ "100312": {
454
+ "content": "<|unused_43|>",
455
+ "lstrip": false,
456
+ "normalized": false,
457
+ "rstrip": false,
458
+ "single_word": false,
459
+ "special": true
460
+ },
461
+ "100313": {
462
+ "content": "<|unused_44|>",
463
+ "lstrip": false,
464
+ "normalized": false,
465
+ "rstrip": false,
466
+ "single_word": false,
467
+ "special": true
468
+ },
469
+ "100314": {
470
+ "content": "<|unused_45|>",
471
+ "lstrip": false,
472
+ "normalized": false,
473
+ "rstrip": false,
474
+ "single_word": false,
475
+ "special": true
476
+ },
477
+ "100315": {
478
+ "content": "<|unused_46|>",
479
+ "lstrip": false,
480
+ "normalized": false,
481
+ "rstrip": false,
482
+ "single_word": false,
483
+ "special": true
484
+ },
485
+ "100316": {
486
+ "content": "<|unused_47|>",
487
+ "lstrip": false,
488
+ "normalized": false,
489
+ "rstrip": false,
490
+ "single_word": false,
491
+ "special": true
492
+ },
493
+ "100317": {
494
+ "content": "<|unused_48|>",
495
+ "lstrip": false,
496
+ "normalized": false,
497
+ "rstrip": false,
498
+ "single_word": false,
499
+ "special": true
500
+ },
501
+ "100318": {
502
+ "content": "<|unused_49|>",
503
+ "lstrip": false,
504
+ "normalized": false,
505
+ "rstrip": false,
506
+ "single_word": false,
507
+ "special": true
508
+ },
509
+ "100319": {
510
+ "content": "<|unused_50|>",
511
+ "lstrip": false,
512
+ "normalized": false,
513
+ "rstrip": false,
514
+ "single_word": false,
515
+ "special": true
516
+ },
517
+ "100320": {
518
+ "content": "<|unused_51|>",
519
+ "lstrip": false,
520
+ "normalized": false,
521
+ "rstrip": false,
522
+ "single_word": false,
523
+ "special": true
524
+ },
525
+ "100321": {
526
+ "content": "<|unused_52|>",
527
+ "lstrip": false,
528
+ "normalized": false,
529
+ "rstrip": false,
530
+ "single_word": false,
531
+ "special": true
532
+ },
533
+ "100322": {
534
+ "content": "<|unused_53|>",
535
+ "lstrip": false,
536
+ "normalized": false,
537
+ "rstrip": false,
538
+ "single_word": false,
539
+ "special": true
540
+ },
541
+ "100323": {
542
+ "content": "<|unused_54|>",
543
+ "lstrip": false,
544
+ "normalized": false,
545
+ "rstrip": false,
546
+ "single_word": false,
547
+ "special": true
548
+ },
549
+ "100324": {
550
+ "content": "<|unused_55|>",
551
+ "lstrip": false,
552
+ "normalized": false,
553
+ "rstrip": false,
554
+ "single_word": false,
555
+ "special": true
556
+ },
557
+ "100325": {
558
+ "content": "<|unused_56|>",
559
+ "lstrip": false,
560
+ "normalized": false,
561
+ "rstrip": false,
562
+ "single_word": false,
563
+ "special": true
564
+ },
565
+ "100326": {
566
+ "content": "<|unused_57|>",
567
+ "lstrip": false,
568
+ "normalized": false,
569
+ "rstrip": false,
570
+ "single_word": false,
571
+ "special": true
572
+ },
573
+ "100327": {
574
+ "content": "<|unused_58|>",
575
+ "lstrip": false,
576
+ "normalized": false,
577
+ "rstrip": false,
578
+ "single_word": false,
579
+ "special": true
580
+ },
581
+ "100328": {
582
+ "content": "<|unused_59|>",
583
+ "lstrip": false,
584
+ "normalized": false,
585
+ "rstrip": false,
586
+ "single_word": false,
587
+ "special": true
588
+ },
589
+ "100329": {
590
+ "content": "<|unused_60|>",
591
+ "lstrip": false,
592
+ "normalized": false,
593
+ "rstrip": false,
594
+ "single_word": false,
595
+ "special": true
596
+ },
597
+ "100330": {
598
+ "content": "<|unused_61|>",
599
+ "lstrip": false,
600
+ "normalized": false,
601
+ "rstrip": false,
602
+ "single_word": false,
603
+ "special": true
604
+ },
605
+ "100331": {
606
+ "content": "<|unused_62|>",
607
+ "lstrip": false,
608
+ "normalized": false,
609
+ "rstrip": false,
610
+ "single_word": false,
611
+ "special": true
612
+ },
613
+ "100332": {
614
+ "content": "<|unused_63|>",
615
+ "lstrip": false,
616
+ "normalized": false,
617
+ "rstrip": false,
618
+ "single_word": false,
619
+ "special": true
620
+ },
621
+ "100333": {
622
+ "content": "<|unused_64|>",
623
+ "lstrip": false,
624
+ "normalized": false,
625
+ "rstrip": false,
626
+ "single_word": false,
627
+ "special": true
628
+ },
629
+ "100334": {
630
+ "content": "<|unused_65|>",
631
+ "lstrip": false,
632
+ "normalized": false,
633
+ "rstrip": false,
634
+ "single_word": false,
635
+ "special": true
636
+ },
637
+ "100335": {
638
+ "content": "<|unused_66|>",
639
+ "lstrip": false,
640
+ "normalized": false,
641
+ "rstrip": false,
642
+ "single_word": false,
643
+ "special": true
644
+ },
645
+ "100336": {
646
+ "content": "<|unused_67|>",
647
+ "lstrip": false,
648
+ "normalized": false,
649
+ "rstrip": false,
650
+ "single_word": false,
651
+ "special": true
652
+ },
653
+ "100337": {
654
+ "content": "<|unused_68|>",
655
+ "lstrip": false,
656
+ "normalized": false,
657
+ "rstrip": false,
658
+ "single_word": false,
659
+ "special": true
660
+ },
661
+ "100338": {
662
+ "content": "<|unused_69|>",
663
+ "lstrip": false,
664
+ "normalized": false,
665
+ "rstrip": false,
666
+ "single_word": false,
667
+ "special": true
668
+ },
669
+ "100339": {
670
+ "content": "<|unused_70|>",
671
+ "lstrip": false,
672
+ "normalized": false,
673
+ "rstrip": false,
674
+ "single_word": false,
675
+ "special": true
676
+ },
677
+ "100340": {
678
+ "content": "<|unused_71|>",
679
+ "lstrip": false,
680
+ "normalized": false,
681
+ "rstrip": false,
682
+ "single_word": false,
683
+ "special": true
684
+ },
685
+ "100341": {
686
+ "content": "<|unused_72|>",
687
+ "lstrip": false,
688
+ "normalized": false,
689
+ "rstrip": false,
690
+ "single_word": false,
691
+ "special": true
692
+ },
693
+ "100342": {
694
+ "content": "<|unused_73|>",
695
+ "lstrip": false,
696
+ "normalized": false,
697
+ "rstrip": false,
698
+ "single_word": false,
699
+ "special": true
700
+ },
701
+ "100343": {
702
+ "content": "<|unused_74|>",
703
+ "lstrip": false,
704
+ "normalized": false,
705
+ "rstrip": false,
706
+ "single_word": false,
707
+ "special": true
708
+ },
709
+ "100344": {
710
+ "content": "<|unused_75|>",
711
+ "lstrip": false,
712
+ "normalized": false,
713
+ "rstrip": false,
714
+ "single_word": false,
715
+ "special": true
716
+ },
717
+ "100345": {
718
+ "content": "<|unused_76|>",
719
+ "lstrip": false,
720
+ "normalized": false,
721
+ "rstrip": false,
722
+ "single_word": false,
723
+ "special": true
724
+ },
725
+ "100346": {
726
+ "content": "<|unused_77|>",
727
+ "lstrip": false,
728
+ "normalized": false,
729
+ "rstrip": false,
730
+ "single_word": false,
731
+ "special": true
732
+ },
733
+ "100347": {
734
+ "content": "<|unused_78|>",
735
+ "lstrip": false,
736
+ "normalized": false,
737
+ "rstrip": false,
738
+ "single_word": false,
739
+ "special": true
740
+ },
741
+ "100348": {
742
+ "content": "<|unused_79|>",
743
+ "lstrip": false,
744
+ "normalized": false,
745
+ "rstrip": false,
746
+ "single_word": false,
747
+ "special": true
748
+ },
749
+ "100349": {
750
+ "content": "<|unused_80|>",
751
+ "lstrip": false,
752
+ "normalized": false,
753
+ "rstrip": false,
754
+ "single_word": false,
755
+ "special": true
756
+ },
757
+ "100350": {
758
+ "content": "<|unused_81|>",
759
+ "lstrip": false,
760
+ "normalized": false,
761
+ "rstrip": false,
762
+ "single_word": false,
763
+ "special": true
764
+ },
765
+ "100351": {
766
+ "content": "<|unused_82|>",
767
+ "lstrip": false,
768
+ "normalized": false,
769
+ "rstrip": false,
770
+ "single_word": false,
771
+ "special": true
772
+ },
773
+ "100352": {
774
+ "content": "<image>",
775
+ "lstrip": false,
776
+ "normalized": false,
777
+ "rstrip": false,
778
+ "single_word": false,
779
+ "special": true
780
+ }
781
+ },
782
+ "additional_special_tokens": [
783
+ "<image>"
784
+ ],
785
+ "bos_token": "<|end_of_text|>",
786
+ "clean_up_tokenization_spaces": false,
787
+ "eos_token": "<|end_of_text|>",
788
+ "errors": "replace",
789
+ "extra_special_tokens": {},
790
+ "model_max_length": 1000000000000000019884624838656,
791
+ "pad_token": "<|pad|>",
792
+ "padding_side": "left",
793
+ "processor_class": "Granite4VisionProcessor",
794
+ "tokenizer_class": "GPT2Tokenizer",
795
+ "unk_token": "<|unk|>"
796
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff