Unlimited-OCR: GPU 과부하 없이 40페이지 PDF를 한 번에 파싱하기
요약
Baidu가 공개한 Unlimited-OCR은 Reference Sliding Window Attention(R-SWA) 기술을 통해 KV 캐시 급증 문제를 해결한 문서 파싱 모델입니다. 단 한 번의 포워드 패스로 수십 페이지의 PDF를 메모리 효율적으로 파싱할 수 있습니다.
핵심 포인트
- R-SWA 기술로 KV 캐시 크기를 일정하게 유지하여 메모리 사용량 최적화
- 32K의 최대 출력 길이를 지원하여 다중 페이지 단일 패스 파싱 가능
- MoE 구조를 채택하여 3B 파라미터 대비 낮은 추론 연산 비용 제공
- Transformers, SGLang, Docker 등 다양한 실행 환경 지원
문서 파싱 (document-parsing) 파이프라인을 구축해 본 적이 있다면, 그 반복되는 과정을 잘 알고 있을 것입니다. PDF를 페이지별로 나눕니다. 각 페이지를 OCR 모델에 통과시킵니다. 출력된 결과물들을 다시 하나로 합칩니다. 그런 다음, 페이지 경계에서 잘려 나간 표, 섹션을 잃어버린 제목, 그리고 참조 지점에서 세 페이지나 떨어진 곳에 고립되어 버린 각주를 수정하기 위해 엄청난 양의 글루 코드 (glue code)를 작성해야 합니다.
Baidu의 Unlimited-OCR은 이러한 과정을 전혀 거칠 필요가 없어야 한다는 가설에 기반한 프로젝트입니다. 이 모델은 단 한 번의 포워드 패스 (forward pass)로 수십 페이지를 파싱하며, MIT 라이선스를 따릅니다.
이 포스트에서는 이 모델이 실제로 무엇을 다르게 수행하는지 다루고, 이어서 모델을 실행할 수 있는 세 가지 구체적인 방법을 소개합니다: 빠른 Transformers 스크립트, 실제 처리량 (throughput)을 위한 SGLang 서버, 그리고 Python 환경을 전혀 건드리고 싶지 않은 분들을 위한 Docker 이미지입니다.
이 모델이 해결하는 문제
표준 트랜스포머 디코딩 (transformer decoding)에는 대부분의 OCR 벤치마크가 조용히 숨기고 있는 비용이 있습니다: 바로 생성되는 토큰이 늘어날수록 KV 캐시 (KV cache)가 증가한다는 점입니다.
KV 캐시는 모델의 단기 기억입니다. 모델이 생성하는 모든 토큰은 미래의 토큰이 과거를 참조 (attend)할 수 있도록 캐시에 추가됩니다. 세 단락 정도를 작성하는 챗봇에게는 이 방식이 괜찮습니다. 하지만 40페이지 분량의 기술 매뉴얼을 30,000개의 Markdown 토큰으로 전사 (transcribing)하는 OCR 모델에게는 그렇지 않습니다. 메모리 사용량이 급증하고, 그에 따라 어텐션 (attention) 비용도 상승하며, 실행 시간이 길어질수록 생성 속도는 느려집니다. 8페이지쯤 되면 처리량 그래프가 직선이 아니라 절벽처럼 떨어지기 시작할 것입니다.
업계의 임시방편은 청킹 (chunking)이었습니다. 한 페이지를 처리하고, 캐시를 비우고, 다음 페이지를 처리하는 방식입니다. 하지만 이 방식은 모델이 이전에 무엇이 나왔는지 전혀 알 수 없다는 점을 감수해야 합니다.
Unlimited-OCR은 캐시 증가 문제를 직접적으로 공격합니다. 개발 팀은 디코더의 모든 어텐션 레이어 (attention layer)를 **Reference Sliding Window Attention (R-SWA)**라고 불리는 기술로 교체했습니다.
그 직관은 인간 타이피스트가 작업하는 방식과 유사합니다. 당신은 이미 타이핑한 모든 단어를 머릿속에 담아두지 않습니다. 마지막 한두 문장 정도만 기억하며, 원본 문서를 계속해서 훑어봅니다. R-SWA도 동일한 방식을 취합니다. 디코더(decoder)는 최근에 생성된 토큰들을 고정된 크기의 윈도우(window)로 유지하지만, 원본 이미지 토큰에는 영구적으로 접근할 수 있습니다. KV 캐시(KV cache)는 고정된 용량을 가진 큐(queue)로 구현되어 있어, 새로운 토큰이 들어오면 윈도우 내에서 가장 오래된 토큰이 제거됩니다.
그 결과, 캐시 크기가 계속 커지는 대신 일정하게 유지됩니다. 토큰이 500번째이든 30,000번째이든 메모리(Memory)와 토큰당 지연 시간(per-token latency)은 일정하게 유지됩니다.
실제 제공되는 기능
- 총 3B 파라미터, 500M 활성화. 이는 Mixture-of-Experts (MoE) 모델이므로, 추론(inference) 시 연산 비용은 3B 모델보다는 500M 모델에 가깝습니다.
- 32K 최대 출력 길이 (max output length), 이것이 다중 페이지의 단일 패스 파싱(single-pass parsing)을 가능하게 만듭니다.
- OmniDocBench v1.5에서 93.23 기록, 이는 지속 학습(continue-trained)의 기반이 된 DeepSeek-OCR 베이스라인보다 약 6.2포인트 높은 수치입니다. 효율성 작업은 보통 정확도를 희생하기 마련이지만, 여기서는 그렇지 않았다는 점이 주목할 만합니다.
- MIT 라이선스. 상업적 이용이 가능하며, 어떠한 제약 조건도 없습니다.
아키텍처는 DeepSeek-OCR의 DeepEncoder (SAM-ViT-B 및 CLIP-L)가 MoE 디코더에 데이터를 공급하는 구조입니다. 인코더(encoder)의 공격적인 시각적 토큰 압축(visual token compression) 덕분에 이미지 측 캐시 크기가 작게 유지되어 전체 시스템이 작동할 수 있습니다.
논문에서 언급했지만 놓치기 쉬운 한 가지는, R-SWA가 OCR 전용이 아니라는 점입니다. 이는 자동 음성 인식 (ASR)을 포함하여, 긴 호흡의 전사(transcription) 형태를 가진 모든 작업에 적용 가능한 범용 어텐션 메커니즘 (general-purpose attention mechanism)입니다.
시작하기 전에
NVIDIA GPU가 필요합니다. 공식 저장소(repo)에는 CPU나 Apple Silicon을 지원하는 경로가 없습니다.
가중치(weights)는 bfloat16 형식이므로, 활성화(activations) 및 이미지 토큰을 제외하고 모델을 로드하는 데만 약 6GB가 필요합니다. 단일 이미지 작업의 경우 12GB 그래픽 카드가 합리적인 최소 사양이며, 32K 컨텍스트(context)에서 다중 페이지를 실행하려면 더 많은 여유 공간이 필요할 것입니다. 유지 관리자들은 Python 3.12.3 및 CUDA 12.9 환경에서 테스트를 진행했습니다.
이 모든 과정을 직접 실행하기 전에 결과물만 확인하고 싶다면, 파일을 바로 업로드해 볼 수 있는 Hugging Face Space가 있습니다.
경로 1: Transformers (여기서 시작하세요)
이것이 작동하는 결과를 얻는 가장 빠른 방법입니다. 환경을 설정하세요:
python -m venv .venv
source .venv/bin/activate
...
이 버전들을 고정(Pin)하십시오. 이 모델은 trust_remote_code를 통해 커스텀 모델링 코드 (custom modeling code)를 제공하며, 해당 코드는 이 특정 릴리스들에 맞춰 작성되었습니다. 여기서 버전 드리프트 (Version drift)가 발생하면 깔끔한 오류 대신 혼란스러운 임포트 에러 (import errors)가 발생합니다.
이제 단일 이미지 처리입니다:
import torch
from transformers import AutoModel, AutoTokenizer
...
여기에는 보기보다 중요한 두 가지 세부 사항이 있습니다:
프롬프트 (prompt)는 반드시 문자 그대로 <image>로 시작해야 합니다. 이것은 장식이 아니라, 시각적 특징 (visual features)이 삽입되는 플레이스홀더 토큰 (placeholder token)입니다. 이를 누락하면 모델이 본 적도 없는 문서를 환각 (hallucinating)하는 것과 같은 출력이 나옵니다.
no_repeat_ngram_size와 ngram_window는 핵심적인 역할을 합니다. 목차나 가격표와 같이 반복적인 레이아웃 (layout)에서 긴 호흡의 생성 (Long-horizon generation)을 수행할 때, 모델이 동일한 행을 영원히 출력하는 루프에 빠질 수 있습니다. 이 파라미터들은 슬라이딩 윈도우 (sliding window) 내에서 35-gram이 반복되는 것을 차단합니다. 튜닝 노이즈 (tuning noise)처럼 보인다고 해서 이를 제거하지 마십시오.
gundam vs base
단일 이미지 추론 (Single-image inference) 시 두 가지 구성 (configuration)을 제공하며, 명칭이 직관적이지는 않습니다:
| 모드 | 설정 | 용도 |
|---|---|---|
| gundam | base_size=1024, image_size=640, crop_mode=True | 단일 이미지, 특히 밀도가 높은 이미지. 이미지를 타일 (tiles)로 자르고 각각을 처리하므로 작은 텍스트도 보존됩니다. |
| base | base_size=1024, image_size=1024, crop_mode=False | 전체 이미지를 한 번에 처리. 다중 페이지 (multi-page) 작업에 필수적입니다. |
다중 페이지 및 PDF 경로는 base 모드만 지원합니다. 이는 기본 설정이 아니라 엄격한 제약 사항 (hard constraint)입니다.
다중 페이지
model.infer_multi(
tokenizer,
prompt='<image>Multi page parsing.',
...
ngram_window가 여기서 128에서 1024로 급격히 증가한다는 점에 유의하세요. 여러 페이지에 걸쳐 반복되는 구조가 실제로 더 많아지기 때문에, 이를 따라잡기 위해서는 반복 감지 (repeat-detection) 윈도우를 넓혀야 합니다.
PDFs
직접적인 PDF 진입점은 없습니다. 먼저 래스터화 (rasterize)를 수행한 다음, 생성된 이미지를 infer_multi에 전달합니다:
import os, tempfile
import fitz # PyMuPDF
...
300 DPI를 권장 기본값으로 사용합니다. 메모리를 아끼기 위해 이보다 낮게 설정하면 작은 텍스트와 표의 선(table rules)을 놓치게 되는데, 이는 보통 사용자가 가장 중요하게 생각하는 콘텐츠입니다.
Path 2: SGLang 서버 (실제 서비스용)
모델을 평가하는 용도로는 Transformers가 적합합니다. 동시 요청을 처리하는 서비스를 구축하려면, SGLang을 실행하고 OpenAI 호환 API를 통해 통신하세요.
환경을 설정합니다. SGLang은 PyPI가 아니라 저장소(repo) 내의 로컬 휠 (wheel) 파일로 제공된다는 점에 유의하세요:
uv venv --python 3.12
source .venv/bin/activate
...
작은 주의 사항: README의 설명글에는 kernels==0.9.0으로 고정하라고 되어 있지만, 바로 아래의 명령 블록에서는 0.11.7을 설치합니다. 명령 블록을 따르세요. 만약 커널 관련 오류가 발생한다면, 해당 불일치가 현재 저장소 상태와 비교하여 가장 먼저 확인해야 할 사항입니다.
서버를 실행합니다:
python -m sglang.launch_server \
--model baidu/Unlimited-OCR \
--served-model-name Unlimited-OCR \
...
필수 플래그(flags)는 다음과 같습니다:
--enable-custom-logit-processor— no-repeat-ngram 프로세서가 커스텀 로짓 프로세서 (custom logit processor)로 실행됩니다. 이 플래그가 없으면 이를 참조하는 요청이 실패합니다.--attention-backend fa3— Hopper 클래스 하드웨어가 필요한 FlashAttention 3를 사용합니다. 구형 GPU에서는 다른 백엔드 (backend)가 필요합니다.--page-size 1및--disable-overlap-schedule— R-SWA의 캐시 제거 (cache eviction)는 일반적인 페이지 어텐션 (paged-attention) 및 중첩 스케줄링 (overlapped-scheduling) 최적화와 잘 맞지 않습니다.
그다음 클라이언트입니다. 이미지는 표준 OpenAI 비전 (vision) 형식인 base64 데이터 URL로 입력되며, 모델별 추가 사항이 몇 가지 포함됩니다:
import base64, json, os
import requests
from sglang.srt.sampling.custom_logit_processor import (
...
temperature: 0과 skip_special_tokens: False 설정은 모두 의도적인 것입니다. 이것은 생성 (generation)이 아니라 전사 (transcription)이므로, 샘플링 (sampling) 과정에서의 어떠한 무작위성도 순전한 단점일 뿐입니다. 또한 특수 토큰 (special tokens)은 출력 결과물에서 원하는 레이아웃 구조 (layout structure)를 담고 있습니다.
1200초의 타임아웃 (timeout) 설정 또한 과도한 것이 아닙니다. 긴 문서는 시간이 오래 걸리며, 이것이 바로 스트리밍 (streaming)이 필요한 정확한 이유입니다.
배치 처리 (Batch processing)
해당 리포지토리 (repo)에는 infer.py가 포함되어 있으며, 이는 사용자를 대신해 SGLang 서버를 시작하고 서버에 동시 요청 (concurrent requests)을 보냅니다.
# 이미지 디렉토리
python infer.py \
--image_dir ./examples/images \
...
유용한 추가 옵션: --model_dir은 로컬 경로 또는 Hugging Face ID를 허용하며, --gpu는 CUDA_VISIBLE_DEVICES를 설정하고, --server_log는 서버 출력을 읽을 수 있는 곳에 저장합니다.
동시성 (concurrency)은 낮게 시작하세요. 문서상 예시는 8이지만, 적절한 숫자는 사용자의 VRAM과 문서의 길이에 따라 달라집니다.
경로 3: Docker를 통한 vLLM
환경 관리 (environment management)를 완전히 건너뛰고 싶다면 다음과 같이 하세요:
# 기본값, CUDA 13.0
docker pull vllm/vllm-openai:unlimited-ocr
...
docker run --rm --gpus all --network host --ipc host \
vllm/vllm-openai:unlimited-ocr \
baidu/Unlimited-OCR \
...
n-gram 프로세서 (ngram processor)와 관련해서는 SGLang과 동일한 상황이며, 서버 시작 시 반드시 등록되어야 합니다. Prefix caching (접두사 캐싱)과 멀티모달 프로세서 캐시 (multimodal processor cache)는 모두 비활성화되어 있는데, 이는 R-SWA의 고정 창 캐시 (fixed-window cache)가 해당 최적화 기법들이 전제하는 가정을 무효화하기 때문입니다.
자세한 내용은 공식 vLLM 레시피 (official vLLM recipe)에서 확인할 수 있습니다.
파라미터 요약표 (Parameter cheat sheet)
| 파라미터 (Parameter) | 단일 이미지 (Single image) | 다중 페이지 / PDF (Multi-page / PDF) |
|---|---|---|
| mode | gundam 또는 base | base 전용 |
| ... |
이 도구가 적합하지 않은 경우
경계 상자 (bounding boxes) 및 단어별 신뢰도 점수 (per-word confidence scores)가 필요한 경우에는 다른 도구를 찾아보십시오. 이 모델은 탐지 후 인식 (detection-plus-recognition) 파이프라인이 아니라 Markdown을 생성하는 엔드투엔드 (end-to-end) 모델이기 때문입니다. 짧은 영수증이나 단일 행을 OCR 하는 경우에도 마찬가지입니다. 이러한 경우에는 GPU 상의 3B 모델이 PaddleOCR 또는 Tesseract에 비해 과도하게 비대합니다 (overkill). 또한, NVIDIA GPU가 없다면 현재 지원되는 경로가 없습니다.
마무리
여기서 흥미로운 주장은 벤치마크 수치가 아닙니다. 효율성 작업은 거의 항상 어딘가에서 품질 저하를 초래함에도 불구하고, 고정된 크기의 KV 캐시 (KV cache)가 긴 문서에서 모델을 더 빠르고 정확하게 만들었다는 점입니다.
만약 R-SWA가 저자들이 제안한 방식대로 일반화될 수 있다면, 동일한 트릭은 모델이 소스(source)를 주시하면서 긴 입력을 긴 출력으로 전사(transcribe)하는 모든 작업에 적용될 수 있습니다. 긴 형태의 자동 음성 인식 (Long-form ASR)이 명백한 다음 단계입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기