{"slug": "unlimited-ocr-one-shot-long-horizon-parsing", "title": "Unlimited OCR: One-shot long-horizon parsing", "summary": "Baidu released Unlimited-OCR, a one-shot long-horizon parsing model that extends DeepSeek-OCR, on June 22, 2026. The open-source model supports single-image and multi-page PDF parsing with configurable image sizes and is available on GitHub and ModelScope.", "body_md": "- [2026/06/23] 📄 Our paper is now available on\n[arXiv](https://arxiv.org/abs/2606.23050). - [2026/06/23] 🤝 Thanks to the ModelScope community for their support. Our model is now available at\n[ModelScope](https://modelscope.cn/models/PaddlePaddle/Unlimited-OCR). - [2026/06/22] 🚀 We present\n[Unlimited-OCR](https://github.com/baidu/Unlimited-OCR), aiming to push[Deepseek-OCR](https://github.com/deepseek-ai/DeepSeek-OCR)one step further.\n\nInference using Huggingface transformers on NVIDIA GPUs. Requirements tested on python 3.12.3 + CUDA12.9：\n\n```\ntorch==2.10.0\ntorchvision==0.25.0\ntransformers==4.57.1\nPillow==12.1.1\nmatplotlib==3.10.8\neinops==0.8.2\naddict==2.4.0\neasydict==1.13\npymupdf==1.27.2.2\npsutil==7.2.2\npython\nimport os\nimport torch\nfrom transformers import AutoModel, AutoTokenizer\n\nmodel_name = 'baidu/Unlimited-OCR'\n\ntokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)\nmodel = AutoModel.from_pretrained(\n    model_name,\n    trust_remote_code=True,\n    use_safetensors=True,\n    torch_dtype=torch.bfloat16,\n)\nmodel = model.eval().cuda()\n\n# ── Single image supports two configs: gundam or base ──\n# gundam: base_size=1024, image_size=640, crop_mode=True\n# base: base_size=1024, image_size=1024, crop_mode=False\nmodel.infer(\n    tokenizer,\n    prompt='<image>document parsing.',\n    image_file='your_image.jpg',\n    output_path='your/output/dir',\n    base_size=1024, image_size=640, crop_mode=True,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=128,\n    save_results=True,\n)\n\n# ── Multi page / PDF only uses base (image_size=1024) ──\nmodel.infer_multi(\n    tokenizer,\n    prompt='<image>Multi page parsing.',\n    image_files=['page1.png', 'page2.png', 'page3.png'],\n    output_path='your/output/dir',\n    image_size=1024,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=1024,\n    save_results=True,\n)\n\n# ── PDF (convert pages to images, then multi-page parsing) ──\nimport tempfile, fitz  # PyMuPDF\n\ndef pdf_to_images(pdf_path, dpi=300):\n    doc = fitz.open(pdf_path)\n    tmp_dir = tempfile.mkdtemp(prefix='pdf_ocr_')\n    mat = fitz.Matrix(dpi / 72, dpi / 72)\n    paths = []\n    for i, page in enumerate(doc):\n        out = os.path.join(tmp_dir, f'page_{i+1:04d}.png')\n        page.get_pixmap(matrix=mat).save(out)\n        paths.append(out)\n    doc.close()\n    return paths\n\nmodel.infer_multi(\n    tokenizer,\n    prompt='<image>Multi page parsing.',\n    image_files=pdf_to_images('your_doc.pdf', dpi=300),\n    output_path='your/output/dir',\n    image_size=1024,\n    max_length=32768,\n    no_repeat_ngram_size=35, ngram_window=1024,\n    save_results=True,\n)\n```\n\nSet up the environment (uv-managed virtualenv). Install the local SGLang wheel first,\nthen pin `kernels==0.9.0`\n\nand install PyMuPDF for PDF-to-image conversion:\n\n```\nuv venv --python 3.12\nsource .venv/bin/activate\n\nuv pip install wheel/sglang-0.0.0.dev11416+g92e8bb79e-py3-none-any.whl\nuv pip install kernels==0.11.7\nuv pip install pymupdf==1.27.2.2\n```\n\nStart the SGLang server:\n\n```\npython -m sglang.launch_server \\\n    --model baidu/Unlimited-OCR \\\n    --served-model-name Unlimited-OCR \\\n    --attention-backend fa3 \\\n    --page-size 1 \\\n    --mem-fraction-static 0.8 \\\n    --context-length 32768 \\\n    --enable-custom-logit-processor \\\n    --disable-overlap-schedule \\\n    --skip-server-warmup \\\n    --host 0.0.0.0 \\\n    --port 10000\n```\n\nSend streaming requests to the OpenAI-compatible API:\n\n``` python\nimport base64\nimport json\nimport os\nimport tempfile\n\nimport fitz\nimport requests\nfrom sglang.srt.sampling.custom_logit_processor import DeepseekOCRNoRepeatNGramLogitProcessor\n\nserver_url = \"http://127.0.0.1:10000\"\n\nsession = requests.Session()\nsession.trust_env = False\n\ndef pdf_to_images(pdf_path, dpi=300):\n    doc = fitz.open(pdf_path)\n    tmp_dir = tempfile.mkdtemp(prefix=\"pdf_ocr_\")\n    mat = fitz.Matrix(dpi / 72, dpi / 72)\n    image_paths = []\n    for i, page in enumerate(doc):\n        image_path = os.path.join(tmp_dir, f\"page_{i + 1:04d}.png\")\n        page.get_pixmap(matrix=mat).save(image_path)\n        image_paths.append(image_path)\n    doc.close()\n    return image_paths\n\ndef encode_image(image_path):\n    ext = os.path.splitext(image_path)[1].lower()\n    mime = \"image/jpeg\" if ext in (\".jpg\", \".jpeg\") else f\"image/{ext.lstrip('.')}\"\n    with open(image_path, \"rb\") as f:\n        data = base64.b64encode(f.read()).decode(\"utf-8\")\n    return {\"type\": \"image_url\", \"image_url\": {\"url\": f\"data:{mime};base64,{data}\"}}\n\ndef build_content(prompt, image_paths):\n    return [{\"type\": \"text\", \"text\": prompt}] + [encode_image(path) for path in image_paths]\n\ndef generate(prompt, image_paths, image_mode, ngram_window):\n    payload = {\n        \"model\": \"Unlimited-OCR\",\n        \"messages\": [{\"role\": \"user\", \"content\": build_content(prompt, image_paths)}],\n        \"temperature\": 0,\n        \"skip_special_tokens\": False,\n        \"images_config\": {\"image_mode\": image_mode},\n        \"custom_logit_processor\": DeepseekOCRNoRepeatNGramLogitProcessor.to_str(),\n        \"custom_params\": {\n            \"ngram_size\": 35,\n            \"window_size\": ngram_window,\n        },\n        \"stream\": True,\n    }\n    response = session.post(\n        f\"{server_url}/v1/chat/completions\",\n        headers={\"Content-Type\": \"application/json\"},\n        data=json.dumps(payload),\n        timeout=1200,\n        stream=True,\n    )\n    response.raise_for_status()\n\n    chunks = []\n    for line in response.iter_lines(chunk_size=1, decode_unicode=True):\n        if not line or not line.startswith(\"data: \"):\n            continue\n        data = line[len(\"data: \"):]\n        if data == \"[DONE]\":\n            break\n        event = json.loads(data)\n        delta = event[\"choices\"][0].get(\"delta\", {}).get(\"content\", \"\")\n        if delta:\n            print(delta, end=\"\", flush=True)\n            chunks.append(delta)\n    print()\n    return \"\".join(chunks)\n\n# Single image supports two configs: gundam or base. Example below uses gundam.\ngenerate(\"document parsing.\", [\"your_image.jpg\"], image_mode=\"gundam\", ngram_window=128)\n\n# Multi image (base only)\ngenerate(\"Multi page parsing.\", [\"page1.png\", \"page2.png\"], image_mode=\"base\", ngram_window=1024)\n\n# PDF (base only)\ngenerate(\"Multi page parsing.\", pdf_to_images(\"your_doc.pdf\", dpi=300), image_mode=\"base\", ngram_window=1024)\n```\n\nFor batch inference, `infer.py`\n\nstarts the SGLang server automatically and sends concurrent requests for an image directory or PDF:\n\n```\n# Image directory\npython infer.py \\\n    --image_dir ./examples/images \\\n    --output_dir ./outputs \\\n    --concurrency 8 \\\n    --image_mode gundam\n\n# PDF pages\npython infer.py \\\n    --pdf ./examples/document.pdf \\\n    --output_dir ./outputs \\\n    --concurrency 8 \\\n    --image_mode gundam\n```\n\nUseful options:\n\n```\n--model_dir baidu/Unlimited-OCR   # Local path or Hugging Face model ID\n--gpu 0                           # CUDA_VISIBLE_DEVICES value\n--server_log ./log/sglang_server.log\n```\n\nWe 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.\n\n```\n@misc{yin2026unlimitedocrworks,\n      title={Unlimited OCR Works}, \n      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},\n      year={2026},\n      eprint={2606.23050},\n      archivePrefix={arXiv},\n      primaryClass={cs.CV},\n      url={https://arxiv.org/abs/2606.23050}, \n}\n```\n\n", "url": "https://wpnews.pro/news/unlimited-ocr-one-shot-long-horizon-parsing", "canonical_source": "https://github.com/baidu/Unlimited-OCR", "published_at": "2026-06-23 11:35:05+00:00", "updated_at": "2026-06-23 23:46:23.309511+00:00", "lang": "en", "topics": ["artificial-intelligence", "computer-vision", "large-language-models", "ai-products", "ai-tools"], "entities": ["Baidu", "DeepSeek", "ModelScope", "GitHub", "Hugging Face", "NVIDIA", "PyMuPDF", "SGLang"], "alternates": {"html": "https://wpnews.pro/news/unlimited-ocr-one-shot-long-horizon-parsing", "markdown": "https://wpnews.pro/news/unlimited-ocr-one-shot-long-horizon-parsing.md", "text": "https://wpnews.pro/news/unlimited-ocr-one-shot-long-horizon-parsing.txt", "jsonld": "https://wpnews.pro/news/unlimited-ocr-one-shot-long-horizon-parsing.jsonld"}}