Articlehuggingface.co·2025년 10월 3일·0

SOTA OCR with Core ML and dots.ocr

Quick Summary

RedNote의 30억 매개변수 OCR 모델 dots.ocr를 단일 이미지 처리에 맞게 단순화하고, 비전 인코더를 Core ML로 변환해 PyTorch와 유사한 출력까지 검증한 온디바이스 구현 기록이다.

SOTA OCR with Core ML and dots.ocr 관련 대표 이미지

🖼️ 인포그래픽

SOTA OCR with Core ML and dots.ocr 내용을 설명하는 본문 이미지

🖼️ 4컷 인포그래픽

SOTA OCR with Core ML and dots.ocr 내용을 설명하는 본문 이미지

💡 한 줄 요약

RedNote의 30억 매개변수 OCR 모델 dots.ocr를 단일 이미지 처리에 맞게 단순화하고, 비전 인코더를 Core ML로 변환해 PyTorch와 유사한 출력까지 검증한 온디바이스 구현 기록이다.

📌 핵심 요약

  • dots.ocr는 OmniDocBench에서 Gemini 2.5 Pro를 앞선 OCR 모델로 소개되며, 저자들은 API 키·네트워크·호출 비용 없이 기기에서 실행하기 위해 Apple의 Core ML과 MLX를 조합한다.
  • 전체 모델 가운데 12억 매개변수 NaViT 기반 비전 인코더는 Core ML로, Qwen2.5-1.5B 언어 모델 백본은 MLX로 실행하도록 역할을 분리한다.
  • 첫 변환 목표는 Neural Engine 최적화가 아니라 GPU·FLOAT32·정적 형상 조건에서 최소 기능 모델을 정상 변환하는 것으로 설정한다.
  • 단일 이미지만 처리한다는 전제 아래 배치·영상용 가변 길이 마스킹, 불필요한 어텐션 구현, 동적 반복문을 제거하고 Core ML이 지원하지 못하는 연산과 자료형을 단계적으로 수정한다.
  • 변환 결과는 PyTorch 출력과 최대 약 0.006, 평균 약 0.000011의 차이를 보였지만, 모델 크기가 5GB를 넘고 비전 인코더 한 번의 순전파에도 1초 이상이 걸려 추가 최적화가 필요했다.

🧩 주요 포인트

  1. dots.ocr는 OmniDocBench에서 Gemini 2.5 Pro를 앞선 OCR 모델로 소개되며, 저자들은 API 키·네트워크·호출 비용 없이 기기에서 실행하기 위해 Apple의 Core ML과 MLX를 조합한다.
  2. 전체 모델 가운데 12억 매개변수 NaViT 기반 비전 인코더는 Core ML로, Qwen2.5-1.5B 언어 모델 백본은 MLX로 실행하도록 역할을 분리한다.
  3. 첫 변환 목표는 Neural Engine 최적화가 아니라 GPU·FLOAT32·정적 형상 조건에서 최소 기능 모델을 정상 변환하는 것으로 설정한다.
  4. 단일 이미지만 처리한다는 전제 아래 배치·영상용 가변 길이 마스킹, 불필요한 어텐션 구현, 동적 반복문을 제거하고 Core ML이 지원하지 못하는 연산과 자료형을 단계적으로 수정한다.
  5. 변환 결과는 PyTorch 출력과 최대 약 0.006, 평균 약 0.000011의 차이를 보였지만, 모델 크기가 5GB를 넘고 비전 인코더 한 번의 순전파에도 1초 이상이 걸려 추가 최적화가 필요했다.

🧠 상세 정리

1. 경쟁력 있는 OCR의 온디바이스 실행 가능성

글은 하드웨어 성능과 매개변수당 모델 효율이 꾸준히 향상되면서 2025년에는 경쟁력 있는 모델을 기기 자체에서 실행하는 일이 이전보다 현실적이 되었다는 관찰에서 출발한다. 사례로 제시된 RedNote의 30억 매개변수 OCR 모델 dots.ocr는 OmniDocBench에서 Gemini 2.5 Pro를 앞선 것으로 소개되며, OCR 품질을 크게 양보하지 않고도 온디바이스 활용을 검토할 수 있는 수준에 도달했다. 온디바이스 실행은 애플리케이션에 API 키를 넣을 필요가 없고, 모델 호출 비용이 들지 않으며, 네트워크 연결 없이도 동작한다는 장점이 있다. 다만 모바일과 개인용 기기는 연산 능력과 전력 예산이 제한되어 있으므로, 단순히 모델을 옮기는 것만으로는 충분하지 않고 실행 경로와 모델 구조를 하드웨어에 맞게 조정해야 한다.

2. Neural Engine과 Core ML·MLX의 역할

