Image-Text-to-Text
Transformers
Safetensors
English
granite4_vision
conversational
custom_code
8-bit precision
Instructions to use beaupi/granite-vision-4.1-4b-oQ8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use beaupi/granite-vision-4.1-4b-oQ8 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="beaupi/granite-vision-4.1-4b-oQ8", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("beaupi/granite-vision-4.1-4b-oQ8", trust_remote_code=True) model = AutoModelForMultimodalLM.from_pretrained("beaupi/granite-vision-4.1-4b-oQ8", trust_remote_code=True, device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use beaupi/granite-vision-4.1-4b-oQ8 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "beaupi/granite-vision-4.1-4b-oQ8" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beaupi/granite-vision-4.1-4b-oQ8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/beaupi/granite-vision-4.1-4b-oQ8
- SGLang
How to use beaupi/granite-vision-4.1-4b-oQ8 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "beaupi/granite-vision-4.1-4b-oQ8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beaupi/granite-vision-4.1-4b-oQ8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "beaupi/granite-vision-4.1-4b-oQ8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "beaupi/granite-vision-4.1-4b-oQ8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use beaupi/granite-vision-4.1-4b-oQ8 with Docker Model Runner:
docker model run hf.co/beaupi/granite-vision-4.1-4b-oQ8
Upload granite-vision-4.1-4b-oQ8 via oMLX
Browse files- README.md +387 -0
- added_tokens.json +3 -0
- chat_template.jinja +180 -0
- config.json +217 -0
- configuration.py +44 -0
- downsampling.py +151 -0
- generation_config.json +7 -0
- merges.txt +0 -0
- model.safetensors +3 -0
- modeling.py +550 -0
- preprocessor_config.json +143 -0
- processing.py +54 -0
- special_tokens_map.json +33 -0
- tokenizer.json +0 -0
- tokenizer_config.json +796 -0
- vocab.json +0 -0
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
|
|
|