CUDA 18VOL · TIER 3 수치 · CONTENT-FIRST · A4 LANDSCAPE · 14p

Mixed Precision & 수치 안정성

FP32 · TF32 · BF16 · FP16 · FP8 · FP4 bit semantics · Accumulation · Error propagation
Volume V09 / 18
Tier T3 수치
선행 V01 (PMPP Core), V02 (GPU Arch)
용도 bit-level 포맷 이해 · mixed precision 훈련 설계

목차

§1 IEEE 754 기본p.2
§2 Reduced-precision (FP16/BF16/TF32)p.3
§3 FP8 variants (E4M3/E5M2)p.4
§4 FP4/FP6 variants (MX·NVFP4)p.5
§5 Block-scale formatsp.6
§6 Rounding modesp.7
§7 Accumulation · associativityp.8
§8 Error 전파 · Kahanp.9
§9 Softmax 수치 안정성p.10
§10 Mixed precision trainingp.11
§11 Loss scalingp.12
§12 FP8 training (TE)p.13
§13 Cheat Sheetp.14

범례

핵심 용어 (노란 배경)
표 헤더 / 매우 중요
정의·공식 박스
예시·워크드 박스
빨강주의·실수
시험·실무 핵심
(!)니모닉 (첫글자 암기)
인과·흐름
∵∴이유·결론
타 권 cross-ref
인쇄 A4 가로 / 여백 없음 / 배경 그래픽 포함
IEEE 754 · H100 WP · OCP MX spec · NVFP4 WP · Higham 수치해석

1 표현식 sign · exp · mantissa (-1)^S · 2^E · 1.M

x = (−1)S · 2(E − bias) · (1.M)2 S: 1 bit   E: exponent field   M: mantissa (fraction)   1.M: implicit leading 1 (normalized)
  • Normalized: E ∈ [1, 2e−2], leading 1 implicit
  • Subnormal: E = 0, leading 0, gap 균등 채움 underflow 완화
  • Zero: E = 0, M = 0 (±0 존재)
  • Inf/NaN: E = 2e−1

2 Bias exponent 정규화

bias unsigned exponent field signed exponent 변환: bias = 2e−1 − 1.
FP32: 127 · FP64: 1023 · FP16: 15 · BF16: 127
formatebiasE range
FP64111023[−1022, +1023]
FP328127[−126, +127]
FP16515[−14, +15]
BF168127[−126, +127]

3 Subnormal gradual underflow

subnormal: x = (−1)S · 21−bias · (0.M)2 leading 0 · smallest subnormal: 21−bias−m (m = mantissa bits)
  • FP32 min normal 2−126 ≈ 1.18e−38 · min subnormal 2−149 ≈ 1.40e−45
  • FTZ (flush-to-zero): GPU에서 subnormal을 0으로 — 성능↑ 정밀↓

4 Special values Inf · NaN E=all-1

SEM
+0000
−0100
+Inf0all-10
−Inf1all-10
sNaNall-1≠0, MSB=0
qNaNall-1≠0, MSB=1
  • NaN 전파: op(x, NaN) = NaN (quiet) 중독 (poison)
  • NaN ≠ NaN — IEEE 비교 규칙
  • ±0: 부호 있음, 비교는 같음 (+0 == −0)

5 FP32 bit layout ★

31 30        23 22                    0
 ┌─┬──────────┬───────────────────────┐
 │S│  E (8)   │      M (23)           │
 └─┴──────────┴───────────────────────┘
  sign  exp       mantissa (fraction)
  bias = 127
  normalized: x = (-1)^S · 2^(E-127) · 1.M

6 FP64 bit layout

63 62          52 51                    0
 ┌─┬─────────────┬───────────────────────┐
 │S│   E (11)    │       M (52)          │
 └─┴─────────────┴───────────────────────┘
  bias = 1023
  precision ≈ 15~17 decimal digit

εmach(FP64) = 2−52 ≈ 2.22e−16 · ↗ V09 §8 Error

7 Machine epsilon 정밀도 한계

εmach = 2−m m: mantissa bit 수 (implicit 1 제외)   1 + εmach ≠ 1 인 최소 ε
formatmεmach
FP64522−52 ≈ 2.22e−16
FP32232−23 ≈ 1.19e−7
FP16102−10 ≈ 9.77e−4
BF1672−7 ≈ 7.81e−3

8 FP32 · FP64 dynamic range

FP64FP32
max norm~1.80e+308~3.40e+38
min norm~2.23e−308~1.18e−38
min subnorm~4.94e−324~1.40e−45
precision15~17 dd6~9 dd

IEEE 754-2008 · dd = decimal digit

혼동: exponent field (bit 값) ≠ exponent E (실제 지수 = field − bias). bit 표현과 수학 표현 분리.
IEEE 4 category: N·S·Z·I (Normal · Subnormal · Zero · Inf/NaN)

