Train High, Infer Low - 머신러닝 학습과 서빙의 FP32, FP16, BF16, INT8 정밀도 선택
머신러닝 모델을 프로덕션에 배포할 때 가장 많이 고민하는 것 중 하나가 바로 수치 정밀도(Numerical Precision) 선택입니다. FP32로 학습한 모델을 FP16으로 서빙해도 될까? INT8 양자화는 언제 해야 할까? 이번 글에서는 정밀도 선택 전략을 정리했습니다.
TL;DR - 바쁜 분들을 위한 요약
"Train High, Infer Low" - 학습은 높은 정밀도로, 서빙은 낮은 정밀도로
| 상황 | 추천 조합 | 메모리 절감 | 안정성/품질 | 비고 |
|---|---|---|---|---|
| LLM 학습/서빙 | FP32+BF16 Mixed 학습 → BF16 추론 | 50% | ⭐⭐⭐⭐⭐ | 가장 일반적인 선택, 넓은 범위(±3.4×10³⁸), 수치 안정성 우수 |
| 고성능 서빙 | FP32 학습 → BF16 추론 | 50% | ⭐⭐⭐⭐⭐ | A100, H100 등 최신 GPU 권장 |
| 컴퓨터 비전 추론 (제한적) | FP32 학습 → FP16 추론 | 50% | ⭐⭐⭐ | ⚠️ 오버플로우 위험 (범위 ±65K) |
| 모바일/엣지 디바이스 | FP32 학습 → INT8 추론 (QAT) | 75% | ⭐⭐ | 정확도 손실 1~5%, 정수 표현으로 제한적, 양자화 작업 필요 |
핵심: FP16은 정밀도는 높지만 표현 범위가 좁아서(최대값 65,504) 오버플로우 위험이 있습니다. INT8은 메모리 효율은 최고지만 정확도 손실이 가장 큽니다. 실무에서는 BF16이 가장 안정적이고 범용적입니다.
수치 정밀도, 왜 중요한가?
모델 서빙 시 정밀도 선택은 다음 세 가지에 직접적인 영향을 미칩니다:
- 추론 속도: FP16은 FP32 대비 최대 2배, INT8은 최대 4배 빠릅니다
- 메모리 사용량: 정밀도를 낮추면 모델 크기가 절반~1/4로 감소합니다
- 정확도: 정밀도를 낮추면 0.1%~5%의 정확도 손실이 발생할 수 있습니다
핵심 데이터 타입 4가지
FP32 (Float32) - 학습의 표준
구조: [1bit 부호][8bit 지수][23bit 가수] = 32bit
표현 범위: ±3.4 × 10³⁸
정밀도: 약 7~8자리
언제 사용?
- 모델 학습 (Training)
- 베이스라인 정확도 측정
- 디버깅 및 검증
FP16 (Float16) - GPU 추론 가속
구조: [1bit 부호][5bit 지수][10bit 가수] = 16bit
표현 범위: ±65,504 ⚠️
정밀도: 약 3~4자리
장점: 메모리 50% 절감, 속도 2배 향상
단점: 좁은 표현 범위로 오버플로우 위험
언제 사용?
- GPU에서 추론 가속
- 컴퓨터 비전 모델 (이미지는 0~255로 정규화)
- 하드웨어가 FP16에 최적화된 경우
BF16 (BFloat16) - 두마리 토끼 잡기
구조: [1bit 부호][8bit 지수][7bit 가수] = 16bit
표현 범위: ±3.4 × 10³⁸ (FP32와 동일\\!)
정밀도: 약 2~3자리
핵심 차이: FP16은 정밀도를, BF16은 표현 범위를 선택했습니다.
FP32: [S][EEEEEEEE][MMMMMMMMMMMMMMMMMMMMMMM]
1 8비트 23비트
FP16: [S][EEEEE][MMMMMMMMMM]
1 5비트 10비트 ← 지수 축소, 정밀도 우선
BF16: [S][EEEEEEEE][MMMMMMM]
1 8비트 7비트 ← 지수 유지, 범위 우선 (FP32 상위 16비트)
비유:
- FP16 = 고성능 현미경 (세밀하지만 시야 좁음)
- BF16 = 고성능 망원경 (시야 넓지만 세밀함 떨어짐)
언제 사용?
- 대규모 언어 모델 (LLM) 학습 및 추론
- TPU 또는 최신 GPU 사용 시
- Gradient 안정성이 중요한 경우
INT8 - 엣지 디바이스의 필수
구조: 8bit 정수
표현 범위: -128 ~ 127 (또는 0 ~ 255)
메모리: FP32의 25%
장점: 매우 작은 메모리, 빠른 추론, 낮은 전력 소모
단점: 양자화 과정 필요, 1~5% 정확도 손실
언제 사용?
- 모바일/엣지 디바이스 배포
- 대규모 서빙 시스템 (비용 절감)
- 실시간 처리가 필요한 경우
Mixed Precision Training (AMP)
최근 서빙에서는 Mixed Precision을 사용하는 것이 표준입니다.
Pure vs AMP
Pure BF16 (모든 연산을 BF16으로):
model = model.bfloat16()
output = model(input.bfloat16())
BF16 AMP (자동으로 섞어서 사용, 권장):
with torch.autocast(device_type='cuda', dtype=torch.bfloat16):
output = model(input)
AMP는 어떻게 동작하나?
| 연산 종류 | 사용 정밀도 | 이유 |
|---|---|---|
| Matmul, Conv | BF16 | 계산 집약적, 속도 중요 |
| ReLU, Pooling | BF16 | 단순 연산 |
| Softmax | FP32 | 수치 안정성 중요 (exp 연산) |
| LayerNorm | FP32 | 통계 계산, 정밀도 중요 |
| Loss 계산 | FP32 | 정확한 손실 값 필요 |
하드웨어 지원 체크하기
GPU
| 하드웨어 | FP32 | FP16 | BF16 | INT8 |
|---|---|---|---|---|
| NVIDIA GPU (Ampere+) | ✓ | ✓ | ✓ | ✓ |
| NVIDIA GPU (Turing) | ✓ | ✓ | △ | ✓ |
| Google TPU | ✓ | ✓ | ✓ | ✓ |
| Apple Silicon | ✓ | ✓ | △ | ✓ |
CPU
Intel CPU:
| 세대 | 모델 | BF16 지원 | 가속 기술 | 성능 |
|---|---|---|---|---|
| 4세대 Xeon | Sapphire Rapids (2023+) | ✓ | AMX | 🚀 최고 (2~4배) |
| 3세대 Xeon | Ice Lake (2020+) | ✓ | AVX-512 BF16 | ⚡ 우수 (1.5~2배) |
| Core 13/14세대 | Raptor Lake (2022+) | ✓ | AVX-512 (일부) | ⚡ 우수 |
| 구형 | Cascade Lake 이전 | X | - | - |
AMD CPU:
| 세대 | 모델 | BF16 지원 |
|---|---|---|
| EPYC Genoa | 4세대 (2022+) | ✓ |
| Ryzen 7000 | Zen 4 (2022+) | ✓ |
| 구형 | Zen 3 이전 | X |
ARM CPU:
| 세대 | 모델 | BF16 지원 |
|---|---|---|
| AWS | Graviton3 (2022+) | ✓ |
| Apple | M3/M4 (2023+) | ✓ |
| 구형 | Zen 3 이전 | X |
import torch
# CPU BF16 지원 확인
if torch.cpu.amp.autocast_mode.is_autocast_available('cpu'):
print("CPU BF16 지원됨\\!")
# CPU BF16 AMP 사용
with torch.cpu.amp.autocast():
output = model(input)
결론
수치 정밀도 선택은 정확도, 성능, 비용의 트레이드오프입니다.
학습과 서빙의 정밀도를 반드시 맞출 필요는 없습니다. 오히려 다른 정밀도를 사용하는 것이 일반적입니다. FP32로 서빙한것과 BF16, FP16 으로 서빙했을때의 결과 품질이 어느정도의 차이를 보이는데 각 모델이나 서비스마다 직접 테스트 하면서 결정해야 합니다.
각 단계에서 정확도를 측정하고, 비즈니스 요구사항에 맞는 최적점을 찾는 것이 핵심입니다. "Train High, Infer Low" 전략으로 시작해서 점진적으로 최적화하세요.
참고 자료:
- PyTorch AMP: https://pytorch.org/docs/stable/amp.html
- TensorFlow Mixed Precision: https://www.tensorflow.org/guide/mixed_precision
- NVIDIA Quantization Toolkit: https://github.com/NVIDIA/TensorRT-Model-Optimizer