Image-Text-to-Text
Transformers
Safetensors
multilingual
unlimited-ocr
feature-extraction
baidu
vision-language
ocr
custom_code
Instructions to use suryatmodulus/Unlimited-OCR with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use suryatmodulus/Unlimited-OCR with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="suryatmodulus/Unlimited-OCR", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("suryatmodulus/Unlimited-OCR", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use suryatmodulus/Unlimited-OCR with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "suryatmodulus/Unlimited-OCR" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "suryatmodulus/Unlimited-OCR", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/suryatmodulus/Unlimited-OCR
- SGLang
How to use suryatmodulus/Unlimited-OCR 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 "suryatmodulus/Unlimited-OCR" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "suryatmodulus/Unlimited-OCR", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'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 "suryatmodulus/Unlimited-OCR" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "suryatmodulus/Unlimited-OCR", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use suryatmodulus/Unlimited-OCR with Docker Model Runner:
docker model run hf.co/suryatmodulus/Unlimited-OCR
| pipeline_tag: image-text-to-text | |
| language: | |
| - multilingual | |
| tags: | |
| - baidu | |
| - vision-language | |
| - ocr | |
| - custom_code | |
| license: mit | |
| library_name: transformers | |
| <p align="center"> | |
| <img src="assets/baidu.png" width="55%" alt="Baidu Inc." /> | |
| </p> | |
| <hr> | |
| <h1 align="center">Unlimited OCR Works</h1> | |
| <div align="center"> | |
| <a href="https://github.com/baidu/Unlimited-OCR"> | |
| <img alt="GitHub" src="https://img.shields.io/badge/GitHub-Code-181717?logo=github&logoColor=white" /> | |
| </a> | |
| <a href="https://huggingface.co/baidu/Unlimited-OCR"> | |
| <img alt="Hugging Face" src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Model-ffc107?color=ffc107&logoColor=white" /> | |
| </a> | |
| </div> | |
| <div align="center"> | |
| <a href="https://huggingface.co/baidu/Unlimited-OCR/blob/main/Unlimited-OCR.pdf"> | |
| <img alt="arXiv" src="https://img.shields.io/badge/arXiv-Unlimited OCR Works-b31b1b?logo=arxiv&logoColor=white" /> | |
| </a> | |
| <a href="https://x.com/Baidu_Inc" target="_blank"> | |
| <img alt="Twitter Follow" src="https://img.shields.io/badge/Twitter-Baidu Inc.-white?logo=x&logoColor=white" /> | |
| </a> | |
| </div> | |
| <h3 align="center">Welcome the Era of One-shot Long-horizon Parsing.</h3> | |
| <p align="center"> | |
| <img src="assets/Unlimited-OCR.png" width="1000" alt="Unlimited OCR overview" /> | |
| </p> | |
| ## Release | |
| - [2026/06/22] 🚀 We present [Unlimited-OCR](https://github.com/baidu/Unlimited-OCR), aiming to push [Deepseek-OCR](https://github.com/deepseek-ai/DeepSeek-OCR) one step further. | |
| - [2026/06/23] 🤝 Thanks to the ModelScope community for their support. Our model is now available at [ModelScope](https://modelscope.cn/models/PaddlePaddle/Unlimited-OCR). | |
| ## Inference | |
| ### Transformers | |
| Inference using Huggingface transformers on NVIDIA GPUs. Requirements tested on python 3.12.3 + CUDA12.9: | |
| ``` | |
| 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.2 | |
| ``` | |
| ```python | |
| import os | |
| import torch | |
| from transformers import AutoModel, AutoTokenizer | |
| model_name = 'baidu/Unlimited-OCR' | |
| tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True) | |
| model = AutoModel.from_pretrained( | |
| model_name, | |
| trust_remote_code=True, | |
| use_safetensors=True, | |
| torch_dtype=torch.bfloat16, | |
| ) | |
| model = model.eval().cuda() | |
| # ── Single image supports two configs: gundam or base ── | |
| # gundam: base_size=1024, image_size=640, crop_mode=True | |
| # base: base_size=1024, image_size=1024, crop_mode=False | |
| model.infer( | |
| tokenizer, | |
| prompt='<image>document parsing.', | |
| image_file='your_image.jpg', | |
| output_path='your/output/dir', | |
| base_size=1024, image_size=640, crop_mode=True, | |
| max_length=32768, | |
| no_repeat_ngram_size=35, ngram_window=128, | |
| save_results=True, | |
| ) | |
| # ── Multi page / PDF only uses base (image_size=1024) ── | |
| model.infer_multi( | |
| tokenizer, | |
| prompt='<image>Multi page parsing.', | |
| image_files=['page1.png', 'page2.png', 'page3.png'], | |
| output_path='your/output/dir', | |
| image_size=1024, | |
| max_length=32768, | |
| no_repeat_ngram_size=35, ngram_window=1024, | |
| save_results=True, | |
| ) | |
| # ── PDF (convert pages to images, then multi-page parsing) ── | |
| import tempfile, fitz # PyMuPDF | |
| def pdf_to_images(pdf_path, dpi=300): | |
| doc = fitz.open(pdf_path) | |
| tmp_dir = tempfile.mkdtemp(prefix='pdf_ocr_') | |
| mat = fitz.Matrix(dpi / 72, dpi / 72) | |
| paths = [] | |
| for i, page in enumerate(doc): | |
| out = os.path.join(tmp_dir, f'page_{i+1:04d}.png') | |
| page.get_pixmap(matrix=mat).save(out) | |
| paths.append(out) | |
| doc.close() | |
| return paths | |
| model.infer_multi( | |
| tokenizer, | |
| prompt='<image>Multi page parsing.', | |
| image_files=pdf_to_images('your_doc.pdf', dpi=300), | |
| output_path='your/output/dir', | |
| image_size=1024, | |
| max_length=32768, | |
| no_repeat_ngram_size=35, ngram_window=1024, | |
| save_results=True, | |
| ) | |
| ``` | |
| ### SGLang | |
| Set up the environment (uv-managed virtualenv). Install the local SGLang wheel first, | |
| then pin `kernels==0.9.0` and install PyMuPDF for PDF-to-image conversion: | |
| ```shell | |
| uv venv --python 3.12 | |
| source .venv/bin/activate | |
| uv pip install wheel/sglang-0.0.0.dev11416+g92e8bb79e-py3-none-any.whl | |
| uv pip install kernels==0.11.7 | |
| uv pip install pymupdf==1.27.2.2 | |
| ``` | |
| Start the SGLang server: | |
| ```shell | |
| python -m sglang.launch_server \ | |
| --model baidu/Unlimited-OCR \ | |
| --served-model-name Unlimited-OCR \ | |
| --attention-backend fa3 \ | |
| --page-size 1 \ | |
| --mem-fraction-static 0.8 \ | |
| --context-length 32768 \ | |
| --enable-custom-logit-processor \ | |
| --disable-overlap-schedule \ | |
| --skip-server-warmup \ | |
| --host 0.0.0.0 \ | |
| --port 10000 | |
| ``` | |
| Send streaming requests to the OpenAI-compatible API: | |
| ```python | |
| import base64 | |
| import json | |
| import os | |
| import tempfile | |
| import fitz | |
| import requests | |
| from sglang.srt.sampling.custom_logit_processor import DeepseekOCRNoRepeatNGramLogitProcessor | |
| server_url = "http://127.0.0.1:10000" | |
| session = requests.Session() | |
| session.trust_env = False | |
| def pdf_to_images(pdf_path, dpi=300): | |
| doc = fitz.open(pdf_path) | |
| tmp_dir = tempfile.mkdtemp(prefix="pdf_ocr_") | |
| mat = fitz.Matrix(dpi / 72, dpi / 72) | |
| image_paths = [] | |
| for i, page in enumerate(doc): | |
| image_path = os.path.join(tmp_dir, f"page_{i + 1:04d}.png") | |
| page.get_pixmap(matrix=mat).save(image_path) | |
| image_paths.append(image_path) | |
| doc.close() | |
| return image_paths | |
| def encode_image(image_path): | |
| ext = os.path.splitext(image_path)[1].lower() | |
| mime = "image/jpeg" if ext in (".jpg", ".jpeg") else f"image/{ext.lstrip('.')}" | |
| with open(image_path, "rb") as f: | |
| data = base64.b64encode(f.read()).decode("utf-8") | |
| return {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{data}"}} | |
| def build_content(prompt, image_paths): | |
| return [{"type": "text", "text": prompt}] + [encode_image(path) for path in image_paths] | |
| def generate(prompt, image_paths, image_mode, ngram_window): | |
| payload = { | |
| "model": "Unlimited-OCR", | |
| "messages": [{"role": "user", "content": build_content(prompt, image_paths)}], | |
| "temperature": 0, | |
| "skip_special_tokens": False, | |
| "images_config": {"image_mode": image_mode}, | |
| "custom_logit_processor": DeepseekOCRNoRepeatNGramLogitProcessor.to_str(), | |
| "custom_params": { | |
| "ngram_size": 35, | |
| "window_size": ngram_window, | |
| }, | |
| "stream": True, | |
| } | |
| response = session.post( | |
| f"{server_url}/v1/chat/completions", | |
| headers={"Content-Type": "application/json"}, | |
| data=json.dumps(payload), | |
| timeout=1200, | |
| stream=True, | |
| ) | |
| response.raise_for_status() | |
| chunks = [] | |
| for line in response.iter_lines(chunk_size=1, decode_unicode=True): | |
| if not line or not line.startswith("data: "): | |
| continue | |
| data = line[len("data: "):] | |
| if data == "[DONE]": | |
| break | |
| event = json.loads(data) | |
| delta = event["choices"][0].get("delta", {}).get("content", "") | |
| if delta: | |
| print(delta, end="", flush=True) | |
| chunks.append(delta) | |
| print() | |
| return "".join(chunks) | |
| # Single image supports two configs: gundam or base. Example below uses gundam. | |
| generate("document parsing.", ["your_image.jpg"], image_mode="gundam", ngram_window=128) | |
| # Multi image (base only) | |
| generate("Multi page parsing.", ["page1.png", "page2.png"], image_mode="base", ngram_window=1024) | |
| # PDF (base only) | |
| generate("Multi page parsing.", pdf_to_images("your_doc.pdf", dpi=300), image_mode="base", ngram_window=1024) | |
| ``` | |
| ## Visualization | |
| <img src="assets/long-horizon-ocr.gif" width="100%" alt="Long-horizon OCR demo" /> | |
| ## Acknowledgement | |
| We would like to thank [Deepseek-OCR](https://github.com/deepseek-ai/DeepSeek-OCR), [Deepseek-OCR-2](https://github.com/deepseek-ai/DeepSeek-OCR-2), [PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR) for their valuable models and ideas. | |
| ## Citation | |
| Coming soon! | |
| <!-- ```bibtex | |
| @article{, | |
| title={Unlimited OCR Works}, | |
| author={}, | |
| journal={arXiv preprint arXiv:}, | |
| year={2026} | |
| } --> |