1 FP16 layout 1/5/10 exp=5 narrow

15 14   10 9               0
 ┌─┬──────┬───────────────┐
 │S│E (5) │   M (10)      │
 └─┴──────┴───────────────┘
 bias=15  range ~[6e-8, 6.5e+4]
 ε_mach = 2^-10 ≈ 9.77e-4
  • IEEE 754-2008 binary16 표준
  • range 좁음 gradient underflow ∴ loss scaling 필요
  • precision 10 bit BF16보다 정밀

2 BF16 layout 1/8/7 FP32 exp 유지

15 14         7 6             0
 ┌─┬────────────┬─────────────┐
 │S│  E (8)     │   M (7)     │
 └─┴────────────┴─────────────┘
 bias=127  range ≈ FP32
 ε_mach = 2^-7 ≈ 7.81e-3
  • FP32 상위 16 bit 그대로 = FP32 ↔ BF16 변환 단순 truncate
  • range 넓음 loss scaling 불필요
  • precision 낮음 — 7 mantissa bit

3 TF32 layout 1/8/10 TC input only

18 17          10 9             0
 ┌─┬─────────────┬───────────────┐
 │S│   E (8)     │    M (10)     │
 └─┴─────────────┴───────────────┘
 19-bit internal · storage 32-bit
 bias=127  range = FP32
  • A100+ Tensor Core 전용 FP32 입력을 silently TF32로 변환
  • FP32 range + FP16 precision
  • accumulation은 FP32 (TF32로 누적 아님)
  • 주의: 비결정적 — reproducibility 필요시 off

4 3-format 비교 ★

FP16BF16TF32
S/E/M1/5/101/8/71/8/10
bias15127127
max norm65504~3.4e38~3.4e38
min norm6.1e−51.2e−381.2e−38
εmach9.8e−47.8e−39.8e−4
loss scale필요불필요불필요
storage16b16b32b

5 Range × Precision trade 정성 2D

precision (mantissa)
  ↑
10│ FP16  TF32        FP32
  │                    │
 7│      BF16
  │
 3│ FP8-E4M3
 2│ FP8-E5M2 FP6-E3M2
 1│ FP4-E2M1
  └─────────────────────→ range (exp)
    e=4  e=5  e=8(FP32·BF16·TF32)  e=11(FP64)

세로축 mantissa bit = precision · 가로축 exp bit = range · 정성 배치

6 Tensor Core 지원 매트릭스 A100/H100

dtypeA100 (3gen)H100 (4gen)
FP16312 TF989 TF
BF16312 TF989 TF
TF32156 TF495 TF
FP81979 TF
FP64 TC19.5 TF67 TF

NVIDIA A100/H100 whitepaper · sparsity 미포함 · TC=Tensor Core

FP16 vs BF16 선택: gradient underflow 걱정 크면 BF16. precision 민감 (작은 weight update) 하면 FP16 + loss scale.

1 FP8 두 variant ★ inf·grad

E4M3E5M2
S/E/M1/4/31/5/2
bias715
max44857344
min norm2−62−14
min subn2−92−16
εmach2−3=0.1252−2=0.25
Inf/NaNNaN only (S.1111.111)IEEE 표준
용도weight · activationgradient

OCP FP8 spec · H100 whitepaper · E4M3 NaN만 (Inf 없음, range↑)

2 FP8 E4M3 bit layout

 7 6     3 2   0
 ┌─┬─────┬─────┐
 │S│E (4)│M (3)│
 └─┴─────┴─────┘
 bias=7  max=448  NaN: S.1111.111
 Inf 없음 → max 표현 확장 (240 vs 224)

3 FP8 E5M2 bit layout

 7 6       2 1 0
 ┌─┬─────────┬───┐
 │S│ E (5)   │M 2│
 └─┴─────────┴───┘
 bias=15  max=57344  IEEE 표준 (Inf/NaN)
 → FP16과 exp 공유, mantissa만 다름

4 왜 2가지? range vs precision

원칙 forward activation은 precision 중요 E4M3. backward gradient는 dynamic range 중요 (극단값) E5M2.
  • weight: 분포 좁음 E4M3
  • activation (forward): 정규화 후 좁은 분포 E4M3
  • gradient: 극단값 (outlier) 많음 E5M2
  • optimizer state (moment): FP32 유지 (너무 민감)

5 Per-tensor scaling 공식 ★

s = amax(x) / FP8max
xq = round(clamp(x / s, −FP8max, FP8max))
x̂ = xq · s s: scale (scalar)   amax: element-wise max |x|
  • 1 scale per tensor — metadata 최소
  • outlier 1개가 전체 tensor 정밀도 파괴 가능

6 Scaling 세분도 비교

단위metadataoutlier 견딤
per-tensor1낮음
per-channelC
per-block G=32N/32높음
per-elementN(=FP32)

