동일 모델을 FP8로 서빙하면 BF16보다 빠르다는 건 조건이 붙은 말이다. 배치 크기가 크고, 입력 시퀀스가 길고, H100처럼 FP8 Tensor Core가 탑재된 GPU를 쓸 때. 이 조건 중 하나라도 빠지면 순위가 바뀐다.
batch=1 decode 구간에서는 W4A16(AWQ/GPTQ)이 per-tensor FP8보다 빠른 경우가 실제로 생긴다. "정밀도가 낮을수록 빠르다"는 직관은 prefill에서는 맞지만 decode에서는 어긋난다. 이 역전이 왜 일어나는지를 하드웨어 연산 경로부터 풀어보자.
하드웨어 세대가 전제를 바꾼다
FP8 Tensor Core는 H100(Hopper)에서 처음 등장했다. A100의 최저 정밀도 Tensor Core는 INT8이다. A100에서 FP8 모델을 올리면 FP8 Tensor Core 가속 경로가 없고, Transformer Engine 없이는 CUDA core로 fallback한다. A100 환경 벤치마크를 H100에 그대로 적용하거나 반대 방향으로도, 결론이 달라진다.
NVIDIA H100 데이터시트 기준으로 H100 FP8 dense FLOPS는 약 1,979 TFLOPS이고 BF16은 989 TFLOPS — 이론 배수는 정확히 2배다. FP8 Tensor Core가 작동하려면 행렬 크기가 16의 배수여야 하고, 입력 텐서가 E4M3(가중치·활성화용) 또는 E5M2(그래디언트용) 포맷이어야 한다. E4M3는 지수 4비트·가수 3비트 구조로 표현 범위가 [-448, 448]이고, E5M2는 지수 5비트·가수 2비트로 범위가 더 넓다. 실제 서빙에서는 가중치와 활성화 모두 E4M3이 표준이다.
prefill처럼 행렬 연산이 큰 구간에서는 이 이론 배수에 꽤 근접하게 수렴한다. 문제는 decode에서 나타난다.
Arithmetic Intensity: decode가 FP8을 살리지 못하는 이유
LLM 추론은 prefill과 decode로 나뉜다. prefill은 입력 전체를 한 번에 행렬 연산하기 때문에 batch 안의 모든 토큰이 하나의 GEMM에 참여한다. 행렬이 크면 GPU의 FLOPS가 실제 병목 — compute-bound다.
decode는 다르다. 한 스텝마다 토큰 하나씩 생성하고, 배치가 작으면 행렬 연산에서 처리하는 데이터가 극도로 줄어든다. Arithmetic intensity는 연산량(FLOP)을 데이터 이동량(byte)으로 나눈 값인데, batch=1 BF16 decode에서는 약 1 FLOP/byte 수준으로 떨어진다. H100이 compute-bound로 전환되는 임계점은 BF16 기준 약 295 FLOP/byte — batch=1 decode는 이 임계점의 0.3%에 불과하다.
이미 메모리 대역폭이 병목인 상태에서 FP8으로 FLOPS를 2배 올려봤자 속도는 올라가지 않는다. 이 구간에서는 W4A16이 이긴다. 가중치를 4비트로 저장하면 메모리에서 읽어야 할 바이트 수가 BF16 대비 4분의 1이다. 대역폭이 병목이므로, 가중치 전송량이 줄면 처리 속도도 그만큼 빨라진다.
Granularity가 decode throughput을 깎는 방식
W4A16이 decode에서 유리하다고 해도, granularity가 변수다.
AWQ·GPTQ 기반 W4A16은 대부분 per-group(group size=128)으로 양자화한다. 각 그룹마다 별도의 FP16 스케일과 zero-point를 저장하고, 연산 직전에 dequantization을 거쳐 FP16 MMA로 보낸다. per-tensor FP8은 텐서 전체에 스케일이 하나다. 두 방식의 dequantization 비용 차이가 크다.
per-group W4A16은 그룹 수만큼 추가 메모리 읽기와 연산이 발생한다. 70B 모델에서 group size=128이면 가중치 텐서 하나당 수백 개의 스케일 벡터를 별도로 로드해야 한다. 이 overhead가 decode에서 두드러진다. decode는 이미 memory-bound인데 per-group 스케일·zero-point 로드가 추가 메모리 트래픽을 만들기 때문이다. batch=1~4의 낮은 concurrency에서는 per-group W4A16이 per-tensor FP8보다 느려지는 지점이 생긴다.
prefill에서는 반대다. 행렬이 충분히 크면 4비트 가중치의 대역폭 절약이 dequantization overhead를 압도한다.
per-channel quantization(채널별 스케일, zero-point 없음)은 두 방식의 중간이다. per-group보다 overhead가 작고 정확도는 그보다 낮다. batch=1 서빙에서 per-channel이 per-group보다 나은 trade-off를 보이는 경우가 있다.
배치 크기가 바뀌면 순위가 바뀐다
NVIDIA TensorRT-LLM 벤치마크(H100 80GB, input 1024 토큰, output 128 토큰, FP16 대비 speedup):
| 포맷 | LLaMA-v2-7B batch=1 | LLaMA-v2-7B batch=8 |
|---|---|---|
| FP8 | 1.51× | 1.40× |
| INT8 SQ | 1.47× | 1.32× |
batch=1에서 FP8 speedup이 1.51×이지만 batch=8에서는 1.40×으로 줄어든다. output token 생성 비중이 늘수록 memory-bound 구간이 늘어나고, FP8의 FLOPS 이점이 희석된다.
최대 throughput에서는 다르다. GPT-J 6B, batch=64에서 H100 FP8은 10,907 tok/s, A100 FP16은 3,679 tok/s였다. TTFT를 500ms 이하로 제한할 때 batch=16에서 FP8이 FP16 대비 2.3× 속도 향상을 달성했다 — prefill이 dominant한 긴 입력 시나리오에서 FP8 Tensor Core의 이점이 실측으로 나타나는 구간이다.
대형 모델에서는 비용 효율 격차가 더 벌어진다. "Give Me BF16 or Give Me Death" 논문(2024)의 405B 모델 H100 동기식 서빙 결과:
| 포맷 | 레이턴시 | 비용 효율 |
|---|---|---|
| BF16 | 15.0s | 5 queries/USD |
| FP8 | 7.8s | 19 queries/USD |
| INT4 | 7.8s | 37 queries/USD |
레이턴시는 FP8과 INT4가 같지만 비용 효율에서 INT4가 2배 가까이 앞선다. 같은 레이턴시에서 INT4는 메모리 절약으로 replica를 더 많이 띄울 수 있기 때문이다.
KV 캐시 양자화를 가중치 양자화와 같이 쓸 때
vLLM에서 가중치 FP8과 KV 캐시 FP8을 동시에 적용:
vllm serve meta-llama/Llama-3-8B \
--quantization fp8 \
--kv-cache-dtype fp8
AWQ(W4A16) 가중치에 FP8 KV 캐시를 조합하면:
vllm serve meta-llama/Llama-3-8B \
--quantization awq \
--kv-cache-dtype fp8
두 양자화를 동시에 적용하면 메모리 절약은 곱연산으로 커진다. BF16 가중치 + BF16 KV 캐시 기준(70B 모델 약 140GB) 대비 FP8 가중치 + INT8 KV 캐시로 전환하면 가중치가 절반, KV 캐시도 절반으로 줄어 총 GPU 메모리 점유가 50~55% 수준까지 내려갈 수 있다.
오차도 겹친다. 가중치 양자화 오차는 임베딩에 가까운 초반 레이어와 출력에 가까운 후반 레이어에서 집중되는 경향이 있다. KV 캐시 양자화 오차는 attention score가 peaked되는 구간에서 두드러지는데, GQA 헤드 수가 적고 context가 길수록 심해진다. 두 오차가 겹치는 레이어는 모델의 GQA 비율과 레이어 깊이에 따라 다르다.
vLLM은 특정 레이어를 KV 캐시 양자화에서 제외하는 옵션을 제공한다:
vllm serve <model> \
--kv-cache-dtype fp8 \
--kv-cache-dtype-skip-layers 0 1 23
초반·후반 레이어 몇 개를 BF16 KV 캐시로 남기면 정확도 손실을 최소화하면서 메모리 절약 대부분을 챙길 수 있다. FP8 가중치 양자화의 MMLU 정확도 손실은 TRT-LLM 기준 0.21%~0.89%, AWQ(INT4)는 0.85%~2.11%다.
어떤 포맷을 먼저 시도해야 하는가
하드웨어부터 확인한다. A100이면 FP8 Tensor Core가 없으므로 가중치 서빙에 FP8을 써도 FLOPS 이득이 없다. A100에서는 INT8(W8A8)이 양자화 가속의 실용적인 시작점이다.
H100 이상이면 서비스의 병목이 어디인지 본다. TTFT SLA가 엄격한 서비스(긴 문서 요약, RAG 파이프라인)는 prefill이 critical path다. 배치가 크고 입력이 긴 이 구간에서 FP8 Tensor Core가 실제로 작동하고, throughput 이득도 실측에서 나타난다. TPOT SLA가 엄격한 저지연 채팅은 decode가 critical path이고 concurrency가 낮다 — W4A16이 더 잘 맞는 시나리오다.
70B 이상 대형 모델에서 GPU 메모리가 빠듯하면 INT4(AWQ/GPTQ)로 replica 수를 늘리는 게 같은 인프라 비용에서 throughput을 높이는 더 직접적인 방법이다. 405B 서빙에서 INT4가 FP8 대비 비용당 처리량을 2배 가까이 냈다는 수치가 이를 뒷받침한다.
H200은 Tensor Core 스펙이 H100과 동일하고 HBM3e로 메모리 대역폭이 늘었다. decode-bound 시나리오에서는 H200의 넓어진 대역폭이 W4A16의 상대적 이점을 줄여, H100보다 FP8과의 격차가 좁아질 가능성이 높다.