baidu/Unlimited-OCR-2
Captured source
source ↗Unlimited OCR Works 2
Pioneering the OCR-3.0 Era: From Long- to Unlimited-Horizon Parsing.
Release
- [2026/10/27] 🚀 We release **Unlimited OCR 2**, achieving unlimited-horizon parsing with SR-SWA.
- [2026/07/21] 🤝 Thanks to the ms-swift community for their support, our model now supports training with ms-swift.
- [2026/07/03] 🤝 Thanks to the Baidu Cloud team for their support. Our model is now available on Baidu Cloud.
- [2026/06/28] 🤝 Thanks to the vLLM community and Tianyu Guo for their support, our model now supports vLLM inference.
- [2026/06/24] 🤝 Thanks to AK for creating a demo for us. It is now available at Hugging Face Spaces.
- [2026/06/23] 📄 Our paper is now available on arXiv.
- [2026/06/23] 🤝 Thanks to the ModelScope community for their support. Our model is now available at ModelScope.
- [2026/06/22] 🚀 We present Unlimited-OCR, aiming to push Deepseek-OCR one step further.
What's New in 2
- Sparse Reference Sliding Window Attention (SR-SWA): Compresses text-visual attention interactions from ultra-long sequences down to a fixed-size set of working references (e.g., 512 tokens). This bounds computational complexity, keeping per-step decoding latency and memory footprint nearly constant regardless of document length.
- From Long- to Unlimited-Horizon Parsing: Powered by SR-SWA, Unlimited-OCR 2 achieves true, unbounded document parsing within a finite context window—effectively eliminating quadratic attention scaling and memory bottlenecks as documents grow.
- Ultra-Long Document Parsing SOTA: Achieves state-of-the-art performance across both dozens-of-pages benchmarks (e.g., MPDocBench) and extreme hundred-page benchmarks (e.g., MarathonDocBench).
Inference
> Unlimited OCR 2 supports Transformers (native, for quick tests) and SGLang (recommended for serving).
Transformers
Tested with Python 3.10, torch==2.13.0, transformers==4.52.1, huggingface-hub==0.36.0, tokenizers==0.21.4, on an NVIDIA A800-80GB:
pip install torch==2.13.0 torchvision pillow transformers==4.52.1 huggingface-hub==0.36.0 \ tokenizers==0.21.4 addict==2.4.0 einops==0.8.2 easydict==1.13
Load the model once:
import torch from transformers import AutoModel, AutoTokenizer model_name = "baidu/Unlimited-OCR-2" 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).eval().cuda()
Multi-page inference (infer_multi). All pages of a document are parsed in one request, so the model can use cross-page context. Pass the page images in page order:
pages = [f"your_doc/page_{i}.jpg" for i in range(1, 8)]
text, num_tokens = model.infer_multi(tokenizer, image_files=pages,
output_path="output/multi", save_results=True)The prompt is built automatically as "" * num_pages + "Multi page parsing.", and each page is encoded as one global view (base mode). The output contains one ` per input page, in the same order as image_files`.
Single-page inference (infer). A single page is encoded with dynamic tiling (gundam mode) by default:
text = model.infer(tokenizer, image_file="your_doc/page_1.jpg", output_path="output/single", save_results=True)
SGLang
Set up the environment (uv-managed virtualenv, Python 3.10) and install the customized SGLang wheel sglang-0.5.20.dev10+g8d62f5fb9c-py3-none-any.whl, plus PyMuPDF for PDF-to-image conversion:
uv venv --python 3.10 source .venv/bin/activate uv pip install wheel/sglang-0.5.20.dev10+g8d62f5fb9c-py3-none-any.whl uv pip install pymupdf==1.27.2.2 uv pip install fastokens==0.3.2
Start the SGLang server:
# Page-window scheduling for very long documents (the KV tail of the previous window is reused).
export SGLANG_UOCR_EANABLE_DOC_LIMIT=1 # 1 = enable, 0 = whole document in one window
export SGLANG_UOCR_DOC_GUNDAM_PAGE_WINDOW=10 # pages per window (gundam mode)
export SGLANG_UOCR_DOC_BASE_PAGE_WINDOW=10 # pages per window (base mode)
export SGLANG_UOCR_MAX_PAGE_TOKENS=20000 # per-page output cap; must be > 0
# Chunk cap for the SAM attention bias. The built-in default (512) allows a single
# ~462 MiB allocation and can OOM; 64 is equivalent with a lower peak.
export SGLANG_OPT_UOCR_SAM_REL_POS_BIAS_MB=64
# Pass large crop tensors through /dev/shm instead of pickling them into the
# tokenizer -> scheduler frame.
export SGLANG_UOCR_SHM_WRAP_MODEL_DATA=1
export SGLANG_UOCR_SHM_WRAP_MIN_MB=1
export SGLANG_VLM_CACHE_SIZE_MB=0
# Reduces fragmentation failures on the large contiguous allocations.
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True
python -m sglang.launch_server \
--model-path baidu/Unlimited-OCR-2 \
--served-model-name Unlimited-OCR-2 \
--chat-template unlimited-ocr \
--tokenizer-backend fastokens \
--tokenizer-worker-num 8 \
--mem-fraction-static 0.7 \
--max-running-requests 64 \
--max-prefill-tokens 2048 \
--enable-custom-logit-processor \
--enable-streaming-session \
--allow-auto-truncate \
--disable-radix-cache \
--mm-preprocess-cache-size-mb 0 \
--cuda-graph-backend-decode full --cuda-graph-max-bs-decode 64 \
--cuda-graph-backend-prefill full \
--cuda-graph-max-bs-prefill 16384 \
--cuda-graph-bs-prefill 1024 2048 \
--cuda-graph-config '{"prefill": {"backend": "full", "full_prefill_max_req": 64}}' \
--host 0.0.0.0 \
--port 10000Notes on the knobs that matter for memory:
--mem-fraction-staticis the share reserved for weights + KV.0.75leaves too little headroom at 32+ concurrent requests;0.7is stable.--max-prefill-tokensdrives a temporary tensor of roughly[tokens, context/32], so memory grows linearly with it:4096 -> 2048halves that peak.- The largest
--cuda-graph-bs-prefillbucket must equal--max-prefill-tokens. A smaller one makes oversized batches fall back to eager; a larger one is never...
Excerpt shown — open the source for the full document.
Notability
notability 7.0/10Baidu released a new OCR model version.