학습은 보통 PyTorch나 TensorFlow 같은 무거운 프레임워크로 한다. 그런데 그 모델을 폰이나 브라우저에서 돌리려면 그 프레임워크를 통째로 들고 가야 한다. 폰에 올리기엔 너무 무겁다. 이 간극을 메우는 두 가지가 ONNX와 양자화다.
ONNX — 모델계의 PDF
ONNX(Open Neural Network Exchange)는 학습한 모델을 프레임워크에 독립적인 공용 파일 포맷으로 내보낸 것이다.
비유하면 PDF다. 문서를 한글이나 워드로 만들었어도 PDF로 내보내면 그 프로그램 없이 어디서나 열린다. ONNX도 마찬가지다. PyTorch로 학습했어도 ONNX로 내보내면 PyTorch 없이 "ONNX Runtime"이라는 가벼운 실행기만으로 폰·브라우저·서버 어디서든 돌릴 수 있다.
내보내는 동작 자체는 한 줄이다.
torch.onnx.export(model, dummy_input, "model.onnx", opset_version=17)이 호출은 모델의 연산 그래프(어떤 계산을 어떤 순서로 하는지)와 가중치 텐서(학습된 숫자들)를 protobuf라는 포맷으로 직렬화해 한 파일에 담는다. opset_version은 ONNX 연산자 규격의 버전이다. 실행기는 이 파일만 읽으면 원래 프레임워크 없이 같은 계산을 재현할 수 있다.
INT8 양자화 — 숫자의 해상도를 낮춰 4배 줄이기
ONNX로 내보내도 모델은 여전히 클 수 있다. 가중치가 보통 float32(32비트 실수)로 저장되기 때문이다. 양자화(quantization)는 이 숫자의 해상도를 낮춰 파일을 줄이고 실행을 빠르게 한다. 가장 흔한 것이 INT8(8비트 정수) 양자화다.
비유하면 사진의 색 수를 줄이는 것과 같다. 1,600만 색 사진을 256색으로 줄여도 전체 그림은 거의 그대로 보인다. 대신 파일은 훨씬 작아진다. 양자화는 가중치 숫자에 같은 일을 한다. 32비트의 미세한 해상도를 8비트로 낮추되, 전체 동작은 거의 유지한다.
학습이 끝난 모델에 사후 적용하는 방식을 PTQ(Post-Training Quantization, 학습 후 양자화)라 한다. float32 가중치 w를 INT8로 바꾸는 수식은 이렇다.
scale = (max(w) - min(w)) / 255
zero_point = round(-min(w) / scale)
w_int8 = round(w / scale) + zero_pointscale은 실수 범위를 256단계(0~255)에 욱여넣기 위한 한 칸의 크기다. zero_point는 실수 0이 정수 축에서 어디에 오는지를 맞추는 기준점이다. 실행할 때는 역으로 풀어 근삿값을 쓴다.
w_fp32 ≈ (w_int8 - zero_point) * scale파라미터당 4바이트가 1바이트로 줄어드니 이론상 4배 압축이다. 실제 예로 ViT-B/32 분류 모델은 FP32 약 330MB에서 INT8 약 85MB로 줄어든다.
정확도는 얼마나 손해 보나
해상도를 낮췄으니 정확도 손실이 있다. 하지만 작다. 이미지 분류에서 INT8 PTQ의 정확도 저하는 ImageNet top-1 기준 보통 0.5~1% 수준이다. 모델 크기가 4배, 추론 속도가 크게 개선되는 대가로 정확도 1% 미만을 내주는 거래다. 배포 크기와 속도가 정확도 소수점보다 중요한 온디바이스 환경에서는 일반적으로 감수할 만하다.
양자화에는 두 방식이 있다.
| 방식 | 활성화 값 범위 측정 | 캘리브레이션 데이터 | 효과 |
|---|---|---|---|
| Dynamic Quantization | 실행 중 실시간 측정 | 불필요 | 크기 위주 개선 |
| Static Quantization | 사전에 대표 데이터로 측정 | 필요 | 크기 + 속도 개선 |
Dynamic은 추가 데이터 없이 간편하지만 주로 크기만 줄인다. Static은 대표 입력 묶음(캘리브레이션 데이터셋)으로 활성화 값의 범위를 미리 재두기 때문에 크기와 속도를 함께 개선하지만, 그 측정 단계가 추가된다. 모델을 끝까지 빠르게 하려면 Static이 낫다.
이점과 트레이드오프
이점:
- 프레임워크 독립: 학습 프레임워크 없이 가벼운 실행기로 어디서나 돌린다.
- 크기·속도: INT8 양자화로 4배 작아지고 빨라진다.
- 배포 단순화: 모델이 파일 하나로 정리된다.
감수하는 것:
- 정확도 소폭 손실: INT8 기준 top-1 0.5~1%.
- 변환 검증 필요: 내보내기와 양자화 후 원래 모델과 결과가 같은지 확인하는 단계가 든다. 일부 연산자는 ONNX 규격에 없거나 양자화에 민감해 따로 손봐야 한다.
- 동적 구조 취약: 입력에 따라 계산 그래프가 바뀌는 모델은 고정 그래프로 내보내기 까다롭다.
정리하면 ONNX와 INT8 양자화는 "학습 환경의 풍부함"을 "배포 환경의 가벼움"과 맞바꾸는 단계다. 이렇게 포장한 모델을 실제로 폰 안에서 실행하는 런타임(WASM)은 다른 글에서 다룬다.
'TIL' 카테고리의 다른 글
| MediaPipe Tasks Vision — 브라우저에서 손과 얼굴을 추적하는 법 (0) | 2026.06.08 |
|---|---|
| WASM 온디바이스 추론 — 서버 없이 폰 안에서 모델 돌리기 (0) | 2026.06.07 |
| LoRA — 모델 전체를 재학습하지 않고 일부만 바꾸는 법 (0) | 2026.06.07 |
| KNN과 근사 최근접 이웃 — 벡터 검색은 어떻게 빨라지나 (0) | 2026.06.07 |
| 임베딩과 대조학습 — 학습 없이 분류하는 제로샷의 원리 (0) | 2026.06.07 |