양자화·ONNX 모델 변환
학습된 모델을 양자화하고 ONNX로 변환해 추론 성능을 비교
Repository개인 저장소
malit9999/ai-model-format-conversion-mission-16(새 탭에서 열림)무엇을 하는 미션인가
학습을 마친 분류 모델 하나를 세 가지 포맷으로 만들어 비교하는 미션입니다.
원본은 미션 13에서 Full Fine-Tuning으로
학습한 모델(final_full_ft)이고, 여기서 동적 양자화 .pth와 ONNX를 추가로 만듭니다.
정확도와 Macro F1은 같은 테스트셋(6,660개)에 같은 지표를 적용해 비교했습니다. 반면 latency는 포맷마다 실행 장치가 달라(GPU 1개 / CPU 2개) 동일 조건 비교가 아닙니다.
변환 방법
ONNX 내보내기 — 배치 크기와 문장 길이를 고정하지 않으려고 dynamic_axes를 지정했습니다.
서비스에서 들어오는 입력 길이가 매번 다르기 때문입니다.
# notebooks/modeling.ipynb — 배치·길이를 동적 축으로 열어 둔다
torch.onnx.export(
model_cpu,
(dummy_inputs["input_ids"], dummy_inputs["attention_mask"]),
ONNX_PATH,
input_names=["input_ids", "attention_mask"],
output_names=["logits"],
dynamic_axes={
"input_ids": {0: "batch_size", 1: "sequence_length"},
"attention_mask": {0: "batch_size", 1: "sequence_length"},
"logits": {0: "batch_size"},
},
opset_version=14,
)
동적 양자화 — nn.Linear만 대상으로 qint8을 적용했습니다. Transformer 계열에서 가중치
대부분이 Linear에 몰려 있는 구조를 그대로 이용한 설정입니다.
# notebooks/modeling.ipynb — Linear 레이어만 int8로
quantized_model = torch.quantization.quantize_dynamic(
model_for_quant,
{torch.nn.Linear},
dtype=torch.qint8,
)
세 포맷 비교 (test set 6,660개)
| 포맷 | 실행 장치 | 용량 | Accuracy | Macro F1 | latency |
|---|---|---|---|---|---|
기본 .pth | GPU | 416.20 MB | 0.8821 | 0.8448 | 2.48 ms |
양자화 .pth | CPU | 171.57 MB | 0.8577 | 0.8075 | 38.32 ms |
| ONNX | CPU | 416.40 MB | 0.8821 | 0.8448 | 67.58 ms |
이 표에서 읽히는 것
양자화는 용량을 41% 수준으로 줄였지만 정확도가 함께 내려갔습니다 (Accuracy −0.0244, Macro F1 −0.0373). 클래스별로 보면 neutral의 F1이 0.71 → 0.63으로 가장 크게 떨어집니다.
ONNX는 용량이 줄지 않았습니다(416.40 MB로 오히려 소폭 증가). 다만 정확도는 원본과 소수점 네 자리까지 동일해, 변환 과정에서 수치 손실이 없었다는 점은 확인됩니다.
latency는 같은 장치에서 측정된 값끼리만 비교할 수 있습니다. 이 실험에서 그 조건을 만족하는
것은 CPU에서 잰 두 값 — 양자화 .pth 38.32 ms와 ONNX 67.58 ms뿐입니다.
이번 실행에서는 양자화 .pth 쪽이 더 짧게 측정됐습니다. 실행 옵션을 조정하지 않은
단일 측정이라, 이 결과를 ONNX Runtime의 일반적인 성능으로 확대해 말할 수는 없습니다.
GPU에서 잰 기본 .pth(2.48 ms)는 장치가 달라 위 두 값과 함께 두지 않았습니다.
한계
- CPU에서 기본
.pth를 측정한 값이 없어, 양자화가 얼마나 빨라졌는지는 이 실험으로 말할 수 없습니다 - ONNX Runtime의 그래프 최적화 옵션이나 실행 프로바이더는 조정하지 않았습니다
- 양자화는
nn.Linear만 대상이며 임베딩·LayerNorm은 그대로입니다