Chandra는 이미지·PDF를 HTML·Markdown·JSON으로 변환하는 VLM 기반 OCR 엔진으로, 복잡한 표·수식·손글씨·90개 이상의 언어를 레이아웃까지 보존하며 인식합니다.
Chandra 2(2026년 3월 출시)는 9B 파라미터를 ~5B(Qwen3.5)로 줄이면서 olmOCR 정확도는 83.1% → 85.9%로 오히려 높아졌습니다. 처리량도 2배 개선. HuggingFace 월간 165K+ 다운로드. GitHub 스타: 11.1k(2026-06-04 기준).
Tesseract 같은 전통 OCR은 "이미지에서 글자를 뽑아내는" 도구입니다. 표의 셀 구분, 수식의 분수 구조, 손글씨의 맥락은 신경 쓰지 않죠. Chandra는 VLM(Vision Language Model)이 이미지를 이해하고 구조화합니다.
결과물은 단순 텍스트가 아니라 <table>, <math>, <div data-bbox="..."> 같은 의미 있는 HTML입니다. 이 HTML이 중간 표현(IR)이 되어 Markdown·JSON으로 변환됩니다.
전통 OCR은 표의 셀 경계를 오해하고, 수식의 분수 구조를 한 줄 텍스트로 뭉개며, 동남아시아 저자원 언어에서 정확도가 크게 떨어집니다. 결과물을 다시 파싱해야 하는 후처리 공수가 막대합니다.
Qwen3.5 기반 ~5B 모델이 이미지를 보고 36개 허용 태그·14개 허용 속성 범위 안에서 HTML을 직접 생성합니다. data-bbox로 좌표 정보까지 포함. 90개 언어 평균 72.7% vs Gemini 60.8%.
| 비교 항목 | Chandra 2 | Gemini 2.5 Flash | Tesseract | olmOCR |
|---|---|---|---|---|
| 파라미터 | ~5B | 비공개(거대) | 전통 ML | 7B+ |
| olmOCR 정확도 | 85.9% | ~63.8% | ~60% | 기준 모델 |
| 90개 언어 평균 | 72.7% | 60.8% | 제한적 | - |
| 레이아웃 보존 | HTML + bbox | 텍스트 위주 | 텍스트만 | 텍스트 위주 |
| 로컬 실행 | vLLM/HF | API만 | 로컬 | 로컬 |
| 구성 요소 | 기술 | 역할 |
|---|---|---|
| 기반 아키텍처 | Qwen3.5 | 이미지+텍스트 멀티모달 추론 |
| 모델 크기 | v1: 9B, v2: ~5B (Qwen3.5) | 파라미터 수 |
| 텐서 타입 | BF16 (bfloat16) | 메모리 효율적 추론 |
| 프레임워크 | HuggingFace Transformers 5.2+ | 모델 로딩/추론 |
| 서빙 엔진 | vLLM | 고성능 LLM 서빙 (OpenAI 호환 API) |
| 가속 | Flash Attention | 어텐션 연산 최적화 |
| 기술 | 역할 |
|---|---|
| Python 3.10+ / uv | 코어 언어 / 빠른 의존성 관리 |
| Pydantic Settings | 환경변수 → Python 객체 자동 매핑 |
| pypdfium2 | Chrome PDF 렌더링 엔진 — PDF → 이미지 변환 |
| Pillow | 이미지 리사이즈 / 크롭 / LANCZOS 리샘플링 |
| BeautifulSoup4 | 생성된 HTML 파싱 및 구조 분석 |
| markdownify | HTML → Markdown 변환 (커스터마이징) |
| openai | vLLM OpenAI 호환 API 호출 |
| Streamlit | 인터랙티브 데모 UI |
# 사용자는 method만 바꾸면 됨
manager = InferenceManager(method="vllm") # 또는 "hf"
result = manager.generate(batch)
vLLM(서버 모드, 높은 처리량)과 HuggingFace(서버 없이 단일 스크립트)가 동일한 generate(batch) 인터페이스를 구현합니다. 같은 모델을 다른 환경에 맞게 서빙하는 실전적 패턴입니다.
OCR 결과를 바로 텍스트로 뽑지 않고 HTML을 중간 표현(IR)으로 사용합니다. HTML이 이미 table·div·math 구조를 갖고 있으므로 Markdown이나 JSON으로 변환이 훨씬 쉽습니다. 허용 태그/속성을 제한해 모델 출력의 일관성을 확보합니다.
vLLM 추론 실패 시 온도를 0.0 → 0.8까지 점진적으로 올립니다. 반복 토큰 패턴(degenerate output)을 감지하면 자동 재시도합니다. LLM 서빙에서 흔한 품질 저하 문제를 우아하게 해결하는 패턴입니다.
입력(input.py) → 프롬프팅(prompts.py) → 추론(model/) → 후처리(output.py) 각 단계가 독립 모듈로 분리되어 한 단계만 교체하거나 테스트할 수 있습니다.
| 모듈 | 핵심 역할 | 배울 것 |
|---|---|---|
| input.py | PDF→이미지 변환, 해상도 보장 | pypdfium2 사용법, 파일타입 감지 패턴 |
| output.py | HTML 파싱→MD/이미지 추출 | BeautifulSoup + markdownify 파이프라인 |
| prompts.py | VLM 프롬프트 설계 | Structured Output 유도 기법 |
| settings.py | 환경변수 기반 설정 | Pydantic Settings 실전 패턴 |
| model/vllm.py | vLLM API 호출 + 재시도 | OpenAI 호환 API, ThreadPool 병렬화 |
| model/hf.py | 로컬 HF 추론 | Transformers AutoModel 사용법 |
VLM이 이미지를 "보고" 텍스트를 생성하는 원리(Vision Encoder → Language Model), 4B 파라미터로 9B를 능가하는 모델 경량화 기법, BF16 추론의 의미와 메모리 절약 효과를 배웁니다.
vLLM이 HuggingFace 대비 빠른 이유(PagedAttention, Continuous Batching), OpenAI 호환 API로 LLM 서빙하는 표준 패턴, ThreadPoolExecutor로 동시 요청 처리를 익힙니다.
# vLLM 클라이언트 OpenAI 호환 호출 패턴
from openai import OpenAI
client = OpenAI(api_key="EMPTY", base_url="http://localhost:8000/v1")
response = client.chat.completions.create(
model="chandra",
messages=[{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{img_b64}"}},
{"type": "text", "text": "OCR this image to HTML"}
]
}],
temperature=0.0,
max_tokens=12384
)
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
MODEL_CHECKPOINT: str = "datalab-to/chandra-ocr-2"
MAX_OUTPUT_TOKENS: int = 12384
VLLM_API_BASE: str = "http://localhost:8000/v1"
IMAGE_DPI: int = 192
MIN_IMAGE_DIM: int = 1536
class Config:
env_file = "local.env"
extra = "ignore" # 알 수 없는 env 변수 무시
settings = Settings() # 모듈 레벨 싱글톤
허용 태그/속성을 제한하여 모델 출력 품질을 제어하는 기법, data-bbox로 좌표 정보를 HTML에 내장하는 아이디어, 시맨틱 라벨(Caption·Table·Code-Block) 분류 프롬프트를 배웁니다.
| 항목 | 요구사항 |
|---|---|
| GPU VRAM | 8GB+ (4B 모델 BF16 기준) |
| RAM | 16GB+ |
| 디스크 | ~10GB (모델 가중치) |
| Python | 3.10+ |
| CUDA | 12.0+ (권장) |
| 항목 | 요구사항 |
|---|---|
| GPU | NVIDIA H100 80GB (벤치마크 기준) |
| GPU VRAM | 24GB+ (동시 처리 96 시퀀스 기준) |
| RAM | 32GB+ |
| 처리량 | ~1.44 pages/sec (H100 80GB 기준) |
GPU 없이 사용하는 방법: Hosted API(datalab.to), 웹 Playground, HuggingFace에 11개 양자화 버전(GGUF·AWQ) 제공.
설치 후 아무 PDF로 OCR을 실행하고 결과물(Markdown·HTML·JSON·이미지)을 직접 확인합니다. 일반 OCR과의 차이를 체감하는 것이 목표입니다.
pip install chandra-ocr
chandra my_document.pdf ./output --method vllm
cat ./output/my_document.md
드래그앤드롭으로 다양한 문서(손글씨·표·수식)를 넣어보고 인식 결과를 비교합니다. Streamlit 앱 구조도 함께 분석합니다.
pip install "chandra-ocr[all]"
chandra_app # 브라우저에서 http://localhost:8501
폴더 내 모든 PDF를 일괄 처리하여 결과를 JSON으로 저장하는 파이프라인을 직접 구현합니다. 실제 업무 자동화 패턴을 익힙니다.
Markdownify 클래스를 상속하여 테이블을 CSV로 자동 추출하고, 수식을 LaTeX 파일로 별도 저장하며, 이미지 캡션을 JSON으로 구조화하는 기능을 추가합니다.
OCR 역사(규칙 기반 → CNN → Transformer → VLM), Tesseract vs EasyOCR vs Chandra 비교 실습, Chandra CLI로 다양한 문서 10개 처리, settings.py 환경변수 커스터마이징
Qwen-VL 논문 읽기(Vision Encoder + LLM 연결 구조), HuggingFace Transformers로 VLM 추론 실습, model/hf.py 코드 라인별 분석, Flash Attention 원리
vLLM 공식 문서 정독(PagedAttention·Continuous Batching), model/vllm.py 재시도 로직·온도 에스컬레이션 분석, vLLM 서버 직접 띄우고 벤치마크, 멀티 GPU 설정 실습
input.py — pypdfium2 PDF 렌더링 심화, output.py — HTML 파싱·Markdownify 커스터마이징, 자체 문서 처리 파이프라인 설계 및 구현
prompts.py 분석(허용 태그/속성 제한 전략), 프롬프트 변형 실험, 자체 도메인 특화 프롬프트 설계(영수증·의료문서 등)
양자화(GGUF·AWQ) 적용 실습(VRAM 50% 절약), Docker로 Chandra 서비스 컨테이너화, FastAPI + vLLM API 서버 구축, 처리량·에러율·지연시간 모니터링
| 키워드 | 설명 |
|---|---|
| VLM | Vision Language Model. 이미지와 텍스트를 동시에 이해하는 멀티모달 AI 모델 |
| OCR | Optical Character Recognition. 이미지에서 텍스트를 추출하는 기술 |
| vLLM | LLM 빠른 서빙 엔진. PagedAttention으로 메모리 효율 극대화 |
| PagedAttention | vLLM의 핵심 기술. OS 가상 메모리처럼 KV 캐시를 페이지 단위로 관리 |
| Continuous Batching | 요청 완료 즉시 새 요청을 배치에 추가하는 동적 배칭 기법 |
| BF16 | bfloat16. 16비트 부동소수점. FP32 대비 메모리 절반, FP16보다 넓은 범위 |
| Flash Attention | 어텐션 연산 메모리를 O(N²)→O(N)으로 줄이는 알고리즘 |
| pypdfium2 | Chrome PDF 엔진(PDFium)을 Python에서 사용하는 바인딩. 렌더링 품질 브라우저 수준 |
| data-bbox | Chandra가 HTML 요소에 부여하는 바운딩박스 좌표 (0~1000 스케일) |
| 시맨틱 라벨 | 문서 요소의 의미적 분류: Caption·Table·Section-Header·Code-Block 등 |
| Form Flattening | PDF 폼 필드를 정적 이미지로 변환. 체크박스·입력란 등이 렌더링에 포함됨 |
| Markdownify | HTML을 Markdown으로 변환하는 Python 라이브러리. Chandra가 커스터마이징 |
| OpenRAIL-M | 모델 가중치용 오픈 라이선스. 특정 제한 조건 부과 (코드는 Apache 2.0) |
| olmOCR | OCR 모델 성능 표준 벤치마크. 수학·표·오래된 스캔 등 카테고리별 평가 |
| Pydantic Settings | 환경변수를 Python 객체로 자동 매핑하는 설정 관리 프레임워크 |
| ThreadPoolExecutor | Python 내장 스레드 풀. vLLM 요청을 병렬 처리하는 데 사용 |
| LANCZOS 리샘플링 | 이미지 업스케일링 시 고품질을 보장하는 보간 알고리즘 |
| KaTeX | 빠른 수학 수식 렌더링 라이브러리. Chandra는 수식을 KaTeX 호환 LaTeX로 출력 |