
Mac에서 양자화된 Unlimited-OCR 테스트 결과: 4-Bit는 최적의 지점이 아니었습니다.
요약
Baidu의 Unlimited-OCR 모델을 대상으로 Mac 환경(MLX, GGUF)에서 양자화 성능을 테스트한 결과입니다. 단순 벤치마크의 한계를 지적하며, 합성 데이터셋을 활용해 실제 OCR 품질 저하를 정밀하게 측정하는 방법론을 제시합니다.
핵심 포인트
- 양자화 벤치마크의 노이즈와 오류 가능성 경고
- MLX 및 llama.cpp(GGUF) 런타임 기반 로컬 실행 테스트
- 정확한 측정을 위한 합성 OCR 코퍼스 및 정답(Ground Truth) 활용
- 단순 수치보다 밀집 텍스트 및 숫자 데이터에서의 실질 품질 중요성
전정밀도 (full-precision) 모델이 자체 4-bit 버전보다 성능이 낮게 나오는 양자화 "품질 사다리 (quality ladder)"는 실제 품질을 측정하는 것이 아닙니다.
그것은 노이즈를 측정하는 것입니다.
MIT 라이선스로 출시된 Baidu의 새로운 3B OCR 모델인 Unlimited-OCR의 양자화 버전을 살펴보는 동안 저는 이 문제에 계속 직면했습니다. 대부분의 양자화된 저장소(repos)는 두 가지 문제 중 하나를 가지고 있었습니다. 품질 수치를 전혀 제공하지 않거나, 혹은 그 수치를 신뢰하기 어려웠습니다.
일부 베이스라인 (baselines)은 자체 양자화 모델 (quants)에게 패배하기도 했습니다. 일부 문자 오류율 (character error rates)은 100%를 넘기도 했습니다. 많은 경우, 통제되지 않는 반복 루프 (runaway repetition loops)가 평균치를 조용히 부풀리고 있었습니다.
그래서 저는 제가 읽고 싶었던 사다리를 직접 만들었습니다.
저는 사람들이 Mac에서 로컬로 사용할 가능성이 가장 높은 두 가지 런타임 (runtimes)을 테스트했습니다:
- Apple Silicon을 위한 MLX
- llama.cpp를 통한 GGUF
아래의 모든 수치는 재현 가능한 평가 실행에서 도출되었으며, 전체 하네스 (harness)는 오픈 소스입니다.
결과는 유용했지만, 두 가지 발견은 진심으로 저를 놀라게 했습니다.
내가 이 작업을 수행한 이유
양자화 벤치마크 (quantization benchmarks)는 실제보다 더 좋아 보이게 만들기 쉽습니다.
모델이 깨끗한 페이지 한 장에 대한 빠른 스모크 테스트 (smoke test)를 통과할 수는 있지만, 밀집된 텍스트, 송장 (invoices), 표 (tables), 또는 작은 글꼴에서는 여전히 무너질 수 있습니다. OCR의 경우, 이것은 매우 중요합니다. "대체로 작동함"과 "숫자를 조용히 손상시킴" 사이의 차이는 결코 작지 않습니다.
저는 더 실질적인 질문에 답하고 싶었습니다:
만약 내가 이 모델을 로컬에서 실행한다면, 각 양자화 단계에서 실제로 품질을 얼마나 손실하게 될까?
이론적으로가 아닙니다. 느낌(vibes)으로도 아닙니다. 정답 (ground truth)이 알려진 통제된 OCR 작업에서 측정하고자 했습니다.
대부분의 사람들이 건너뛰는 방법론
어려운 점은 단순히 모델을 양자화하는 것만이 아니었습니다.
어려운 점은 평가 결과를 읽기 쉽게 만드는 것이었습니다.
세 가지 선택이 결과를 훨씬 더 깔끔하게 만들었습니다.
1. 정확한 정답 (Exact Ground Truth) 사용
주석이 드문드문 달린 실제 세계의 양식 데이터셋을 기준으로 점수를 매기는 대신, 저는 합성 OCR 코퍼스 (synthetic OCR corpus)를 생성했습니다.
이 코퍼스는 다음을 포함합니다:
- 24개의 렌더링된 페이지 (rendered pages)
- 세 가지 난이도 계층 (difficulty tiers):
- 깨끗한 산문 (clean prose)
- 밀집된 작은 글꼴 페이지 (dense small-font pages)
- 숫자가 많은 송장 (digit-heavy invoices)
- 결정론적 시드 (deterministic seed)
- 글자 단위로 알려진 정답 (ground truth known character-for-character)
이것이 중요한 이유는 희소한 주석 (sparse annotations)이 OCR 모델을 실제보다 더 나쁘게 보이게 만들 수 있기 때문입니다.
예를 들어, 데이터셋이 몇 개의 필드에만 라벨을 붙였는데 모델이 페이지 전체를 전사(transcribe)한다면, 잘못된 이유로 인해 문자 오류율 (character error rate, CER)이 부풀려질 수 있습니다.
이번 테스트를 위해, 저는 정확한 텍스트 대 텍스트 (text-to-text) 비교를 원했습니다.
2. 각 양자화 모델을 자체 런타임 기준점(Baseline)과 비교
모든 양자화된 모델은 동일한 런타임 내의 full-precision BF16 변환 모델을 기준으로 측정됩니다.
즉, 다음과 같습니다:
- GGUF 양자화 모델은 llama.cpp 환경에서 GGUF-BF16과 비교됩니다.
- MLX 양자화 모델은 mlx-vlm 환경에서 MLX-BF16과 비교됩니다.
런타임 간의 교차 기준점 (cross-runtime baselines)은 사용하지 않습니다.
이것이 중요한 이유는 동일한 모델과 프롬프트를 사용하더라도 서로 다른 런타임에서 각기 다르게 실패할 수 있기 때문입니다.
3. 루프(Loops)를 숨기지 않고 드러내기
모든 디코딩 실행에는 다음이 적용됩니다:
- temperature 0
- 반복 억제 (repetition suppression) 비활성화
두 번째 항목은 의도적인 설정입니다.
만약 양자화로 인해 모델이 불안정해진다면, 저는 그 불안정성이 루프 페이지 (loop page)로서 명확하게 드러나기를 원합니다. 평균값 속에 조용히 묻혀버리는 것을 원하지 않습니다.
루프 페이지는 출력/참조 길이 비율 (output/reference length ratio)을 사용하여 플래그를 지정합니다. 또한 일반적인 OCR 성능 저하와 완전한 디코딩 붕괴 (total decoding collapse) 사이의 차이를 쉽게 구분할 수 있도록 루프 횟수를 별도로 보고합니다.
결과
GGUF 계층 (GGUF Ladder)
M3 Max에서 llama.cpp를 사용하여 GGUF-BF16을 기준으로 측정되었습니다.
| 변형 (Variant) | 크기 (Size) | 전체 CER | BF16 대비 변화 (Δ vs BF16) | 루프 (Loops) |
|---|---|---|---|---|
| BF16 | 5.47 GiB | 0.78% | — | 0/24 |
| ... | ||||
![]() |
MLX 계층 (MLX Ladder)
mlx-vlm을 사용하여 MLX-BF16을 기준으로 측정되었습니다.
| 변형 (Variant) | 크기 (Size) | 전체 CER | BF16 대비 차이 (Δ vs BF16) | 루프 (Loops) |
|---|---|---|---|---|
| BF16 | 6.67 GB | 1.62% | — | 0/24 |
| ... | ||||
![]() |
두 가지 사항이 눈에 띕니다.
결과 1: 4-Bit는 최적의 지점(Sweet Spot)이 아니었습니다
많은 사람들이 4-bit 양자화 (Quantization)를 기본적으로 최적의 지점이라고 간주합니다.
그러한 규칙은 대규모 밀집 채팅 모델 (Dense Chat Models)에 대한 퍼플렉시티 (Perplexity) 연구에서 비롯되는 경우가 많습니다.
Unlimited-OCR은 그렇지 않습니다.
이 모델은 약 570M의 활성 파라미터 (Active Parameters)를 가진 3B Mixture-of-Experts (MoE) OCR 모델입니다. 또한 작은 오류가 중요한 정밀도가 높은 작업을 수행합니다. 이는 일반적인 4-bit 휴리스틱 (Heuristic)이 깨질 수 있는 바로 그 유형의 설정입니다.
이번 테스트에서 6-bit까지는 측정 가능한 손실이 없었습니다.
Q8_0와 Q6_K는 24페이지 모두에서 BF16이 인식한 텍스트를 동일하게 재현했습니다.
그다음 절벽(Cliff)이 나타났습니다.
손상은 밀집된 작은 글꼴의 페이지에 집중되었습니다. 깨끗한 페이지는 4-bit에서도 여전히 CER 2% 미만을 유지했는데, 이는 왜 가벼운 1페이지 테스트가 오해를 불러일으킬 수 있는지를 설명해 줍니다.
쉬운 페이지로는 이를 잡아낼 수 없습니다.
어려운 단계가 필요합니다. 또한 실제 기준점 (Baseline)도 필요합니다.
결과 2: 4-Bit 양자화의 종류가 중요합니다
균일한 (Uniform) 4-bit는 좋지 않았습니다.
혼합 정밀도 (Mixed-precision) 4-bit는 훨씬 더 좋았습니다.
GGUF에서 혼합 정밀도는 균일한 4-bit를 약 2.8배 앞질렀습니다.
MLX에서 이는 균일한 4-bit를 약 5.9배 앞질렀습니다.
하지만 문제를 완전히 해결하지는 못했습니다. 절벽을 완만하게 만들었을 뿐, 제거하지는 못했습니다.
저는 또한 회복이 어디에서 발생하는지 이해하기 위해 MLX 어블레이션 (Ablation) 테스트를 수행했습니다. 다른 모든 것을 균일한 4-bit와 동일하게 유지하면서 비전-언어 프로젝터 (Vision-to-language Projector)만 float 상태로 남겨두었습니다.
그럼에도 24페이지 중 7페이지에서 루프가 발생했습니다.
이는 회복이 디코더 (Decoder) 측, 즉 어텐션 프로젝션 (Attention Projections), 임베딩 (Embeddings), 그리고 LM 헤드 (LM Head)에서 일어나고 있음을 시사합니다.
주로 시각적 경로 (Visual Path)에서 발생하는 것이 아닙니다.
내가 예상하지 못했던 결과: 반복 억제 (Repetition Suppression)는 트레이드오프 (Tradeoff) 관계입니다
Unlimited-OCR의 공식 파이프라인 (Pipeline)은 다음과 같은 반복 억제 (Repetition Suppression) 설정을 사용합니다:
no_repeat_ngram_size=35
lama.cpp에는 DRY 샘플러 (DRY sampler)를 통한 유사한 메커니즘이 있습니다.
4-bit 양자화 모델 (Quants)에서만 루프 (Loop) 현상이 발생했기 때문에, 문제가 된 GGUF 모델을 상위 단계 (Upstream) 스타일의 DRY 설정으로 다시 실행해 보았습니다.
처음에는 해결책처럼 보였습니다.
Q4_K_M의 전체 CER (Character Error Rate)이 개선되었습니다:
15.64% → 10.47%
가장 심각했던 루프 페이지들이 복구되었습니다.
하지만 트레이드오프 (Tradeoff)가 깔끔하지 않았습니다.
이전에는 괜찮았던 페이지들의 성능이 악화되었습니다:
3.88% → 10.86%
가장 큰 피해는 템플릿 송장 (Template invoices)과 같이 실제로 반복적인 내용이 포함된 문서에서 나타났습니다.
설상가상으로, DRY는 이전에는 문제가 없던 페이지에서 완전히 새로운 치명적인 루프 (Catastrophic loop)를 유발했습니다:
0% → 218% CER
따라서 반복 억제 (Repetition Suppression)는 공짜 해결책이 아닙니다.
한 가지 실패 모드 (Failure mode)를 다른 모드로 맞바꾸는 것입니다.
만약 문서에 표 (Tables), 송장 (Invoices), 양식 (Forms), 템플릿 (Templates)과 같이 정당한 반복 내용이 포함되어 있다면, 기본적으로 활성화된 DRY 샘플러 (DRY sampler)가 조용히 정확도를 떨어뜨릴 수 있습니다.
이것이 바로 위에서 제시한 주요 계층 (Primary ladder)의 점수가 반복 억제 (Repetition Suppression)를 끈 상태로 측정된 이유입니다.
보너스: R-SWA 첫 살펴보기
Unlimited-OCR의 핵심 메커니즘은 R-SWA, 즉 참조 슬라이딩 윈도우 어텐션 (Reference Sliding Window Attention)입니다.
목표는 긴 호흡의 파싱 (Parsing) 과정 동안 KV 캐시 (KV cache) 메모리를 일정하게 유지하는 것입니다.
아직 MLX 포트 (Port) 중 R-SWA를 구현한 것은 없지만, llama.cpp에는 이를 구현한 오픈 PR (Open PR), **#24975**가 있습니다. 이것은 제 작업이 아닙니다. 모든 공로는 PR 작성자에게 있습니다.
동일한 GGUF 파일이 메인라인 (Mainline)의 다음 설정과 비교하여, PR 브랜치 (PR branch)에서는 다음과 같이 로드됩니다:
n_swa = 128
n_swa = 0
저는 다음 조건들을 테스트했습니다:
- 동일한 가중치 (Weights)
- 동일한 24페이지
- 두 가지 어텐션 방식 (Attention regimes)
인식된 텍스트는 24페이지 중 21페이지에서 동일했습니다.
차이가 발생한 3개의 페이지에서 R-SWA는 약간의 순이익 (Net improvement)을 만들어냈습니다. 루프 (Loops)를 유발하지도 않았습니다.
중요한 주의 사항: 이는 단일 페이지의 충실도 동등성 (Single-page fidelity parity)만을 테스트한 것입니다.
R-SWA가 존재하는 진짜 이유는 멀티 페이지 (multi-page), 상수 메모리 파싱 (constant-memory parsing) 때문입니다. 이 부분은 여기서 테스트되지 않았습니다.
알아둘 만한 두 가지 런타임 세부 사항
몇 가지 작은 런타임 결과들도 언급할 가치가 있습니다.
첫째, 동일한 프롬프트라도 런타임 (runtime)에 따라 다르게 실패할 수 있습니다.
예를 들어:
Free OCR.
이 프롬프트는 llama.cpp에서는 즉시 EOS (End of Sentence)를 출력하지만, mlx-vlm 0.6.3에서는 반복 루프 (repetition loop)에 빠져버립니다.
둘째, mlx-vlm 0.6.3은 바이트 수준의 BPE 디코딩 (byte-level BPE decoding)을 건너뛰는 느린 경로를 통해 이 토크나이저 (tokenizer)를 로드합니다.
즉, 원시 출력 (raw output)에 다음과 같은 마커가 포함됩니다:
Ġ
Ċ
이것들은 직접 디코딩해야 합니다.
llama.cpp는 올바르게 디토크나이즈 (detokenizes) 합니다.
재현하기
모든 것은 공개되어 있습니다:
- Hugging Face의 6개 모델 리포지토리 및 컬렉션
- GitHub의 평가 하네스 (Evaluation harness) — 코퍼스 생성기 (corpus generator), CER/WER 스코어러 (scorer), 루프 진단 도구 (루프 진단 도구의 스코어링 코어는 백엔드에 무관하며, 러너는 MLX 전용입니다)
GGUF 수치 뒤에 숨겨진 정확한 명령어는 다음과 같습니다:
llama-mtmd-cli \
-m unlimited-ocr-Q5_K_M.gguf \
--mmproj mmproj-unlimited-ocr-F16.gguf \
...
주의 사항
이 수치들은 다음 사항들에 특화되어 있습니다:
- 이 모델
- 이 코퍼스 (corpus)
- 합성된 깨끗한 렌더링 (synthetic clean renders)
- 영어 문서
- 단일 페이지 평가
- 이 런타임 빌드
사용자의 문서가 다르게 보인다면, 해당 문서에 하네스를 실행해 보십시오.
그것이 하네스의 용도입니다.
양자화 (quantization)에 있어 유용한 질문은 다음과 같습니다:
작동하는가?
유용한 질문은 다음과 같습니다:
내 데이터에서 품질을 얼마나 잃게 되며, 다른 사람이 이를 검증할 수 있는가?
이것이 수치와 증거의 차이입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기