Apple Neural Engine은 2017년 이후 Apple 기기에 탑재된 전용 AI 가속기로, 높은 처리 성능과 낮은 배터리 소비를 함께 목표로 한다. 글에서 인용한 테스트 결과에 따르면 Neural Engine은 CPU보다 12배, GPU보다 4배 높은 전력 효율을 보였지만, 이 장치에 접근하려면 Apple의 폐쇄형 머신러닝 프레임워크인 Core ML을 사용해야 한다. PyTorch 모델을 Core ML로 변환하는 과정에는 여러 호환성 문제가 있어, 사전 변환된 모델이나 관련 경험이 없으면 개발자가 상당한 시행착오를 겪을 수 있다. 저자들은 이를 보완하기 위해 GPU를 대상으로 하면서 더 유연하게 사용할 수 있는 MLX를 Core ML과 함께 채택했다. 이 연재에서는 비전 인코더를 Core ML에, 언어 모델 백본을 MLX에 배치하고, 두 프레임워크를 결합해 dots.ocr 전체를 기기에서 실행하는 과정을 단계적으로 다룬다.

3. PyTorch에서 Core ML로 변환하는 기본 전략

PyTorch 모델을 Core ML로 옮기는 절차는 먼저 torch.jit.trace 또는 더 현대적인 torch.export를 이용해 PyTorch 실행 그래프를 포착하고, 이어서 coremltools로 그 그래프를 .mlpackage 형식으로 컴파일하는 두 단계로 구성된다. 두 번째 단계에서도 일부 설정을 조절할 수 있지만, 실제 변환 가능성을 크게 좌우하는 것은 coremltools에 어떤 실행 그래프를 전달하느냐이다. 저자들은 ‘먼저 동작하게 만들고, 올바르게 만들고, 빠르게 만든다’는 순서를 적용해 최초 목표를 CPU와 GPU에서 실행되는 FLOAT32·정적 형상 모델로 제한했다. 이 초기 단계에서는 모델 크기나 Neural Engine 활용을 바로 해결하려 하지 않고, 원본 PyTorch 모델과 결과가 일치하는 변환 경로를 먼저 확보한다. 정상 동작을 확인한 뒤에야 정밀도를 낮추고 Neural Engine으로 연산을 이동하는 최적화를 시도한다는 접근이다.

4. 모델 구조 파악과 최소 기능 모델 구성

dots.ocr는 처음부터 학습된 12억 매개변수의 NaViT 기반 비전 인코더와 Qwen2.5-1.5B 언어 모델 백본으로 구성되며, 저자들은 전자를 Core ML로, 후자를 MLX로 실행하기로 했다. 비전 인코더는 QwenVL 계열과 유사하게 이미지를 14×14 패치 단위로 처리하고, 원래 구현은 영상과 여러 이미지로 이루어진 배치까지 지원한다. 그러나 온디바이스 애플리케이션의 첫 구현에서는 한 번에 이미지 한 장만 처리해도 핵심 OCR 기능을 제공할 수 있으므로, 배치와 영상 지원을 제거해 변환 대상 그래프를 단순화했다. 여러 종류로 제공되던 어텐션 구현도 모두 유지하지 않고, iOS 18에서 도입된 Core ML의 scaled_dot_product_attention 인프라에 맞춰 단순한 SDPA 구현만 남겼다. SDPA가 Sliding Window Attention을 구현하지 않았다는 경고가 나타났지만, 해당 기능은 모델의 기본 동작에 필수적이지 않아 변환을 계속 진행했다.

5. 변환 하네스와 자료형 불일치 해결

저자들은 성숙도가 높은 torch.jit.trace를 사용하고, 계산 장치와 정밀도를 손쉽게 바꿀 수 있는 간단한 변환 하네스를 마련했다. FLOAT32와 CPU_AND_GPU 조건으로 원본 구현을 변환하자 VisionRotaryEmbedding의 outer 연산에서 int32와 fp32 자료형이 일치하지 않는 첫 오류가 발생했다. 원본 코드는 torch.arange에 역주파수 텐서와 같은 dtype을 지정한 뒤 torch.outer를 호출하지만, coremltools는 arange의 dtype 인수를 무시하고 항상 int32를 출력했다. 이에 따라 arange 직후 명시적인 형 변환을 추가해 두 입력의 자료형을 맞췄고, 첫 번째 변환 장애를 제거했다. 이 사례는 PyTorch 코드상으로는 자료형이 명확하게 지정되어 있어도 변환기가 해당 의미를 그대로 보존하지 않을 수 있으므로, 실제 변환 그래프와 오류 위치를 기준으로 문제를 추적해야 함을 보여준다.

6. 가변 길이 처리와 어텐션 마스크 제거

자료형 문제를 해결한 뒤에는 repeat_interleave 연산에서 상수에 None을 추가할 수 없다는 오류가 이어졌다. 해당 연산은 시간·높이·너비를 나타내는 grid_thw로부터 누적 시퀀스 길이 cu_seqlens를 만들며, flash_attention_2에서 길이가 서로 다른 시퀀스를 마스킹하기 위한 코드였다. 변환 모델은 영상이나 이미지 배치가 아니라 이미지 한 장만 처리하므로, 저자들은 이 가변 길이 계산 자체를 제거했다. 이후 동적 인덱스를 지원하지 않는 내부 inplace fill 오류도 같은 마스킹 로직에서 발생했으며, 단일 이미지에서는 별도의 어텐션 마스킹이 필요하지 않다는 점을 이용해 모든 위치를 허용하도록 바꿨다. Neural Engine이 불리언 텐서를 지원하지 않는다는 제약까지 미리 고려해 불리언 마스크 대신 값이 모두 0인 실수형 마스크를 사용함으로써, 현재 변환 문제와 이후 가속기 이전 준비를 함께 처리했다.

