한 줄 정의
FP8 E4M3는 숫자 하나를 8비트로 담는 FP8 형식이야. E4M3라는 이름은 지수 4비트, 가수 3비트를 뜻하고, 여기에 부호 1비트가 더해져 총 8비트가 돼.
이 포맷은 “더 작은 BF16”이라기보다, 큰 행렬곱과 일부 어텐션 경로에서 저장·전송 단위를 줄이기 위한 낮은 정밀도 선택지야. 같은 FP8 안에서도 E4M3는 E5M2보다 범위가 좁고 값 간격은 더 촘촘해. 그래서 보통 활성값, 모델 가중치, NVFP4 블록 스케일처럼 상대적으로 정밀도가 더 중요한 곳에서 먼저 보여.
어떻게 작동하나
부동소수점에서 지수는 값이 얼마나 커질 수 있는지를 맡고, 가수는 값 사이 간격이 얼마나 촘촘한지를 맡아. E4M3는 부호 1비트, 지수 4비트, 가수 3비트를 쓰고 최대 표현값은 약 ±448이야. E5M2는 부호 1비트, 지수 5비트, 가수 2비트를 써서 약 ±57,344까지 넓어지지만, 가수 비트가 줄어 값 간격은 더 거칠어져.
NVIDIA Transformer Engine(TE)의 기본 FP8 recipe가 이 차이를 잘 보여 줘. Format.HYBRID 예시는 forward pass에서 E4M3를 쓰고 backward pass에서 E5M2를 써. forward의 활성값과 weight tensor는 정밀도가 더 중요하고, backward의 gradient는 값 범위가 더 크게 튈 수 있다는 판단이 들어간 거야.
다만 E4M3는 단독으로 모든 값을 안전하게 담지 않아. TE FP8 primer는 FP8 연산을 autocast 영역 안에서 처리하고, amax history와 scaling factor를 같이 관리한다고 설명해. 그 primer의 recipe 예시는 amax_history_len=16을 쓰고, FP8 Linear는 두 차원이 모두 16으로 나누어져야 한다고 적어. 그러니까 dtype 이름만 맞는다고 실제 커널 경로가 자동으로 좋아지는 건 아니야.
왜 중요한가
E4M3를 따로 보는 이유는 FP8 Tensor Core나 Blackwell 문서에서 “FP8”이라는 말이 너무 넓게 쓰이기 때문이야. FP8이라고만 쓰면 E4M3인지 E5M2인지, 텐서 자체가 FP8인지 스케일 값만 FP8인지, 런타임이 실제 FP8 커널을 타는지 알 수 없어.
예를 들어 NVFP4에서는 4비트 E2M1 값이 있고, 16개 연속 원소마다 FP8 E4M3 스케일이 하나 붙어. 여기에 텐서 전체 FP32 스케일이 더해져 x = x_e2m1 * s_block * s_global로 값을 복원해. 이때 E4M3는 모델 전체가 FP8이라는 뜻이 아니라, 4비트 값을 다시 풀어낼 때 쓰는 블록 스케일의 저장 형식이야.
DeepGEMM에서도 E4M3는 다른 모습으로 나와. README의 MQA scoring 예시는 q와 kv를 E4M3 텐서로 받고, kv에는 별도 scaling factor가 붙어. 또 DeepGEMM은 SM90과 SM100에서 scaling factor 형식이 다르며, FP8 casting이나 transpose 처리는 사용자가 앞선 커널에서 따로 처리해야 한다고 적어. 이건 CUDA 커널 레이어의 이야기라, 모델 카드에 “FP8”이 붙은 것과는 판단 기준이 달라.
E5M2·BF16·NVFP4와 비교
E4M3와 E5M2는 같은 FP8 계열이지만 선택 기준이 달라. E4M3는 값 간격을 조금 더 촘촘하게 잡고, E5M2는 넓은 범위를 잡아. 그래서 출력 활성값이나 weight처럼 분포가 비교적 관리되는 곳은 E4M3가 자주 나오고, gradient처럼 값이 크게 튈 수 있는 구간은 E5M2가 더 자연스러울 수 있어.
BF16은 더 넉넉한 기준선이야. 16비트를 쓰고 FP32와 같은 8비트 지수 폭을 남기기 때문에 값 범위가 훨씬 넓어. E4M3로 낮추기 전에 BF16 또는 FP16 기준선에서 같은 프롬프트 묶음, 같은 배치, 같은 KV 캐시 설정을 먼저 재야 해.
FP4와 NVFP4 문맥에서는 E4M3가 더 헷갈려져. NVFP4는 값 자체를 4비트 E2M1로 줄이고, 그 값을 복원할 때 16개 값마다 E4M3 스케일을 붙여. 그러니까 “E4M3가 들어갔다”는 말만 보고 전체 모델이 FP8 E4M3로 저장됐다고 읽으면 안 돼.
실무 적용 기준
실무에서는 E4M3를 켤지 말지보다, E4M3가 어느 위치에 들어갔는지를 먼저 확인하는 편이 좋아.
- 텐서 값: 활성값, weight, Q/K/V 텐서가 E4M3인지 확인해. 이 경우 최대값
±448안에 들어오도록 스케일이 잘 잡히는지가 중요해. - 스케일 값: NVFP4처럼 블록 스케일이 E4M3인지 확인해. 이 경우 실제 저장 값은 FP4이고, E4M3는 복원식을 도와주는 보조 값이야.
- 커널 입력: DeepGEMM이나 직접 CUDA 커널에서 E4M3 텐서를 받는지 확인해. casting, transpose, scaling factor layout을 누가 처리하는지도 같이 봐야 해.
- 평가표: BF16·FP16 기준선과 E4M3 결과를 p50·p95 지연시간, tokens/sec, 최대 VRAM, 정확도, 긴 문맥 품질로 나란히 비교해.
중단 신호도 단순해. NaN, Inf, 포화값 증가, p95 지연시간 악화, 품질 회귀, 랭킹 뒤집힘이 보이면 E4M3 적용 범위를 줄여야 해. 필요한 구간은 E5M2, BF16, FP16으로 되돌리는 게 맞아. 낮은 정밀도는 비용을 줄이려고 쓰는 거지, 품질 회귀를 못 본 척하려고 쓰는 장치가 아니야.