구체 알고리즘 선택은 ↗ V10 §1~§4

7 E4M3 값 분포 예시

E=0001 (2^-6)
  0.015625, 0.017578, 0.019531, ... 0.029296
E=0010 (2^-5)
  0.03125, 0.03515, 0.0390, ...
E=1111 (2^8, 특수)
  MSB ≠ 111: normal (up to 448)
  M = 111: NaN only

→ 지수 간 가격차 2배 · 지수 내 8 레벨 (3 mant)

8 Accumulator 선택 acc dtype

원칙 FP8 × FP8 matmul의 accumulator는 반드시 FP32.
N (reduction 차원) 수백~수천 원소를 FP8/FP16에 누적 곧 오버플로·정밀 붕괴.
C[m,n] = Σ_k A[m,k] · B[k,n]
  A,B : FP8
  product : FP16 중간
  acc     : FP32  ← 필수
  output  : BF16/FP16/FP8 dequant
흔한 실수: E4M3로 gradient 저장 amax ≈ 수만 규모에서 즉시 overflow. gradient는 E5M2 또는 BF16.
FP8 역할 분담: 3·2·f·g (E4M3 forward · E5M2 gradient)

1 왜 FP4/FP6? 동기

  • 모델 크기 HBM capacity·BW bottleneck
  • FP8 → FP4 2× 용량, 2× BW, 2× TC throughput
  • precision 격차는 block scaling으로 복구
  • Blackwell TC에 FP4/FP6 natively 지원 (5세대 TE)

2 FP4 variants ★ E2M1

E2M1E3M0
S/E/M1/2/11/3/0
bias13
levels1616
range±6±128
주 용도weight block-scale(거의 미사용)
E2M1:  0b SEEM
  values: 0, ±0.5, ±1, ±1.5, ±2, ±3, ±4, ±6
  → 16 lattice point (sign + magnitude)

3 FP4 E2M1 값 전체 표 16 레벨

bits|x|bits|x|
S0000S1001.0
S0010.5S1011.5
S0101.0*S1102.0
S0111.5*S1113.0

E∈{0,1,2,3}·M∈{0,1} · *subnorm/norm 경계 · MX spec

4 FP6 variants

E2M3E3M2
S/E/M1/2/31/3/2
bias13
max7.528
εmach2−32−2
특징precision↑range↑
  • FP8와 FP4 사이의 중간 bit-width
  • Blackwell TC MXFP6 지원
  • storage: 6 bit · 4 원소 = 24 bit (packing 비효율)

5 MX (OCP Microscaling) block-scale family

MX Open Compute Project 표준. block size G=32 고정, scale은 E8M0 (unsigned, 2의 거듭제곱 only).
nameelemscaleG
MXFP8FP8 E4M3 / E5M2UE8M032
MXFP6FP6 E2M3 / E3M2UE8M032
MXFP4FP4 E2M1UE8M032
MXINT8INT8UE8M032

OCP MX spec v1.0 · 2023

6 NVFP4 NVIDIA 확장 G=16

NVFP4 NVIDIA Blackwell 전용. block G=16, scale format FP8 E4M3.
MXFP4 대비 block 작음 + scale에 mantissa 3 bit 정밀도↑.
MXFP4NVFP4
elementFP4 E2M1FP4 E2M1
scaleUE8M0 (pow-2)FP8 E4M3
block G3216
scale/elem8/32 = 0.25b8/16 = 0.5b
표준OCP openNVIDIA only

NVFP4 whitepaper · 같은 FP4 element지만 quantization 오차 ↓

7 E8M0 scale format

  • 8 bit unsigned exponent only · mantissa 0 bit
  • 표현값: 2k, k ∈ [−127, +127] · NaN = 0xFF
  • scale 자체가 정확한 power-of-2 multiply = exponent add
  • HW 단순 · scale 곱셈이 bit shift 수준
주의: FP4는 16 levels뿐 block scaling 없이는 neural net 거의 쓸모없음. NVFP4/MXFP4 모두 block-scale 필수.

1 Block-scale 원리 ★

핵심 tensor를 길이 G block으로 분할. block마다 독립 scale sg.
block 내 원소는 shared scale로 dequantize.
x[i] = q[i] · s⌊i/G⌋ q[i]: low-precision element · sg: scale of block g · G: block size
  • per-tensor 대비 outlier 흡수
  • per-element (=FP32) 대비 메모리 효율
  • metadata overhead = sizeof(scale) / G

2 MXFP8 (G=32) layout ★ 32-pack

block (G=32 elements, MXFP8):
 ┌─────────────────────────────────────┐
 │ s₀ (E8M0, 1B) │ e₀ e₁ ... e₃₁ (32B) │
 └─────────────────────────────────────┘
   scale            32 FP8 elements
   → total 33 B per block
   → overhead 8b / 32 elem = 0.25 b/elem

