Views
No views yet
| Tag | Task | Output |
|---|---|---|
<chart2csv> | Chart to CSV | CSV table with headers and numeric values |
<chart2code> | Chart to Python code | Python code that recreates the chart |
<chart2summary> | Chart to summary | Natural-language description of the chart |
<tables_json> | Table extraction (JSON) | Structured JSON with dimensions and cells |
<tables_html> | Table extraction (HTML) | HTML <table> markup |
<tables_otsl> | Table extraction (OTSL) | OTSL markup with cell/merge tags |
| KVP (see prompt instructions below) | Schema based Key-Value pairs extraction | JSON with nested dictionaries and arrays |



1pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu128
2pip install transformers==4.57.6 peft==0.18.1 tokenizers==0.22.2 pillow==12.1.11import re
2from io import StringIO
3
4import pandas as pd
5import torch
6from transformers import AutoProcessor, AutoModelForImageTextToText
7from PIL import Image
8from huggingface_hub import hf_hub_download
9
10model_id = "ibm-granite/granite-4.0-3b-vision"
11device = "cuda" if torch.cuda.is_available() else "cpu"
12
13processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
14model = AutoModelForImageTextToText.from_pretrained(
15 model_id,
16 trust_remote_code=True,
17 dtype=torch.bfloat16,
18 device_map=device
19).eval()
20
21# Optional: merge LoRA adapters into base weights for faster inference.
22# Prefer to skip when using text-only tasks, as the LoRA adapters are vision-specific.
23model.merge_lora_adapters()
24
25def run_inference(model, processor, images, prompts):
26 """Run batched inference on image+prompt pairs (one image per prompt)."""
27 conversations = [
28 [{"role": "user", "content": [
29 {"type": "image"},
30 {"type": "text", "text": prompt},
31 ]}]
32 for prompt in prompts
33 ]
34 texts = [
35 processor.apply_chat_template(conv, tokenize=False, add_generation_prompt=True)
36 for conv in conversations
37 ]
38 inputs = processor(
39 text=texts, images=images, return_tensors="pt", padding=True, do_pad=True
40 ).to(model.device)
41 outputs = model.generate(
42 **inputs,
43 max_new_tokens=4096,
44 use_cache=True
45 )
46 results = []
47 for i in range(len(prompts)):
48 gen = outputs[i, inputs["input_ids"].shape[1]:]
49 results.append(processor.decode(gen, skip_special_tokens=True))
50 return results
51
52
53def display_table(text):
54 """Pretty-print CSV (possibly wrapped in ```csv```) or HTML table content via pandas."""
55 m = re.search(r"```csv\s*
56(.*?)```", text, re.DOTALL)
57 if m:
58 df = pd.read_csv(StringIO(m.group(1)))
59 print(df.to_string(index=False))
60 elif "<table" in text.lower():
61 df = pd.read_html(StringIO(text))[0]
62 print(df.to_string(index=False))
63 else:
64 print(text)1chart_path = hf_hub_download(repo_id=model_id, filename="chart.jpg")
2table_path = hf_hub_download(repo_id=model_id, filename="table.png")
3chart_img = Image.open(chart_path).convert("RGB")
4table_img = Image.open(table_path).convert("RGB")
5
6# Batched chart tasks
7chart_prompts = ["<chart2csv>", "<chart2summary>", "<chart2code>"]
8chart_results = run_inference(model, processor, [chart_img] * len(chart_prompts), chart_prompts)
9for prompt, result in zip(chart_prompts, chart_results):
10 print(f"{prompt}:")
11 display_table(result)
12 print()
13
14# Batched table tasks
15table_prompts = ["<tables_html>", "<tables_otsl>"]
16table_results = run_inference(model, processor, [table_img] * len(table_prompts), table_prompts)
17for prompt, result in zip(table_prompts, table_results):
18 print(f"{prompt}:")
19 display_table(result)
20 print()1import json
2
3invoice_path = hf_hub_download(repo_id=model_id, filename="invoice.png")
4invoice_img = Image.open(invoice_path).convert("RGB")
5schema = {
6 "type": "object",
7 "properties": {
8 "invoice_date": {"type": "string", "description": "The date the invoice was issued"},
9 "order_number": {"type": "string", "description": "The unique identifier for the order"},
10 "seller_tax_id": {"type": "string", "description": "The tax identification number of the seller"},
11 }
12}
13
14prompt = f"""Extract structured data from this document.
15Return a JSON object matching this schema:
16
17{json.dumps(schema, indent=2)}
18
19Return null for fields you cannot find.
20Return ONLY valid JSON.
21Return an instance of the JSON with extracted values, not the schema itself."""
22
23result = run_inference(model, processor, [invoice_img], [prompt])[0]
24print(result)granite4_vision.py) and a server launcher
(start_granite4_vision_server.py) that register the model using vLLM's
out-of-tree model integration—no need to build vLLM from source.1pip install vllm
2export LD_LIBRARY_PATH=$CONDA_PREFIX/lib:$LD_LIBRARY_PATHgranite4_vision.py and start_granite4_vision_server.py from this repo.1hf download ibm-granite/granite-4.0-3b-vision granite4_vision.py .
2hf download ibm-granite/granite-4.0-3b-vision start_granite4_vision_server.py .1python start_granite4_vision_server.py \
2 --model ibm-granite/granite-4.0-3b-vision \
3 --trust_remote_code --host 0.0.0.0 --port 8000 \
4 --hf-overrides '{"adapter_path": "ibm-granite/granite-4.0-3b-vision"}'1python start_granite4_vision_server.py \
2 --model ibm-granite/granite-4.0-3b-vision \
3 --trust_remote_code --host 0.0.0.0 --port 8000 \
4 --enable-lora --max-lora-rank 256 \
5 --default-mm-loras '{"image": "ibm-granite/granite-4.0-3b-vision"}'1import base64
2from openai import OpenAI
3from huggingface_hub import hf_hub_download
4from PIL import Image
5
6model_id = "ibm-granite/granite-4.0-3b-vision"
7client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
8
9def run_inference(client, model_id, image_path, tag):
10 with open(image_path, "rb") as f:
11 image_b64 = base64.b64encode(f.read()).decode("utf-8")
12 messages = [
13 {"role": "user", "content": [
14 {"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_b64}"}},
15 {"type": "text", "text": tag},
16 ]}
17 ]
18 response = client.chat.completions.create(
19 model=model_id, messages=messages, max_tokens=4096, temperature=0,
20 )
21 return response.choices[0].message.content
22
23chart_path = hf_hub_download(repo_id=model_id, filename="chart.jpg")
24table_path = hf_hub_download(repo_id=model_id, filename="table.png")
25
26# Chart tasks
27for tag in ["<chart2csv>", "<chart2summary>", "<chart2code>"]:
28 result = run_inference(client, model_id, chart_path, tag)
29 print(f"{tag}:
30{result}
31")
32
33# Table tasks
34for tag in ["<tables_json>", "<tables_html>", "<tables_otsl>"]:
35 result = run_inference(client, model_id, table_path, tag)
36 print(f"{tag}:
37{result}
38")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.1@misc{granite-4.0-3b-vision,
2 title={Granite 4.0 Vision},
3 author={IBM Granite Vision Team},
4 year={2026},
5 url={https://huggingface.co/ibm-granite/granite-4.0-3b-vision}
6}
7
8@article{kondic2026chartnet,
9 title={ChartNet: A Million-Scale, High-Quality Multimodal Dataset for Robust Chart Understanding},
10 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},
11 journal={arXiv preprint arXiv:2603.27064},
12 year={2026}
13}