[vLLM] FP8: 8비트 부동소수점 양자화
들어가며
INT4/INT8 양자화가 정수 연산에 의존한다면, FP8은 부동소수점의 표현력을 유지하면서 비트 수를 절반으로 줄이는 접근이다. NVIDIA의 Hopper(H100) 아키텍처에서 하드웨어 수준의 FP8 지원이 도입되면서, FP8은 LLM 추론에서 가장 실용적인 양자화 포맷으로 부상했다. E4M3(지수 4비트, 가수 3비트) 포맷은 FP16 대비 절반의 메모리만 사용하면서도, 정수 양자화보다 넓은 동적 범위를 제공한다.
공식 문서
vLLM 공식 문서: FP8 Quantization
핵심 구조/코드 분석
Fp8Config: 온라인 vs 오프라인
vllm/model_executor/layers/quantization/fp8.py의 Fp8Config는 두 가지 양자화 모드를 지원한다.
class Fp8Config(QuantizationConfig):
"""Config class for FP8."""
def __init__(
self,
is_checkpoint_fp8_serialized: bool = False,
activation_scheme: str = "dynamic",
ignored_layers: list[str] | None = None,
weight_block_size: list[int] | None = None,
) -> None:
self.is_checkpoint_fp8_serialized = is_checkpoint_fp8_serialized
self.activation_scheme = activation_scheme # "static" or "dynamic"
self.weight_block_size = weight_block_size
핵심 분기 로직은 get_quant_method에 있다:
def get_quant_method(self, layer, prefix):
if isinstance(layer, LinearBase):
if not self.is_checkpoint_fp8_serialized:
online_method = Fp8OnlineLinearMethod(self)
return online_method
else:
offline_method = Fp8LinearMethod(self)
return offline_method
elif isinstance(layer, FusedMoE):
if self.is_checkpoint_fp8_serialized:
return Fp8MoEMethod(self, layer)
else:
return Fp8OnlineMoEMethod(self, layer)
elif isinstance(layer, Attention):
return Fp8KVCacheMethod(self)
| 모드 | 클래스 | 설명 |
|---|---|---|
| 온라인 | Fp8OnlineLinearMethod |
FP16 체크포인트를 로딩 시 실시간 양자화 |
| 오프라인 | Fp8LinearMethod |
미리 양자화된 FP8 체크포인트 사용 |
| MoE 온라인 | Fp8OnlineMoEMethod |
MoE 전문가를 실시간 양자화 |
| MoE 오프라인 | Fp8MoEMethod |
양자화된 MoE 체크포인트 사용 |
| KV 캐시 | Fp8KVCacheMethod |
KV 캐시를 FP8로 저장 |
블록 양자화 (Block Quantization)
FP8의 가장 중요한 발전 중 하나는 블록 단위 스케일링이다. weight_block_size가 지정되면 텐서 전체가 아닌 작은 블록마다 독립적인 스케일을 유지한다:
if weight_block_size is not None:
if not is_checkpoint_fp8_serialized:
raise ValueError(
"The block-wise quantization only supports fp8-serialized "
"checkpoint for now."
)
if len(weight_block_size) != 2:
raise ValueError(
"The quantization block size of weight must have 2 dimensions"
)
if activation_scheme != "dynamic":
raise ValueError(
"The block-wise quantization only supports dynamic activation scheme"
)
블록 양자화의 제약사항이 명확히 드러난다: 오프라인 체크포인트 전용이며, 반드시 동적 활성화 스킴과 함께 사용해야 한다. 이는 DeepSeek-V3 등의 모델에서 사용하는 128x128 블록 FP8과 직결된다.
스케일링 전략 체계
코드에서 import하는 유틸리티 함수들이 FP8의 다양한 스케일링 전략을 보여준다:
from vllm.model_executor.layers.quantization.utils.quant_utils import (
kFp8Dynamic128Sym, # 128 블록 동적 대칭
kFp8DynamicTensorSym, # 텐서 단위 동적 대칭
kFp8DynamicTokenSym, # 토큰 단위 동적 대칭
kFp8Static128BlockSym, # 128 블록 정적 대칭
kFp8StaticTensorSym, # 텐서 단위 정적 대칭
)
텐서 단위는 전체 가중치 텐서에 하나의 스케일을 사용하고, 블록 단위(128)는 더 세밀하게 스케일을 관리한다. "정적"은 캘리브레이션 데이터로 미리 계산한 스케일을 쓰고, "동적"은 실행 시점에 계산한다.
KV 캐시 양자화
Fp8KVCacheMethod는 Attention 레이어에 적용되어 KV 캐시를 FP8로 저장한다. 이는 가중치 양자화와 독립적으로 적용할 수 있어, 긴 시퀀스에서 KV 캐시 메모리를 절반으로 줄인다.
왜 이 설계인가
1. 이중 경로 아키텍처: 온라인 양자화는 기존 FP16 모델을 즉시 FP8로 변환할 수 있어 접근성이 높고, 오프라인 양자화는 미리 최적화된 스케일로 더 높은 정확도를 달성한다. 두 경로를 모두 지원하는 것은 사용자의 워크플로우에 따른 유연성을 제공한다.
2. 블록 양자화의 필수성: 텐서 전체에 하나의 스케일을 사용하면, 이상치(outlier) 하나가 전체 텐서의 정밀도를 떨어뜨린다. 128x128 블록으로 나누면 이상치의 영향이 해당 블록에 국한된다.
3. Deep GEMM 통합: use_deep_gemm 플래그는 NVIDIA의 커스텀 FP8 GEMM 커널을 사용할지 결정한다. H100/H200에서 FP8 텐서 코어를 최대한 활용하기 위한 선택이다.
4. KV 캐시 분리: 가중치 양자화와 KV 캐시 양자화를 독립적으로 제어할 수 있다. FP16 가중치 + FP8 KV 캐시 조합도 가능하여, 정확도와 메모리 효율 사이의 세밀한 트레이드오프가 가능하다.
논문 핵심 내용
FP8 Formats for Deep Learning (2209.05433) 논문은 딥러닝을 위한 두 가지 8비트 부동소수점 인코딩을 제안했다.
핵심 아이디어: E4M3(지수 4비트, 가수 3비트)과 E5M2(지수 5비트, 가수 2비트) 두 포맷을 정의했는데, E4M3은 infinity 표현을 생략하여 동적 범위를 확장한 것이 특징이다. E4M3은 가중치와 활성화에, E5M2는 그래디언트에 사용하는 것이 최적 조합이다. CNN, RNN, Transformer 등 다양한 아키텍처에서 175B 파라미터 규모의 언어 모델까지 테스트했고, FP16 학습 세션의 결과 품질과 사실상 동일한 성능을 달성했다. 기존 하이퍼파라미터를 전혀 수정하지 않고도 이 결과를 얻었다는 점이 핵심이다.
| 포맷 | 지수 비트 | 가수 비트 | 동적 범위 | 주 용도 |
|---|---|---|---|---|
| E4M3 | 4 | 3 | ±448 | 가중치, 활성화 |
| E5M2 | 5 | 2 | ±57344 | 그래디언트 |
| FP16 | 5 | 10 | ±65504 | 기존 학습/추론 |
특히 INT8 양자화가 어려웠던 언어 모델에서도 FP8 사후 양자화(post-training quantization)가 성공적으로 동작한다는 것을 보여줬다. 이는 FP8이 정수 양자화보다 더 넓은 동적 범위를 제공하기 때문이고, H100 GPU에서 하드웨어 네이티브로 지원되면서 실용성이 극대화된 거다.
마무리
FP8은 하드웨어 수준의 지원 덕분에 INT4 양자화보다 더 적은 정확도 손실로 2배 메모리 절약을 달성한다. vLLM의 FP8 구현은 온라인/오프라인, 텐서/블록, 정적/동적의 다양한 조합을 지원하여, DeepSeek부터 Llama까지 폭넓은 모델에 적용할 수 있다.
관련 포스트
vLLM 의 다른글
- 이전글 [vLLM] AWQ: 활성화 인식 가중치 양자화
- 현재글 : [vLLM] FP8: 8비트 부동소수점 양자화
- 다음글 [vLLM] LoRA (Multi-LoRA Serving): 저차원 어댑터 서빙
댓글