tensor [N elements] =
 ┌────────┬────────┬────────┬─── ...
 │block 0 │block 1 │block 2 │
 │s₀│data │s₁│data │s₂│data │
 └────────┴────────┴────────┴─── ...
   각 block 독립 scale · 순차 배치

3 NVFP4 (G=16) layout ★

block (G=16 elements, NVFP4):
 ┌──────────────────────────────────────┐
 │ s₀ (FP8 E4M3, 1B) │ e₀..e₁₅ (packed) │
 └──────────────────────────────────────┘
   scale                16 FP4 = 8 B
   → total 9 B per block
   → overhead 8b / 16 elem = 0.5 b/elem

FP4 packing (2 elem / byte):
 byte: [ e₂ᵢ₊₁ | e₂ᵢ ]  ← nibble
         high     low
 16 elements = 8 bytes

scale precision:
 MXFP4 UE8M0: s ∈ {2^-127, ..., 2^127}  (pow-2 만)
 NVFP4 FP8:   s = (-1)^S · 2^(E-7) · 1.M (full FP8)

4 Microscaling matmul 수식

y = Σg sA,g·sB,g·Σk∈g Aq,k·Bq,k group 내부: low-precision dot · group 사이: scale 곱 후 FP32 acc
  • group 내부 dot 결과는 FP32로 확장 후 scale 곱
  • TC 명령이 group dot + scale을 단일 op로 fuse
  • acc는 FP32 (≥ N=수백에서 필수)

5 Format 효과 bit-rate 비교 ★

formatelem bscale beff b/elem
FP161616
BF161616
FP8 (per-tensor)8≈08
MXFP8 (G=32)80.258.25
MXFP4 (G=32)40.254.25
NVFP4 (G=16)40.54.5

6 Block axis 선택

  • weight: output channel 축 block — dequant이 matmul와 정렬
  • activation: token 축 (per-token group) — 분포 token별 상이
  • KV cache: head 또는 token (↗ V10 §8)
  • 축 선택 실패 matmul에서 scale broadcast 불일치
함정: MXFP4의 E8M0 scale은 pow-2 only. block 내 amax가 2k와 2k+1 사이일 때 최대 2× 낭비 (scale 올림 vs 내림).
Block-scale 3대 조합: MX8·MX4·NV4 (MXFP8 G=32 · MXFP4 G=32 · NVFP4 G=16)

1 왜 rounding? exact 불가능

이유 실수 연산 결과가 target format의 representable 값 사이에 낙하 두 이웃 중 하나로 rounding 필요.
  • rounding 선택은 error 분포를 결정
  • IEEE 754는 4개 기본 모드 정의
  • additional: stochastic, round-to-odd

2 IEEE 754 4 modes ★

