TL;DR: FP8 halves the K/V payload, but “2.7% error per element” is not a format guarantee: E4M3 can round a small nonzero input to zero, giving 100% relative error. Separate normal rounding, underflow and clipping, then validate the actual attention backend across the served context lengths and a predeclared quality margin.
How to approach it
Ask which FP8 variant, scale granularity and attention backend are in use. Establish whether only the cache is compressed or QK computation also uses FP8. Hold weights fixed when comparing cache precision, and ask for the maximum promised context rather than the median. Scale calibration is evidence to inspect, not a certificate of task accuracy.
A strong answer
For finite E4M3 values in the format described by Micikevicius et al., FP8 Formats for Deep Learning, arXiv v1, three fraction bits give eight intervals per normal binade. The maximum finite magnitude is 448, the smallest normal is , and the smallest positive subnormal is . Do not silently substitute a different FP8 encoding such as FNUZ.
With a positive dequantization scale , store and reconstruct . The boundaries move with the scale:
| Region of the original magnitude | What can fail | What to record |
|---|---|---|
| Normal, inside finite range | Rounding moves a value between adjacent floats | Error by layer, head and magnitude |
| Below | Subnormal spacing gives growing relative error | Subnormal and rounded-to-zero fractions |
| Above | Saturating conversion clips outliers | Clipped fraction and clipped magnitude |
For round-to-nearest in the normal range, the usual unit-roundoff bound is . It is an upper bound, not a typical error and not valid through underflow or clipping. At a midpoint of 1.0625, ties-to-even chooses 1.0, producing error. A tensor's relative L2 error of 2.7% would describe that tensor and quantizer, not every element.
This exhaustive scalar teaching quantizer uses Python 3's standard library. It enumerates finite E4M3 magnitudes, rounds ties to an even encoding and saturates finite overflow. It intentionally rejects NaN and infinity; it is not a GPU cast implementation or a model-accuracy experiment.
from math import copysign, isfinite
LEVELS = [((code & 7) * 2**-9 if code < 8 else
(1 + (code & 7) / 8) * 2**((code >> 3) - 7))
for code in range(127)]
def quantize(x, scale=1.0):
if not isfinite(x) or not isfinite(scale) or scale <= 0:
raise ValueError("finite input and positive finite scale required")
target = abs(x) / scale
if target >= LEVELS[-1]:
return copysign(LEVELS[-1] * scale, x)
code = min(range(len(LEVELS)),
key=lambda i: (abs(LEVELS[i] - target), i & 1))
return copysign(LEVELS[code] * scale, x)
for x in (1.0625, 2**-11, 600.0):
y = quantize(x)
print(f"{x:g} -> {y:g}; relative error {abs(y-x)/abs(x):.6%}")
normal midpoint: 1.0625 -> 1.0; abs error 0.0625 / 1.0625 = 5.882353%
underflow: 2^-11 -> 0; abs error 2^-11 / 2^-11 = 100%
clipping: 600 -> 448; abs error 152 / 600 = 25.333333%
sanity: raising scale to 2 avoids clipping at 600, but reconstruction is 576;
range protection still leaves (600 - 576) / 600 = 4% rounding error
A scale based on calibration amax can handle that calibration set's largest magnitude. It does not bound future outliers, preserve every small channel, or establish an acceptable task delta. Finer scales can help when a tensor spans too much range, but add metadata and require a supported kernel.
The vLLM v0.31.0 quantized-KV documentation, checked October 17, 2026, describes per-tensor and per-token-head strategies and backend restrictions. It also notes that the FlashAttention 3 FP8-cache path performs attention in FP8. Record the selected backend and scale source in the evaluation manifest; testing only an FP8-storage/BF16-compute emulator would miss that change.
A key perturbation changes a score by . Correlated errors across channels can matter more than elementwise averages. Value error enters the weighted sum; it can still be severe when attention concentrates on a corrupted value. More context introduces more competing positions, but there is no universal monotonic error curve or guaranteed square-root-log law for real attention noise.
Evaluate the same prompts with BF16 and FP8 caches, keeping weights, template and scoring fixed. Use held-out short, medium and maximum-length cases, varied answer positions, plus multi-token tasks scored by execution or exact match. Inspect per-layer clipping, late-position logit drift and failed examples. If weights are also quantized, run the full weight-precision by cache-precision matrix to separate the two changes. Greedy decoding reduces sampling variation but does not guarantee identical floating-point execution across batch shapes.
For an illustrative 80-layer GQA model with 8 KV heads and head dimension 128:
BF16 K/V payload/token = 2 x 80 x 8 x 128 x 2 B = 327,680 B = 320 KiB
FP8 K/V payload/token = 2 x 80 x 8 x 128 x 1 B = 163,840 B = 160 KiB
BF16 K + FP8 V = 80 x 8 x 128 x (2+1) B = 245,760 B = 240 KiB
These exclude scales, page rounding and allocator metadata. Mixed K/V precision is a possible fallback only if the backend supports it. Ship the tested configuration when its uncertainty bounds meet the quality contract; otherwise retain BF16 or test finer scaling and repeat the evaluation.
What interviewers probe next
"There is no clipping. Is it safe?" Underflow, rounding and changed attention arithmetic remain; compare task outcomes and late-position distributions.
"Why not E5M2?" Its wider range comes with two fraction bits and coarser normal spacing; it is a different trade-off to validate, not an accuracy upgrade.
"Will half the bytes halve latency?" Only the relevant payload halves; weight reads, scale traffic, conversion and kernel efficiency determine total decode time.
How it's scored
Weak: treats a tensor-average error as a per-element guarantee or approves FP8 from short-context perplexity.
Hire: distinguishes rounding, underflow and clipping, checks the backend, and compares served tasks by context length.
Strong Hire: isolates weight/cache effects, records scale failures by layer and head, and uses a measured quality margin before accepting memory savings.
Common mistakes
- Treating calibrated per-tensor scaling as sufficient for every model and workload.
- Applying the normal rounding bound to subnormals or clipped values.
- Claiming that key error always grows monotonically with context length.
- Promising a mixed-precision fallback that the selected backend cannot execute.