FP8 W8A8 양자화
FP8 W8A8 양자화 (FP8 W8A8)
FP8(8비트 부동소수점)은 NVIDIA H100, AMD MI300X 같은 GPU의 하드웨어 가속을 활용해 웨이트와 활성화를 모두 8비트로 압축하는 방식이에요. 이 페이지에서는 vLLM에서 FP8 W8A8 모델을 만들어 배포하는 과정을 단계별로 살펴볼게요.
FP8의 두 표현 (Two FP8 representations)
하드웨어에서 일반적으로 지원되는 FP8 타입은 상황에 따라 쓰임새가 다른 두 가지가 있어요.
- E4M3: 부호 1비트, 지수 4비트, 가수 3비트. 최대 ±448과 nan 값을 표현해요.
- E5M2: 부호 1비트, 지수 5비트, 가수 2비트. 최대 ±57344, ±inf, nan을 표현해요. 동적 범위(dynamic range)가 커진 대신 저장되는 값의 정밀도는 낮아지죠.
FP8 양자화는 모델 메모리 요구량을 약 2배 줄이고, 정확도 영향은 최소화하면서 처리량을 최대 1.6배까지 개선할 수 있어요. vLLM에서 바로 쓸 수 있는 인기 LLM의 FP8 체크포인트 컬렉션도 HuggingFace에 올라와 있으니 참고하세요.
참고: FP8 연산은 NVIDIA compute capability ≥ 8.9(Ada Lovelace, Hopper, Blackwell) GPU에서 지원돼요. compute capability ≥ 7.5(Turing) GPU에서는 FP8 Marlin 커널로 웨이트 온리(W8A16) 방식으로 돌아갑니다.
GEMM 커널 선택 (GEMM kernel selection)
vLLM은 로드 시점에 FP8 GEMM 커널을 자동으로 선택해요. 블록 양자화 체크포인트에서 CUDA라면 순서대로 FlashInfer/DeepGEMM 하이브리드(Hopper 전용), DeepGEMM, CUTLASS, Marlin, Triton, Humming, 그리고 PyTorch 폴백을 시도하죠. 네이티브 FP8을 지원하지 않는 GPU(Turing/Ampere 등)는 웨이트 온리(W8A16) Marlin으로 떨어집니다.
추론이 오류 없이 멈추면 VLLM_USE_DEEP_GEMM=0 또는 --linear-backend cutlass를 시도해 보세요. --linear-backend는 양자화된 선형 레이어에만 영향을 주고, MoE 전문가는 별도의 --moe-backend로 제어해요. 명시적으로 지정한 백엔드가 하드웨어에서 지원되지 않으면 폴백 없이 오류를 냅니다.
설치 (Installation)
성능 좋은 FP8 양자화 모델을 만들려면 llm-compressor 라이브러리를 설치해야 해요.
(venv-llm-compressor) pip install llmcompressor
평가를 위해 vllm과 lm-evaluation-harness도 설치해요.
(venv-vllm) pip install vllm "lm-eval[api]>=0.4.12"
참고: vLLM과 llm-compressor는 호환되지 않을 수 있으니 별도 환경에서 쓰는 걸 권장해요.
양자화 과정 (Quantization process)
양자화 과정은 세 단계로 나뉘어요.
1. 모델 로딩 (Loading the model)
표준 transformers AutoModel 클래스로 모델과 토크나이저를 로딩해요.
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
device_map="auto",
dtype="auto",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
2. 양자화 적용 (Applying quantization)
FP8에서는 단순한 RTN 양자화로도 정확도를 회복할 수 있어요. 웨이트는 정적·채널별(per-channel), 활성화는 동적·토큰별(per-token) 방식인 FP8_DYNAMIC 스킴으로 모든 Linear 레이어를 타겟팅하는 걸 권장해요. RTN은 웨이트 양자화에 데이터가 필요 없고 활성화도 동적으로 양자화되니, 캘리브레이션 데이터가 필요 없어요.
from llmcompressor import oneshot
from llmcompressor.modifiers.quantization import QuantizationModifier
# 간단한 PTQ 양자화 구성
recipe = QuantizationModifier(
targets="Linear",
scheme="FP8_DYNAMIC",
ignore=["lm_head"],
)
# 양자화 알고리즘 적용
oneshot(model=model, recipe=recipe)
# Meta-Llama-3-8B-Instruct-FP8-Dynamic 저장
SAVE_DIR = MODEL_ID.split("/")[1] + "-FP8-Dynamic"
model.save_pretrained(SAVE_DIR)
tokenizer.save_pretrained(SAVE_DIR)
3. 정확도 평가 (Evaluating accuracy)
vLLM으로 모델을 로딩해 실행해요.
from vllm import LLM
llm = LLM("./Meta-Llama-3-8B-Instruct-FP8-Dynamic")