기존 AI 문서 처리 파이프라인에서 Tesseract OCR을 사용하고 있었지만, 한국어 인식 정확도에 한계가 있었습니다.
이 글에서는 PaddleOCR을 도입하고, Tesseract에서 PaddleOCR로의 교체 검증을 완료한 전체 과정을 정리합니다. Recognition 모델 파인튜닝은 테스트를 완료한 상태이며, 운영 환경을 고려하여 진행 예정입니다.
도입 배경
기존 파이프라인은 Tesseract OCR + LayoutLM 조합으로 동작하고 있었습니다. Tesseract는 영문 문서에서는 준수한 성능을 보였지만, 한국어 문서에서는 인식 오류가 빈번하게 발생했습니다.
이를 해결하기 위해 LayoutXLM이 레이블 매핑을, PaddleOCR이 OCR을 담당하는 새로운 구조를 설계했습니다.
| 역할 | 모델 |
|---|---|
| OCR (글자 인식) | PaddleOCR |
| 레이블 매핑 (문서 이해) | LayoutXLM |
PaddleOCR 아키텍처 이해
PaddleOCR은 Detection과 Recognition이 분리된 구조입니다.
- Detection: 이미지에서 글자 영역을 찾는 단계
- Recognition: 찾은 영역에서 실제 글자를 읽는 단계
테스트 결과, Detection은 이미 충분히 잘 동작하고 있었지만 Recognition에서 오류가 발생하고 있었습니다.
업태르제조 → 업태제조 (Recognition 오류)
공급받는져 → 공급받는자 (Recognition 오류)
2024.0l.15 → 2024.01.15 (l과 1 혼동)
따라서 학습 목표는 Recognition 모델의 한글 인식 정확도 개선으로 설정했습니다. 현재는 테스트를 완료한 상태이며, 운영 환경을 고려하여 파인튜닝을 진행할 예정입니다.
Label Studio 텍스트 교정 필드 추가
Recognition 학습을 위해서는 "정답 텍스트"가 필요합니다. 향후 Recognition 파인튜닝 진행 시 활용하기 위해, 기존 Label Studio 인터페이스에 별도의 교정 필드를 추가했습니다.
transcription→ OCR 원본 텍스트 (읽기 전용)corrected_text→ 정답 텍스트 입력 (편집 가능, 새로 추가)
동작 방식은 다음과 같습니다.
- 기존 OCR 결과 텍스트가 각 region에 표시됨
- 사용자가 정답 텍스트 입력 칸에 올바른 텍스트를 직접 입력
- Submit 시 OCR 원본 텍스트 + 정답 텍스트 + 필드 라벨 + bbox가 함께 저장됨
Tesseract 기반 기존 아키텍처에서 먼저 적용 테스트를 완료한 후, PaddleOCR 환경에도 동일하게 적용했습니다.
두 종류의 학습
이 프로젝트에서는 두 가지 학습이 동시에 진행됩니다.
A. LayoutLM 학습 (필드 분류)
OCR 결과 텍스트 + bbox + 라벨을 입력으로 받아, 해당 토큰이 어떤 필드(엔티티)인지 분류하는 학습입니다.
"공급받는자"가 OCR로 잘 들어왔다고 가정하고 → 이게 어떤 라벨인지 학습
B. PaddleOCR Recognition 학습 (글자 읽기) — 진행 예정
bbox 영역을 crop한 이미지를 입력으로 받아, 이미지에서 글자를 정확히 읽는 학습입니다. 테스트 환경에서 파이프라인 검증은 완료되었으며, 운영 환경을 고려하여 진행 예정입니다.
OCR 원본 "공급받는져"는 버리고, 사람이 고친 "공급받는자"를 정답(label)으로 사용
Recognition 학습 데이터 생성 (파이프라인 구축 완료)
Label Studio에서 교정된 데이터를 기반으로 학습 데이터셋을 생성하는 파이프라인을 구축했습니다. bbox 영역을 crop하여 이미지를 만들고, corrected_text를 정답(ground truth)으로 사용합니다. 실제 Recognition 파인튜닝은 운영 환경을 고려하여 진행 예정입니다.
데이터 구조는 다음과 같습니다.
train_data/
├── images/
│ ├── crop_001.jpg
│ ├── crop_002.jpg
│ └── ...
└── label.txt
label.txt 형식:
images/crop_001.jpg 공급받는자
images/crop_002.jpg 2024.01.15
images/crop_003.jpg 업태제조
bbox 수정 시 주의사항
bbox는 LayoutLM과 PaddleOCR에서 서로 다른 역할을 수행합니다. 수정 시 양쪽 모두에 영향을 미치므로 주의가 필요합니다.
| 모델 | bbox 역할 |
|---|---|
| LayoutLM | position embedding (토큰의 문서 내 위치 정보) |
| PaddleOCR | crop 영역 (Recognition 입력 이미지) |
bbox를 수정하면 LayoutLM의 위치 임베딩과 PaddleOCR의 crop 영역이 동시에 변경됩니다.
Tesseract → PaddleOCR 교체 전략
현재 구조는 Tesseract 자체에 종속된 것이 아니라 OCR 출력 포맷에 종속되어 있습니다. 따라서 출력 형식만 맞추면 교체가 가능합니다.
교체 체크리스트:
- PaddleOCR 출력 → Tesseract 호환 포맷 변환 함수 작성
testOCR.py에서 Tesseract 호출부를 PaddleOCR로 교체- bbox 좌표계 통일 (xyxy 형식)
- confidence score 필터링 기준 설정
- LayoutLM 입력 형식에 맞게 변환 로직 검증
- 기존 테스트 케이스로 결과 비교
- 배치 추론 스크립트 업데이트
환경 설정
Python 3.11 가상환경 기반으로 구성합니다.
python3.11 -m venv paddle_env
source paddle_env/bin/activate
pip install paddlepaddle==3.2.2 paddleocr==3.0.1핵심 패키지 버전:
| 패키지 | 버전 |
|---|---|
| Python | 3.11 |
| paddlepaddle | 3.2.2 |
| paddleocr | 3.0.1 |
| torch | 2.1.0 |
PaddleOCR 결과 → LayoutLM 입력 변환
PaddleOCR 출력을 LayoutLM이 기대하는 입력 형식으로 변환해야 합니다.
rec_texts → words
rec_polys → bbox (xyxy 변환)
img.shape → H, W
rec_polys는 4점 좌표(polygon)이므로 min/max로 xyxy 형식의 bbox로 변환이 필요합니다.
def poly_to_xyxy(poly):
xs = [p[0] for p in poly]
ys = [p[1] for p in poly]
return [min(xs), min(ys), max(xs), max(ys)]testOCR.py 핵심 로직
testOCR.py는 PaddleOCR 결과를 LayoutLM에 전달하기 위한 전처리 스크립트입니다. 4단계로 구성됩니다.
- 세로 분할 OCR — 이미지를 세로로 분할하여 PaddleOCR 실행
- score 필터링 — 신뢰도 0.70 미만 결과 제거 (노이즈 판단)
- 포맷 변환 — PaddleOCR 출력 → LayoutLM 입력 형식 변환
- LayoutLM 추론 — 변환된 데이터로 모델 추론 실행
score 임계값 0.70은 테스트 결과에 따라 조정 가능합니다.
언어별 모델 분기
문서 언어에 따라 서로 다른 PaddleOCR Recognition 모델을 사용합니다.
| 언어 | 모델 |
|---|---|
| 영어 / 스페인어 (Latin) | latin_PP-OCRv3_mobile_rec |
| 한국어 (Korean) | korean_PP-OCRv3_mobile_rec |
언어 감지는 문서 메타데이터 또는 프로젝트 설정 기반으로 자동 분기됩니다.
사전 검증
PaddleOCR 교체 전, 기존 checkpoint 기반으로 사전 검증을 수행하여 안정성을 확인합니다.
- checkpoint:
checkpoint-740 - model_version:
LayoutLM-paddle-v1
기존 Tesseract 기반 결과와 PaddleOCR 기반 결과를 동일 문서로 비교하여 품질을 검증합니다.
배치 추론
PaddleOCR 기반 배치 추론을 위한 전용 스크립트 layout_batch_predict_paddle.py를 사용합니다.
테스트 단계에서는 특정 프로젝트(project id=34)만 대상으로 제한하여 안전하게 검증한 후, 전체로 확대할 예정입니다.
단계별 진행 로드맵
| Phase | 단계 | 내용 | 상태 |
|---|---|---|---|
| 0 | 사전 준비 | 환경 설정, PaddleOCR 설치 및 기본 테스트 | ✅ 완료 |
| 1 | 단건 테스트 | 단일 이미지로 PaddleOCR → LayoutLM 파이프라인 검증 | ✅ 완료 |
| 2 | 연결 테스트 | testOCR.py 통합 및 전체 흐름 연결 | ✅ 완료 |
| 3 | 배치 테스트 | 다수 문서 배치 추론 테스트 | ✅ 완료 |
| 4 | 결과 검토 | Tesseract 대비 정확도 비교 및 분석 | ✅ 완료 |
| 5 | 학습 데이터 생성 | Recognition 학습용 crop 이미지 + label.txt 생성 | ⏳ 예정 |
| 6 | Recognition 학습 | PaddleOCR Recognition 모델 fine-tuning | ⏳ 예정 |
| 7 | 성능 비교 | 학습 전/후 Recognition 정확도 비교 | ⏳ 예정 |
Phase 04(OCR 교체 및 검증)는 완료되었으며, Phase 57(Recognition 파인튜닝)은 운영 환경을 고려하여 진행 예정입니다.
정리
Tesseract에서 PaddleOCR로의 전환은 단순한 OCR 엔진 교체가 아니라, 학습 파이프라인과 데이터 흐름 전체를 재설계하는 작업이었습니다.
핵심은 기존 아키텍처가 OCR 출력 포맷에 종속되어 있었기 때문에, 포맷 변환 레이어만 잘 설계하면 교체가 가능했다는 점입니다. Label Studio를 통한 텍스트 교정 워크플로우와 Recognition 학습 데이터 생성 파이프라인을 구축해 두었으며, 현재 OCR 교체 검증(Phase 04)은 완료된 상태입니다. Recognition 파인튜닝(Phase 57)은 운영 환경을 고려하여 진행할 예정이며, 이를 통해 지속적으로 모델 정확도를 개선할 수 있는 구조를 갖추었습니다.