-
Notifications
You must be signed in to change notification settings - Fork 0
Vineyard Wildlife INT8 Quantization Diagnosis
처음에는 "ncnn FP16으로 10 FPS 나왔으니 INT8로 가면 더 빨라지겠지" 정도로 가볍게 시작했습니다. 그러나 결과는:
- imgsz=320: mAP50-95 0.684 → 0.473 (-31%p)
- imgsz=640: mAP50-95 0.787 → 0.000 (detection 0건, 완전 실패)
이 문서는 단순히 "INT8이 안 됐다"가 아니라, 어디서 무엇이 무너졌고 어떻게 진단했는지 정리합니다. 양자화가 한 줄 옵션이 아니라 여러 단계의 의사결정 사슬이라는 점을 가장 잘 보여주는 트랙입니다.
처음 시도한 코드:
quantize_static(
"yolo11n.onnx", "yolo11n_int8.onnx",
calibration_data_reader=calib_reader,
quant_format=QDQ,
weight_type=QInt8,
activation_type=QInt8,
calibrate_method=MinMax,
)- 양자화 자체는 성공 (파일 정상 생성)
- RPi에서 추론도 됨 (속도는 빨라짐)
- 그러나 mAP가 무너짐

| 단계 | 전처리 |
|---|---|
| Calibration (내가 짠 reader) | PIL → resize(320, 320) → /255 (squash) |
| 추론 (ultralytics 기본) | letterbox padding → /255 (aspect ratio 보존) |
squash로 만든 통계로 letterbox 입력을 양자화하니 activation 분포가 어긋나서 quantization scale이 잘못 잡힘. 이것만으로도 큰 정확도 손실 발생.
YOLO의 마지막 detection head는:
- sigmoid (confidence)
- exp (anchor decoding)
- 큰 dynamic range (objectness 0~1, box coordinate는 픽셀 단위)
INT8 256단계로 표현하면 confidence 0.55 ~ 0.65 영역 같은 미세한 값들이 같은 정수로 뭉개져서 NMS 통과 객체가 사라집니다.
onnxruntime의 quantize_static은:
- weights: per_channel 지원
- activations: per_tensor만
YOLO의 multi-scale feature pyramid는 layer마다 분포 편차가 커서 per_tensor 하나의 scale로 묶으면 손실이 큽니다.
MinMax는 calibration 데이터의 max/min을 그대로 quantization range로 씁니다. 한 장의 outlier 이미지가 max를 크게 끌어올리면 나머지 정상 분포가 다 좁은 범위로 압축됩니다.
# 1) calibration reader도 letterbox로 통일
def preprocess(img):
return letterbox(img, new_shape=320, stride=32, auto=False)
# 2) detection head 마지막 6개 conv를 양자화에서 제외
nodes_to_exclude = get_last_n_conv_nodes(onnx_model, n=6)
# 3) calibrate_method 변경
quantize_static(
...,
calibrate_method=CalibrationMethod.Percentile, # outlier robust
nodes_to_exclude=nodes_to_exclude,
per_channel=True,
quant_format=QDQ,
weight_type=QInt8,
activation_type=QInt8,
)
| imgsz | v1 | v2 | 변화 |
|---|---|---|---|
| 320 | 0.473 | 0.545 | +7%p (부분 개선) |
| 640 | 0.000 | 0.000 | 변화 없음 (완전 실패) |
640 imgsz의 더 큰 activation map에서 onnxruntime ARM EP의 INT8 처리에 구조적 한계가 있는 것으로 추정. 우리 환경(RPi 4 + Python 3.13 + onnxruntime 1.24)에서는 현 시점 INT8을 deployment에 사용 불가.
활성화 텐서 크기가 4배가 되면서:
- 분포 추정에 들어가는 outlier 영향이 커짐
- 작은 confidence 값이 INT8 quantization 후 0으로 뭉개지는 비율이 늘어남
- ARM EP 내부 INT8 커널이 큰 feature map에서 누적 오차를 더 키움
확정적인 단정은 어렵지만, "정확히 어디가 망가졌는지" 는 320 vs 640 비교로 분명해졌습니다.
| 트랙 | 가능성 | 비용 | 현재 상태 |
|---|---|---|---|
| ncnn INT8 | 높음 |
ncnn2table + ncnn2int8 시스템 바이너리 컴파일, 1~2일 셋업 |
일정 압박으로 보류 |
| TFLite INT8 | 낮음 | tflite-runtime이 RPi Python 3.13 wheel 미제공 | 사실상 차단 |
| 양자화 인지 학습(QAT) | 중간 | 처음부터 fake-quant 노드로 재학습 필요 | 일정 무리, 다음 분기 |
| 더 작은 모델로 교체 | 가능 | 정확도 손실 | 현재는 ncnn FP16이 충분해서 불필요 |
ncnn FP16을 deployment 베이스라인으로 확정.
이유:
- ncnn FP16이 이미 5 FPS 목표를 +96% 헤드룸으로 통과 (10.03 FPS)
- 정확도 손실 0%
- INT8을 굳이 갈 이유가 없음 (속도 +85% 추가, 정확도 -31%p~100% 손실)
INT8은 향후 RPi 5 / Hailo-8L / Jetson 같은 디바이스 비교 트랙이나, 모델이 더 무거워졌을 때 다시 검토할 카드로 보존.
처음엔 int8=True 같은 옵션 한 줄이면 끝일 줄 알았습니다. 실제로는 calibration 전처리 일치, head exclusion, calibration method, per_channel/per_tensor까지 챙겨야 작동하고, 그마저도 백엔드 한계에 막힐 수 있습니다.
시도 1만 보고 "INT8 안 됨" 으로 끝냈으면 시도 2의 +7%p 개선과 320 vs 640의 다른 양상은 보지 못했을 것입니다. 실패의 원인을 4가지 후보로 분리하는 것이 다음 결정의 근거가 됩니다.
INT8을 안 가도 되는 이유가 "FP16이 이미 5 FPS 목표를 두 배로 넘긴다" 는 점이었습니다. 양자화는 "할 수 있어서" 가 아니라 "필요해서" 가는 것.
ultralytics CLI / onnxruntime / ncnn / TFLite 모두 INT8을 지원한다고 표면상 말하지만, 실제 deployment 환경에서 작동하는 조합은 좁습니다. "프로덕션 양자화는 framework 레벨이 아니라 runtime 레벨에서 정해진다" 가 가장 큰 학습이었습니다.
- RPi 4 추론 백엔드 비교 — 최종적으로 ncnn FP16을 선택한 비교 근거
- 야생동물 5종 multi-class 학습 변천사 — 양자화 대상 모델의 학습 과정
- 카메라 실시간 검출 MVP — FP16 deployment의 실제 운용 결과
Deepvisions | AI Engineer 2026.03 ~ 재직중
2026.05 ~ | @ Deepvisions 캠퍼스 CCTV 4대 · 자전거 OCR + 차량 공회전 다중 신호
2026.04 ~ | @ Deepvisions 포도밭 침입 탐지 (5종 multi-class · 라즈베리파이 4 실시간)
2026.03 ~ | @ Deepvisions 드론 이미지 기반 객체 탐지 + GSD calibration + 수확량 예측
- 프로젝트 메인
- 관련 연구 종합 + 한계 (2026-05) ← 최신
- 수확량 close-up 4장 + 3-Model (2026-05-19)
- 드론 포도 수확량 예측 — 파이프라인 (2026-05)
- 드론 포도송이 탐지 — 학습 변천사 (2026-04)
- SAM3 vs Fine-tuned YOLO
- Grounding DINO vs YOLO Top3 비교 요약
- YOLO Baseline Top3 비교 요약
- YOLO Model Comparison Summary
- 포도 탐지를 위한 데이터 수집
- 포도 수확량 측정을 위한 Object Detection
2025.03 ~ 2025.08 | 카카오테크부트캠프 | ✅ 종료 AI 기반 데스크테리어 추천 서비스
- Name: Woody (이동재)
- Focus: Vision AI, LLM Integration, Backend Engineering
- GitHub: @ehdwo0427
- Email: ehdwo0427@naver.com
- 포트폴리오 : 포트폴리오