7. 동적 제어 흐름 제거와 출력 정밀도 검증

그래프 변환이 성공한 뒤 실제 모델을 실행하자 mps.reshape 결과 형상이 입력 형상과 호환되지 않는다는 런타임 오류가 발생했다. 직접적인 오류 위치가 여러 reshape 후보 가운데 하나일 수 있었지만, 추적 과정에서 출력된 ‘텐서를 순회하면 다른 형상에서 잘못된 추적 결과가 생길 수 있다’는 경고가 원인을 찾는 단서가 되었다. 원본 구현은 grid_thw의 각 시간·높이·너비 조합을 반복문으로 순회했는데, 머신러닝 컴파일러는 입력 텐서에 따라 달라지는 이러한 동적 제어 흐름을 안정적으로 처리하기 어렵다. 저자들은 단일 이미지라는 전제를 다시 적용해 반복문을 제거하고 하나의 높이·너비 쌍을 직접 처리하도록 수정했다. 재변환 후 Core ML 출력과 원본 PyTorch 출력의 최대 차이는 0.006000518798828125, 평균 차이는 1.100682402466191e-05로 측정되어, 최초 목표였던 FLOAT32 변환의 수치적 일치가 확인되었다.

8. 초기 벤치마크의 한계와 후속 최적화 과제

기능적으로 성공한 최초 Core ML 모델은 크기가 5GB를 넘어 온디바이스 배포에 적합하지 않았고, 성능 역시 비전 인코더의 단일 순전파에 1초 이상이 걸렸다. 저자들은 생성된 .mlpackage를 Xcode에서 열고 Performance Report를 모든 계산 장치에 대해 실행하는 방식으로 계산 시간을 측정했다. 따라서 이 단계의 성과는 실사용 가능한 최종 모델을 완성한 것이 아니라, 정적 형상과 FLOAT32 조건에서 변환을 성립시키고 원본과의 출력 일치를 확인한 데 있다. 연재의 두 번째 글에서는 Core ML 비전 인코더와 MLX 언어 모델 백본을 연결해 전체 모델을 기기에서 실행하는 통합 과정을 다룰 예정이다. 세 번째 글에서는 양자화와 동적 형상을 포함해 Neural Engine에서 실행하는 데 필요한 최적화를 심층적으로 다루며, 현재 확인된 모델 크기와 지연 시간 문제를 줄이는 방향으로 이어진다.

🧾 핵심 주장 / 시사점

  • 복잡한 범용 모델을 온디바이스로 옮길 때는 배치·영상·가변 길이 처리처럼 당장 필요하지 않은 기능을 제거한 최소 실행 경로를 먼저 확보하는 것이 변환 장애를 줄이는 핵심 방법이다.
  • Core ML 변환 문제는 원본 PyTorch 코드의 문법보다 변환된 실행 그래프의 자료형, 동적 인덱스, 마스크 표현, 제어 흐름 제약에서 주로 드러났으며, 오류를 그래프의 다음 노드까지 순차적으로 해결하는 방식이 사용됐다.
  • 출력 정밀도가 원본과 유사하다는 사실만으로 온디바이스 배포가 완성되는 것은 아니며, 5GB가 넘는 크기와 1초 이상의 비전 인코더 지연 시간을 해결하려면 양자화와 Neural Engine 최적화가 추가로 필요하다.

✅ 액션 아이템

  • 단일 이미지 처리 제약을 유지하며 배치·영상 가변 마스킹과 동적 루프를 제거한 Core ML 변환 절차를 고정한다.
  • NaViT(12억) 비전 인코더와 Qwen2.5-1.5B 백본의 Core ML/MLX 분할 실행을 유지해 PyTorch 출력 오차를 지속 비교한다.
  • GPU·FLOAT32·정적 형상 조건에서 5GB 초과 모델 크기와 비전 인코더 순전파 1초 이상 지연을 줄이기 위한 최적화 우선순위를 정한다.

❓ 열린 질문

  • 단일 이미지 전용 단순화가 실제 문서 유형 변화에 대해 모델 성능 저하를 충분히 흡수하는가?
  • PyTorch 대비 최대 0.006, 평균 0.000011 오차가 온디바이스 적용의 합리적 허용 범위로 판단할 수 있는가?
  • 비전 인코더 5GB 초과와 1초 이상 순전파 지연을 줄이려면 어떤 최적화 기법을 먼저 적용하는 것이 타당한가?

관련 문서

공통 태그와 주제 흐름을 기준으로 같이 보면 좋은 문서를 이어서 제안합니다.