Views
No views yet


torch==2.10.0
torchvision==0.25.0
transformers==4.57.1
Pillow==12.1.1
matplotlib==3.10.8
einops==0.8.2
addict==2.4.0
easydict==1.13
pymupdf==1.27.2.2
psutil==7.2.21import os
2import torch
3from transformers import AutoModel, AutoTokenizer
4
5model_name = 'baidu/Unlimited-OCR'
6
7tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
8model = AutoModel.from_pretrained(
9 model_name,
10 trust_remote_code=True,
11 use_safetensors=True,
12 torch_dtype=torch.bfloat16,
13)
14model = model.eval().cuda()
15
16# ── Single image supports two configs: gundam or base ──
17# gundam: base_size=1024, image_size=640, crop_mode=True
18# base: base_size=1024, image_size=1024, crop_mode=False
19model.infer(
20 tokenizer,
21 prompt='<image>document parsing.',
22 image_file='your_image.jpg',
23 output_path='your/output/dir',
24 base_size=1024, image_size=640, crop_mode=True,
25 max_length=32768,
26 no_repeat_ngram_size=35, ngram_window=128,
27 save_results=True,
28)
29
30# ── Multi page / PDF only uses base (image_size=1024) ──
31model.infer_multi(
32 tokenizer,
33 prompt='<image>Multi page parsing.',
34 image_files=['page1.png', 'page2.png', 'page3.png'],
35 output_path='your/output/dir',
36 image_size=1024,
37 max_length=32768,
38 no_repeat_ngram_size=35, ngram_window=1024,
39 save_results=True,
40)
41
42# ── PDF (convert pages to images, then multi-page parsing) ──
43import tempfile, fitz # PyMuPDF
44
45def pdf_to_images(pdf_path, dpi=300):
46 doc = fitz.open(pdf_path)
47 tmp_dir = tempfile.mkdtemp(prefix='pdf_ocr_')
48 mat = fitz.Matrix(dpi / 72, dpi / 72)
49 paths = []
50 for i, page in enumerate(doc):
51 out = os.path.join(tmp_dir, f'page_{i+1:04d}.png')
52 page.get_pixmap(matrix=mat).save(out)
53 paths.append(out)
54 doc.close()
55 return paths
56
57model.infer_multi(
58 tokenizer,
59 prompt='<image>Multi page parsing.',
60 image_files=pdf_to_images('your_doc.pdf', dpi=300),
61 output_path='your/output/dir',
62 image_size=1024,
63 max_length=32768,
64 no_repeat_ngram_size=35, ngram_window=1024,
65 save_results=True,
66)docker pull vllm/vllm-openai:unlimited-ocrdocker pull vllm/vllm-openai:unlimited-ocr-cu129kernels==0.9.0 and install PyMuPDF for PDF-to-image conversion:1uv venv --python 3.12
2source .venv/bin/activate
3
4uv pip install wheel/sglang-0.0.0.dev11416+g92e8bb79e-py3-none-any.whl
5uv pip install kernels==0.11.7
6uv pip install pymupdf==1.27.2.21python -m sglang.launch_server \
2 --model baidu/Unlimited-OCR \
3 --served-model-name Unlimited-OCR \
4 --attention-backend fa3 \
5 --page-size 1 \
6 --mem-fraction-static 0.8 \
7 --context-length 32768 \
8 --enable-custom-logit-processor \
9 --disable-overlap-schedule \
10 --skip-server-warmup \
11 --host 0.0.0.0 \
12 --port 100001import base64
2import json
3import os
4import tempfile
5
6import fitz
7import requests
8from sglang.srt.sampling.custom_logit_processor import DeepseekOCRNoRepeatNGramLogitProcessor
9
10server_url = "http://127.0.0.1:10000"
11
12session = requests.Session()
13session.trust_env = False
14
15
16def pdf_to_images(pdf_path, dpi=300):
17 doc = fitz.open(pdf_path)
18 tmp_dir = tempfile.mkdtemp(prefix="pdf_ocr_")
19 mat = fitz.Matrix(dpi / 72, dpi / 72)
20 image_paths = []
21 for i, page in enumerate(doc):
22 image_path = os.path.join(tmp_dir, f"page_{i + 1:04d}.png")
23 page.get_pixmap(matrix=mat).save(image_path)
24 image_paths.append(image_path)
25 doc.close()
26 return image_paths
27
28
29def encode_image(image_path):
30 ext = os.path.splitext(image_path)[1].lower()
31 mime = "image/jpeg" if ext in (".jpg", ".jpeg") else f"image/{ext.lstrip('.')}"
32 with open(image_path, "rb") as f:
33 data = base64.b64encode(f.read()).decode("utf-8")
34 return {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{data}"}}
35
36
37def build_content(prompt, image_paths):
38 return [{"type": "text", "text": prompt}] + [encode_image(path) for path in image_paths]
39
40
41def generate(prompt, image_paths, image_mode, ngram_window):
42 payload = {
43 "model": "Unlimited-OCR",
44 "messages": [{"role": "user", "content": build_content(prompt, image_paths)}],
45 "temperature": 0,
46 "skip_special_tokens": False,
47 "images_config": {"image_mode": image_mode},
48 "custom_logit_processor": DeepseekOCRNoRepeatNGramLogitProcessor.to_str(),
49 "custom_params": {
50 "ngram_size": 35,
51 "window_size": ngram_window,
52 },
53 "stream": True,
54 }
55 response = session.post(
56 f"{server_url}/v1/chat/completions",
57 headers={"Content-Type": "application/json"},
58 data=json.dumps(payload),
59 timeout=1200,
60 stream=True,
61 )
62 response.raise_for_status()
63
64 chunks = []
65 for line in response.iter_lines(chunk_size=1, decode_unicode=True):
66 if not line or not line.startswith("data: "):
67 continue
68 data = line[len("data: "):]
69 if data == "[DONE]":
70 break
71 event = json.loads(data)
72 delta = event["choices"][0].get("delta", {}).get("content", "")
73 if delta:
74 print(delta, end="", flush=True)
75 chunks.append(delta)
76 print()
77 return "".join(chunks)
78
79
80# Single image supports two configs: gundam or base. Example below uses gundam.
81generate("document parsing.", ["your_image.jpg"], image_mode="gundam", ngram_window=128)
82
83# Multi image (base only)
84generate("Multi page parsing.", ["page1.png", "page2.png"], image_mode="base", ngram_window=1024)
85
86# PDF (base only)
87generate("Multi page parsing.", pdf_to_images("your_doc.pdf", dpi=300), image_mode="base", ngram_window=1024)1def remove_det(raw: str) -> str:
2 """
3 Strip <|det|>type [bbox]<|/det|> markers, group lines belonging to the
4 same block with \\n, and separate different blocks with \\n\\n.
5 """
6 blocks = []
7 cur = None
8 for line in raw.splitlines():
9 line = line.rstrip()
10 if not line:
11 continue
12 m = DET_RE.match(line)
13 if m:
14 category, content = m.group(1).strip(), m.group(2).strip()
15 if category == 'image':
16 continue
17 if cur is not None:
18 blocks.append(cur)
19 cur = [content] if content else []
20 continue
21 if cur is None:
22 cur = []
23 cur.append(line)
24 if cur is not None:
25 blocks.append(cur)
26 text = '\n\n'.join('\n'.join(b) for b in blocks).strip()
27 return text
1@misc{yin2026unlimitedocrworks,
2 title={Unlimited OCR Works},
3 author={Youyang Yin and Huanhuan Liu and YY and Qunyi Xie and Chaorun Liu and Shiqi Yang and Shaohua Wang and Zhanlong Liu and Hao Zou and Jinyue Chen and Shu Wei and Jingjing Wu and Mingxin Huang and Zhen Wu and Guibin Wang and Tengyu Du and Lei Jia},
4 year={2026},
5 eprint={2606.23050},
6 archivePrefix={arXiv},
7 primaryClass={cs.CV},
8 url={https://arxiv.org/abs/2606.23050},
9}