baidu/Unlimited-OCR

Unlimited OCR Works: Welcome the Era of One-shot Long-horizon Parsing.

13,868
GitHub 스타
1,150
포크
Python
언어
MIT
라이선스
2026.07.03
최근 푸시
2026.06.24
별표한 날

AI 분석

설치 난이도: 보통
큐레이터 노트
장기간 문서 파싱이 필요한 OCR 작업에 적합하며, 특히 여러 페이지 문서나 PDF를 한 번에 처리해야 하는 경우 유용합니다. 다양한 추론 백엔드를 지원하여 프로덕션 환경에 통합하기 좋습니다.

강점

  • 원샷 장기간 파싱(One-shot Long-horizon Parsing)을 지원하여 긴 문서를 한 번에 처리할 수 있습니다.
  • Transformers, vLLM, SGLang 등 다양한 추론 백엔드를 지원하여 유연하게 배포할 수 있습니다.
  • 단일 이미지와 여러 페이지/PDF를 모두 처리할 수 있으며, gundam과 base 두 가지 설정을 제공합니다.

약점

  • README에 모델 아키텍처나 학습 방법에 대한 상세한 설명이 부족합니다.
  • 지원되는 언어나 OCR 정확도에 대한 벤치마크 결과가 제공되지 않습니다.
  • 의존성 패키지 버전이 고정되어 있어 호환성 문제가 발생할 수 있습니다.

주의사항

  • 모델 크기와 추론 시간이 클 수 있으므로 충분한 GPU 메모리가 필요합니다.
  • vLLM 및 SGLang 사용 시 Docker 이미지나 환경 설정이 복잡할 수 있습니다.
  • PDF 처리 시 PyMuPDF(fitz)를 사용하므로 추가 라이브러리 설치가 필요합니다.

시작 가이드

  • 공식 문서와 논문을 읽어 모델의 세부 사항과 성능을 파악합니다.
  • 제공된 예제 코드를 실행하여 기본적인 추론을 테스트합니다.
  • 자신의 데이터셋에 맞게 프롬프트와 설정을 조정하여 파인튜닝을 고려합니다.

README 한국어 번역

이 번역은 AI가 원문 README를 옮긴 것입니다. 원문이 항상 우선합니다.

<p align="center"> <img src="assets/baidu.png" width="40%" 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://arxiv.org/abs/2606.23050"> <img alt="arXiv" src="https://img.shields.io/badge/arXiv-Unlimited OCR Works-b31b1b?logo=arxiv&logoColor=white" /> </a> <a href="https://x.com/BaiduInc" 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">원샷 장기간 파싱 시대를 맞이합니다.</h3>

<p align="center"> <img src="assets/Unlimited-OCR.png" width="1000" alt="Unlimited OCR 개요" /> </p>

릴리스

  • [2026/06/28] 🤝 vLLM 커뮤니티Tianyu Guo의 지원 덕분에, 이제 모델이 vLLM 추론을 지원합니다.
  • [2026/06/24] 🤝 AK가 데모를 만들어 주셨습니다. 이제 Hugging Face Spaces에서 사용 가능합니다.
  • [2026/06/23] 📄 논문이 arXiv에 공개되었습니다.
  • [2026/06/23] 🤝 ModelScope 커뮤니티의 지원 덕분에, 모델이 ModelScope에서도 사용 가능합니다.
  • [2026/06/22] 🚀 Unlimited-OCR을 발표합니다. Deepseek-OCR을 한 단계 더 발전시키는 것을 목표로 합니다.

추론

Transformers

NVIDIA GPU에서 Huggingface transformers를 사용한 추론. 요구 사항은 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
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()

# ── 단일 이미지는 gundam 또는 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,
)

# ── 여러 페이지 / PDF는 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 (페이지를 이미지로 변환한 후 여러 페이지 파싱) ──
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,
)

vLLM

배포 세부 사항은 공식 vLLM 레시피를 참조하십시오: 레시피: https://recipes.vllm.ai/baidu/Unlimited-OCR

Docker 이미지

GPU 플랫폼에 따라 다음 Docker 이미지를 사용하십시오:

기본 (CUDA 13.0):

docker pull vllm/vllm-openai:unlimited-ocr

Hopper GPU용 (CUDA 12.9)

docker pull vllm/vllm-openai:unlimited-ocr-cu129

SGLang

환경 설정 (uv 관리 virtualenv). 먼저 로컬 SGLang wheel을 설치한 다음, kernels==0.9.0을 고정하고 PDF를 이미지로 변환하기 위해 PyMuPDF를 설치하십시오:

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

SGLang 서버 시작:

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

OpenAI 호환 API로 스트리밍 요청 보내기:

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)

# 단일 이미지는 gundam 또는 base 두 가지 설정을 지원합니다. 아래 예제는 gundam을 사용합니다.
generate("document parsing.", ["your_image.jpg"], image_mode="gundam", ngram_window=128)

# 여러 이미지 (base만)
generate("Multi page parsing.", ["page1.png", "page2.png"], image_mode="base", ngram_window=1024)

# PDF (base만)
generate("Multi page parsing.", pdf_to_images("your_doc.pdf", dpi=300), image_mode="base", ngram_window=1024)

배치 추론의 경우, infer.py가 SGLang 서버를 자동으로 시작하고 이미지 디렉토리 또는 PDF에 대해 동시 요청을 보냅니다:

# 이미지 디렉토리
python infer.py \
    --image_dir./examples/images \
    --output_dir./outputs \
    --concurrency 8 \
    --image_mode gundam

# PDF 페이지
python infer.py \
    --pdf./examples/document.pdf \
    --output_dir./outputs \
    --concurrency 8 \
    --image_mode gundam

유용한 옵션:

--model_dir baidu/Unlimited-OCR   # 로컬 경로 또는 Hugging Face 모델 ID
--gpu 0                           # CUDA_VISIBLE_DEVICES 값
--server_log./log/sglang_server.log

시각화

<img src="assets/long-horizon-ocr.gif" width="100%" alt="장기간 OCR 데모" />

감사의 말

Deepseek-OCR, Deepseek-OCR-2, PaddleOCR의 귀중한 모델과 아이디어에 감사드립니다.

인용

@misc{yin2026unlimitedocrworks,
      title={Unlimited OCR Works},
      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},
      year={2026},
      eprint={2606.23050},
      archivePrefix={arXiv},
      primaryClass={cs.CV},
      url={https://arxiv.org/abs/2606.23050},
}

원본 저장소: baidu/Unlimited-OCR

라이선스: MIT

게재 제외를 원하시면 삭제 요청을 보내주세요.