mode약어규칙
Round Nearest EvenRN가장 가까운 값, tie는 짝수 mantissa
Round toward ZeroRZmagnitude 감소 (truncate)
Round toward −∞RDfloor (direction down)
Round toward +∞RUceil (direction up)
  • RN = IEEE 754 기본 (banker's rounding)
  • RZ = C cast behavior, GPU HW 일부

3 RN-even (banker's) tie-break

정의 중간값 (exact halfway) 최종 mantissa의 LSB가 0 (짝수) 되는 쪽으로 rounding.
decimal 예 (소수 1자리 → 정수):
  2.5 → 2  (even)
  3.5 → 4  (even)
  4.5 → 4  (even)
  5.5 → 6  (even)
→ 긴 합산에서 bias 0 (상·하 round 확률 동일)

4 Rounding error bound 공식

|fl(x) − x| ≤ εmach / 2 · |x| (RN)
|fl(x) − x| ≤ εmach · |x| (RZ/RD/RU) fl(x): rounded 결과   RN은 절반, 나머지는 전체
  • 상대 오차 bound = 1/2 ULP (unit in last place) for RN
  • ULP = 2E−m · 현재 x의 last bit 단위

5 Stochastic Rounding (SR) ★ 랜덤 tie

SR 두 이웃 중 하나를 확률적으로 선택. 확률은 실제 값과 이웃 간 거리 비율.
P(fl(x) = ⌈x⌉) = (x − ⌊x⌋) / ULP
P(fl(x) = ⌊x⌋) = (⌈x⌉ − x) / ULP E[fl(x)] = x · 무편향 (unbiased) · 긴 합산에서 drift 없음
  • unbiased 작은 gradient가 weight에 확률적으로 누적
  • low-bit training (FP16 master 없이) 핵심 기법
  • HW 지원: Hopper/Blackwell FP8 TC 옵션

6 RN vs SR 비교 작은 업데이트

상황RNSR
w += 0.01 (FP16)0으로 drop1/100 확률로 1 ULP 증가
기대값00.01
long-run driftbias 있음unbiased
determinismyesno (seed 없으면)

7 GPU rounding 기본값

  • CUDA FMA (fma.rn.f32): RN 기본
  • type cast __float2half: RN 기본, __float2half_rn/_rz/_rd/_ru variant
  • Tensor Core accumulator: 내부 RN
  • PTX: cvt.{rn|rz|rm|rp|rni|rzi|rmi|rpi} suffix

PTX ISA · cvt instruction · ↗ V03 §5

함정: RZ는 magnitude 감소 (negative → 0 방향, positive → 0 방향). RD (floor)와 다름. 부호 고려.
IEEE 4 modes: N·Z·D·U (Nearest · Zero · Down · Up)

1 FP 덧셈 non-associative ★

핵심 실수에서 (a+b)+c = a+(b+c). 그러나 floating-point에서는 일반적으로 성립 안 함.
fl((a ⊕ b) ⊕ c) ≠ fl(a ⊕ (b ⊕ c)) ⊕: floating-point add · fl: rounding
FP32로 1e20 + (−1e20) + 1 순서에 따라 0 또는 1.
좌결합: (1e20 − 1e20) + 1 = 0 + 1 = 1
우결합: 1e20 + (−1e20 + 1) = 1e20 + (−1e20) = 0

2 이유 정렬·shift 손실

  • 큰 수 + 작은 수: 작은 수의 mantissa가 shift되어 일부 bit 유실
  • 유실된 bit는 되돌아오지 않음
  • subsequent 연산 순서가 어떤 bit를 살리는지 결정
큰 수: 1.00 × 2^20
작은 수: 1.00 × 2^0
정렬:  1.00 × 2^20
     + 0.00...01 × 2^20  (20 bit shift)
     ─────────────────
     → mantissa 비트수 넘으면 소실

3 Reduction tree 순서 결과 변동

serial (left-to-right):
  (((a₀ + a₁) + a₂) + a₃)
  → O(N) step, O(log N) 오차 누적 낮음 if ordered

tree (pairwise):
   a₀ a₁ a₂ a₃
    \ /    \ /
     s₁     s₂
       \   /
        S
  → O(log N) step, 오차 O(√log N)

warp-shuffle:
  stride 16, 8, 4, 2, 1
  → HW에 결정된 순서, 일관성 yes

Higham "Accuracy and Stability" Ch4 · pairwise가 일반적으로 더 정확

4 결정론 문제 ★

non-deterministic atomicAdd, 다중 block reduce, 비결정적 schedule 실행할 때마다 합산 순서 바뀜 결과 bit-exact 다름.
  • atomicAdd: block 도착 순서는 run-by-run 다름 (warp scheduling)
  • cuBLAS: 일부 split-K 내부 atomic 사용 bit-varying
  • 해결책: deterministic 옵션 (cuDNN/cuBLAS), split-K 대신 Stream-K (↗ V05 §8)
  • 테스트 재현성·debugging에서 중요

5 Reduction 오차 경계

serial: |err| ≤ (N−1) · ε · |Σ|
pairwise: |err| ≤ log2N · ε · |Σ|
Kahan: |err| ≤ 2 · ε · |Σ| N: 원소 수 · ε: machine eps · 상수 계수 생략
  • serial O(N) 큰 N에서 위험
  • pairwise O(log N) GPU tree reduce 자연스러움
  • Kahan O(1) 4× FLOP 비용 (↗ §8)

6 Mixed-dtype 누적 원칙

opinputacc
GEMMFP16/BF16/FP8FP32
reductionFP16FP32
layer norm statBF16FP32
softmax denomFP16FP32

원칙: 누적 dtype ≥ 입력 dtype · 짧으면 catastrophic

함정: 테스트에서 "결과 동일"을 bit-exact로 기대 금지. tolerance (relative/absolute) 기반 비교 필수.

1 Relative error 모델 ★ x·(1+δ)

fl(x ⊙ y) = (x ⊙ y) · (1 + δ), |δ| ≤ εmach ⊙: FP 연산 (+ − × /) · δ: relative rounding error
  • 한 연산당 상대 오차 최대 ε
  • 연산 N개 연쇄: (1+δ)N ≈ 1 + Nε (first-order)
  • 일반적 bound: cond · N · ε (condition number 곱)

2 Condition number 입력 민감도

정의 cond(f, x) = |x · f'(x) / f(x)|. 입력 상대 변화 대비 출력 상대 변화.
  • well-conditioned: cond ~ 1
  • ill-conditioned: cond ≫ 1 (이 경우 어떤 알고리즘도 정확 불가)
  • 입력 오차 · cond = 출력 오차 하한

3 Forward vs backward error

종류의미
forward|ŷ − y| / |y|
backward|x̂ − x| / |x|, ŷ = f(x̂)
stabilitybackward error 작으면 "stable"

stable 알고리즘 + ill-conditioned 문제 = 여전히 부정확

4 Catastrophic cancellation ★ 비슷한 값 뺄셈

현상 비슷한 두 수의 뺄셈 선행 자릿수가 상쇄 유효 자릿수 대부분 소실.
FP32 표현: 1.0000002 − 1.0000001
= 2 × 10−7 (유효 1자리)
원래 수는 7자리 유효했는데 결과는 1자리 이하.

5 Cancellation 회피 패턴

문제대체 공식
√(1+x) − 1x / (√(1+x) + 1)
1 − cos(x)2·sin²(x/2)
log(1+x), x→0log1p(x)
exp(x)−1expm1(x)
  • libm에 전용 함수 제공 (log1p / expm1)
  • GPU: __log1pf, __expm1f

6 Kahan summation ★ compensated

s = 0; c = 0   // s: sum, c: lost bit carry
for x in xs:
  y = x - c          // undo prev loss
  t = s + y          // add, may lose LSB
  c = (t - s) - y    // recover lost bit
  s = t
return s
errorKahan ≤ 2ε + O(Nε²) vs serial O(Nε) · N과 무관한 상수 bound
  • 4× FLOP · extra register 1개
  • GPU 병렬 합산에서는 pairwise tree가 대개 충분
  • long-sequence accumulator (e.g. FP8 training)에서 유용

7 Neumaier 개선

  • Kahan의 변형 — |s| < |x|일 때 역할 교체
  • 더 안정적, 비용 동일
  • C++ std::reduce의 일부 impl 채용
함정: compiler의 -ffast-math/-O3가 Kahan의 (t − s) − y 를 "0"으로 최적화 회피. volatile 또는 fast-math off.

1 Naive softmax 문제 ★

softmax(x)i = exp(xi) / Σj exp(xj) xi = 89 이면 exp ≈ 4.5e38 → FP32 overflow · −89에서 exp ≈ 2.3e−39 → subnormal/underflow
  • FP16 exp 범위: x ∈ [−17, +11]
  • FP32 exp 범위: x ∈ [−87, +88]
  • Transformer logits는 수십~수백 도달 overflow 불가피

2 Stable softmax ★ subtract max

m = maxj(xj)
softmax(x)i = exp(xi − m) / Σj exp(xj − m) invariant: softmax(x) = softmax(x + c) for scalar c · choose c = −max → exp input ≤ 0
이유 xi − m ≤ 0 exp(·) ≤ 1 overflow 방지. 최소 하나의 원소에서 exp(0) = 1 분모 ≥ 1 underflow 방지.

3 3-pass → 2-pass → 1-pass

버전pass메모리
naive2logits + denom
stable 3-pass3+max
online (Milakov)1(m, l) state

online softmax: (m, l) pair를 streaming update · FlashAttention 핵심 · ↗ V07 §2~§3

4 Log-sum-exp (LSE)

LSE(x) = log(Σj exp(xj))
stable: LSE(x) = m + log(Σj exp(xj − m)) log softmax = xi − LSE(x) · cross-entropy loss에 직접 사용
  • cross-entropy: loss = −log py = LSE(x) − xy
  • softmax를 실제로 계산하지 않고도 loss 얻음 수치 안정
  • PyTorch F.cross_entropy 내부 LSE 사용

5 Online softmax 결합 공식 증명

block A: (mA, lA) where lA = Σ exp(x − mA)
block B: (mB, lB)
merge: m = max(mA, mB)
l = exp(mA−m)·lA + exp(mB−m)·lB correction factor exp(m_old − m_new) · FlashAttention 핵심 (↗ V07 §3)

6 Low-precision softmax

  • attention logits 저장: BF16 okay, FP16 위험 (범위)
  • exp 내부 누적: FP32 필수
  • P = softmax(S) 출력: FP16/BF16 okay (∈[0,1])
  • FP8 attention: P를 [0, 1]로 clamp 후 E4M3 (FA3 incoherent, ↗ V07 §10)
함정: "logit subtract max" 생략은 debug mode에서 동작해도 deployment에서 NaN. 반드시 production path에 포함.
Softmax 안정화: M·E·L (Max subtract · Exp nonneg · LSE for loss)

1 동기 왜 mixed?

  • TC throughput: FP16/BF16이 FP32 대비 8×+
  • HBM 용량/BW: 16 bit가 32 bit 대비 2×
  • 그러나 weight update · optimizer state는 정밀도 민감
  • forward/backward는 low, master weight·update는 FP32

2 Master weight 개념 ★ FP32 master

원리 optimizer는 FP32 master weight W 보유. forward 직전 FP16으로 cast하여 compute. backward gradient (FP16) → FP32 accumulate → master update.
master W (FP32) ──┐
                  ▼ cast
              W_fp16 ── forward ──► loss
                                    │
              ◄── backward ── grad_fp16
              │
              ▼ cast to FP32 + scale down
         Δ (FP32) ──► update master W

3 Micikevicius 2017 AMP 공식 ★

  1. Master W: FP32
  2. Forward: W → FP16, activation FP16
  3. Loss: FP32 (또는 FP16 + scale)
  4. Backward: gradient FP16
  5. Unscale gradient → FP32
  6. Optimizer step: FP32 master update

Micikevicius et al. "Mixed Precision Training" ICLR 2018

4 BF16 vs FP16 training

FP16BF16
range좁음= FP32
precision10 bit7 bit
loss scaling필수불필요
master WFP32 필요FP32 권장
divergence riskgrad underflowupdate precision
HW 지원V100+A100+

5 Optimizer state precision

  • Adam m, v: FP32 권장 (second moment가 작은 값 축적)
  • BF16 optimizer: 실험적 (일부 방식 수렴 저하)
  • 8-bit optimizer (bitsandbytes): block-wise quant

6 Dtype 할당 template ★

변수BF16 pathFP16 path
master WFP32FP32
W (compute)BF16FP16
activationBF16FP16
gradientBF16FP16 (scaled)
accumulatorFP32FP32
optimizer m/vFP32FP32
loss scaledynamic

7 AMP API 구성

  • PyTorch: torch.amp.autocast + GradScaler
  • JAX: bfloat16 dtype 직접 / jmp
  • Megatron/NeMo: FP32 master + FP16/BF16 compute 수동 관리
  • TE: FP8 mixed precision 전담 (↗ §12)
함정: layer norm / softmax / loss는 "autocast에서 FP32로 유지" — precision 민감 op list 암기. BatchNorm 통계도 FP32.
Mixed precision 3계층: M·C·S (Master FP32 · Compute low · Scale gradient)

1 Gradient underflow 문제 ★

문제 backward에서 gradient는 종종 < 2−14 (FP16 min normal).
→ 0으로 flush → weight update 전혀 일어나지 않음.
  • 특히 초반 layer의 gradient는 깊이만큼 축소
  • subnormal 허용해도 정밀도 낮음
  • BF16은 range가 FP32와 같아 이 문제 없음

2 Loss scaling 원리 scale up · unscale down

L̃ = L · s (forward loss scale up)
∇̃ = ∇L · s (chain rule로 gradient도 s배)
∇ = ∇̃ / s (optimizer 전에 unscale) s: scalar (일반적 2k) · FP16 범위 내로 gradient 이동 → underflow 회피
  • loss에 단일 상수 곱 = gradient 모두에 동일 배율
  • optimizer step 직전 동일 배율로 나누면 원래 update

3 Static vs Dynamic

staticdynamic
shyperparam fixedruntime adapt
튜닝수동 (2k)자동
overflow주기적 점검자동 대응
장점예측 가능로버스트
단점튜닝 필요몇 step loss

4 Dynamic loss scaling 알고리즘 ★

init: s = 2^15
for step:
  scaled_loss = loss * s
  scaled_loss.backward()
  # gradient = grad * s
  if any(isinf(g) or isnan(g)):   # overflow
    s = s / 2                      # shrink
    skip optimizer step
    reset counter
  else:
    unscale grad: g = g / s
    optimizer.step()
    counter += 1
    if counter >= N:              # stable window
      s = s * 2                   # try larger
      counter = 0

PyTorch GradScaler 기본 동작 · N=2000 step default

5 Inf/NaN 탐지

  • NaN 전파: op(NaN, ·) = NaN · 한 번 발생하면 전체 tensor 감염
  • torch.isinf(g).any() / torch.isnan(g).any()
  • GPU: __isnanf, __isinff intrinsic
  • batch-level 집계 (AllReduce bool)가 분산 훈련 필수

6 분산 환경 scaling sync

각 rank가 독립 scale 사용 시 weight divergence
→ scale은 global synchronize
→ overflow rank 있으면 모든 rank skip

protocol:
  1. each rank: check Inf/NaN local
  2. allreduce OR bool
  3. if any rank overflow: shrink s, skip
  4. else: proceed optimizer

7 Gradient clipping 관계

  • clipping은 unscale 이후 수행
  • clip 전 norm 계산도 FP32
  • overflow detect → clip 무의미 (이미 Inf)
함정: BF16에 loss scaling 적용 시 overhead만 증가, 이득 없음. BF16은 range 충분 scaling off.

1 FP8 training 차이점 ★

  • scale이 tensor마다 필요 (range 극단적으로 좁음)
  • forward/backward/gradient 각각 다른 variant
  • scale 결정이 수렴에 직접 영향
  • master weight는 여전히 FP32 (optimizer precision 유지)

2 Transformer Engine 개요

TE NVIDIA 라이브러리. FP8 tensor + scale 관리 + kernel fusion. Hopper/Blackwell TC FP8 instruction과 통합.
  • te.Linear, te.TransformerLayer drop-in
  • 내부: amax history + delayed scaling 자동
  • attention forward/backward FP8

3 Per-tensor amax history ★ window

amax history 최근 N step 동안의 amax(x)를 큐에 저장.
새 scale = max(history) · 다음 step에서 사용.
history[N] (ring buffer):
  step t    : amax_t
  step t-1  : amax_{t-1}
  ...
  step t-N+1: amax_{t-N+1}

amax_used = max(history)
s = amax_used / FP8_max

4 Delayed scaling ★ 1-step 지연

delayed 현재 step의 amax를 다음 step scale에 사용.
이유: 현재 step scale을 즉시 적용하면 amax 계산 후 rescale 필요 추가 pass.
step t:
  x_t 계산
  amax_t 계산 (현재 tensor)
  quant(x_t) with s_{t-1}   ← 직전 step scale
  push amax_t to history

step t+1:
  s_t = max(history) / FP8_max
  quant with s_t

cost: scale이 1 step lag · 수렴에는 무해 (history size N ≥ 16)

5 Dtype transition 규칙

opinputoutput
forward linearFP8 E4M3BF16
activationBF16BF16
backward wgradFP8 E5M2BF16
backward dgradFP8 E5M2BF16
master updateFP32FP32

6 Forward/Backward FP8 variant 배치

forward:
  W (E4M3) × X (E4M3) → Y (FP32 acc → BF16)

backward (grad output gY):
  dgrad: gY (E5M2) × W^T (E4M3) → gX
  wgrad: X^T (E4M3) × gY (E5M2) → gW

이유:
  W, X는 정규화된 좁은 분포 → E4M3
  gY는 outlier 가능 (loss gradient) → E5M2

7 Scale factor safety margin

  • amax 그대로 사용: outlier에 정확히 맞춤 노이즈 1개에 0이 되는 risk
  • safety margin: s = amax · m / FP8max, m > 1
  • TE default: m ≈ 1.0 (amax history가 smoothing 역할)

8 Block-scale FP8 training Blackwell

  • Blackwell TC: MXFP8 block=32 native
  • per-tensor amax 불필요 (block마다 local amax)
  • outlier 자동 흡수 TE 구조 단순화
  • 구체 알고리즘·양자화 선택은 ↗ V10 §11
함정: FP8 training 중 scale을 매 step runtime refresh하면 비결정. TE는 history·delayed로 결정론 유지.

1 전체 포맷 bit layout 표 ★

formatSEMbiasmax
FP641115210231.8e308
FP3218231273.4e38
TF3218101273.4e38
BF161871273.4e38
FP1615101565504
FP8 E4M31437448
FP8 E5M21521557344
FP6 E3M2132328
FP6 E2M312317.5
FP4 E2M112116
FP4 E3M01303128

IEEE 754 · OCP FP8/MX · NVFP4 whitepaper

2 Dtype × use-case 결정 표 ★

대상권장 dtype
master weightFP32
optimizer m/vFP32
forward activationBF16 (or FP16)
forward weight (TC)BF16 / FP8 E4M3
gradientBF16 / FP8 E5M2
matmul accumulatorFP32 항상
reductionFP32
layer norm statFP32
softmax denomFP32
attention P outBF16 (or FP8 [0,1] clamp)
KV cacheFP8 / INT8 (↗ V10)
lossFP32

3 수치 안정성 체크리스트

  1. softmax: subtract max 포함 여부
  2. log: log1p / logsumexp 사용
  3. sqrt·rsqrt ε 가드 (∇sqrt(0) = Inf)
  4. NaN 감지 hook (dev mode)
  5. accumulator dtype ≥ input dtype
  6. reduction tree deterministic 여부

4 Training recipe 요약

전략mastercomputescale
FP32 baselineFP32FP32
FP16 AMPFP32FP16dynamic loss scale
BF16FP32BF16없음
FP8 (TE)FP32FP8per-tensor delayed
MXFP8 (Blackwell)FP32FP8per-block G=32
NVFP4FP32FP4per-block G=16

5 흔한 함정 10선

  1. FP16 accumulator 사용 수백 원소에서 붕괴
  2. softmax subtract max 생략
  3. BF16에 loss scaling 적용
  4. Kahan의 compensated term이 -O3로 제거
  5. RZ와 RD 혼동 (부호에서 차이)
  6. gradient E4M3 사용 (range 부족)
  7. weight E5M2 사용 (precision 부족)
  8. 비결정 reduction 으로 bit-exact 테스트
  9. subnormal FTZ on 상태에서 underflow 무시
  10. scale을 매 step runtime 갱신 비결정
Dtype 선택 5-rule: M·C·A·G·S (Master=32 · Compute=low · Acc=32 · Grad range↑ · Stat=32)
원칙: "precision은 low, range와 accumulator는 high". 모든 설계가 이 원칙의 응용.