← Back to Table of Contents

Chapter 30 — How Datatypes Drive Your Daily Optimization Choices

This is the chapter the rest of the guide was building toward. You now know what a transistor is (Chapter 1), how memory is a hierarchy of speed-vs-capacity tradeoffs (Chapter 9), why bandwidth — not FLOPs — usually bounds you (Chapter 11), what FP8/INT4/NVFP4 actually are (Chapter 23), how a format reshapes the silicon and which generation supports which type (Chapter 24), how much quantization (Chapter 25) and sparsity (Chapter 26) really buy, and how KV-cache, batching, and activations spend your memory budget (Chapter 29).

Here we tie all of it into a single decision framework: when you sit down on Monday morning to make a model fit, run faster, or cost less, which precision and which technique do you reach for — and why? The thesis is simple and, once you see it, hard to unsee: every optimization you can perform is buying back exactly one of three scarce hardware resources — memory capacity, memory bandwidth, or compute throughput — and you pay for it in the only currency the model has, accuracy. Name the resource you are short of, and the right tool is nearly always obvious.

The one-sentence version: Pick the optimization that buys back the resource you are actually short of (capacity, bandwidth, or compute), spend the least accuracy to get it, and never pick a datatype your GPU can’t accelerate.


The Unifying Mental Model: Three Resources and One Currency

Strip away the jargon and a chip offers a model exactly three finite things, plus one thing the model itself owns:

The Four Quantities Every Optimization Touches
Memory capacity (GB)
Can the weights + KV-cache + activations even fit? The "won't fit on one GPU" problem. Measured in GB of HBM.
Memory bandwidth (TB/s)
How fast can bytes stream from HBM? Sets decode token rate. The "too slow at batch=1" problem (Ch 11).
Compute throughput (FLOP/s)
How fast can the tensor cores multiply? Sets training step time and prefill latency. The "compute-bound" problem.
Accuracy (the currency)
What you spend to buy the above. Every lossy technique trades some model quality for capacity, bandwidth, or compute. The skill is spending the least.

Now map every technique in this guide to the resource it buys and the price it charges. This single table is the chapter — everything else is elaboration and worked examples.

Technique Buys back How much Accuracy risk Hardware requirement
BF16 instead of FP32 compute + bandwidth + capacity ~2× all three ~none (training-stable range) any modern tensor core (Ampere+)
FP8 (E4M3/E5M2) compute + bandwidth ~2× over BF16 low–moderate; needs scaling Hopper / Blackwell (Ch 24)
INT8 weight+activation (W8A8) bandwidth + capacity (+ compute) ~2× low for weights, moderate for activations (outliers) INT8 tensor cores (Turing+)
INT4 / NVFP4 weight-only (W4A16) capacity + bandwidth ~4× memory; ~up to 4× decode moderate; needs calibration (GPTQ/AWQ) fast INT4/FP4 path or dequant (Ch 25)
KV-cache quant (INT8/FP8) capacity (KV) + bandwidth 2–4× smaller KV low–moderate (activation outliers) any; targets long context (Ch 29)
2:4 structured sparsity compute + capacity ~2× matmul; ~2× weight storage needs sparse-aware retraining Sparse Tensor Cores (Ampere+) (Ch 26)
GQA / MQA capacity (KV) + bandwidth $n_{heads}/n_{kv}$× smaller KV small if trained in none (architectural)
Distillation / smaller model all three proportional to size cut task-dependent none
Tensor / pipeline / FSDP parallelism capacity (per-GPU) ÷ number of GPUs none (exact) multi-GPU + interconnect (Ch 28)
Gradient checkpointing capacity (activations, training) $O(L) \to O(\sqrt{L})$ none (exact) ~+33% compute
Operator fusion (FlashAttention, torch.compile) bandwidth removes HBM round-trips none (exact) none

The two columns that matter most are “buys back” and “accuracy risk.” Optimizations in the bottom group (parallelism, checkpointing, fusion, GQA) are exact — they cost zero accuracy and you should reach for them first. The lossy ones (lower precision, quantization, sparsity, distillation) are where you spend the accuracy currency, and they should be applied in proportion to how short you actually are.


Are You Compute-Bound or Memory-Bound? Start at the Roofline

Before choosing a technique, classify your workload. The roofline (Chapter 11) splits the world in two, and the split dictates which resource a technique even helps with:

The Roofline Decides Which Techniques Matter
Memory-bound (AI < ridge ≈ 295)
  • LLM decode at small batch, elementwise ops, GEMV
  • Bottleneck = bytes streamed from HBM
  • Win by moving fewer bytes: quantize weights/KV, fuse, batch
  • Extra dequant FLOPs are free (compute is idle)
Compute-bound (AI > ridge ≈ 295)
  • Training, prefill, large-batch GEMMs
  • Bottleneck = tensor-core throughput
  • Win by doing cheaper math: FP8/INT8 matmul, 2:4 sparsity
  • Saving bytes alone barely helps (bandwidth isn't the limit)

This is why the same word “quantization” means different things in the two regimes. Memory-bound: INT4 weight-only gives ~4× speedup purely by reading 4× fewer bytes — the matmul stays in FP16 after dequant, and that’s fine because the multipliers were idle. Compute-bound: you need a format the tensor cores execute natively (FP8, INT8, 2:4) so the math itself gets cheaper; merely storing weights smaller does nothing for a compute-bound GEMM.


The Practitioner Decision Tree

Here is the flow you walk top to bottom. Each branch ends in a concrete precision/technique recommendation.

What Should I Do Monday Morning?
START: Does the model + KV-cache + activations FIT in HBM? (run the Ch 29 budget)
NO → capacity problem. In order of cheapness: GQA & KV-quant (inference) / checkpointing (training) → weight quant INT8→INT4 → tensor/pipeline/FSDP shard across GPUs (Ch 28)
YES → Is it TRAINING or INFERENCE?
Branch A — Training
TRAINING → default to BF16 compute + FP32 master weights (range & stability)
On Hopper/Blackwell & compute-bound? → enable FP8 for the matmuls (≈2× over BF16), keep FP32 master weights & loss scaling
Activations don't fit? → gradient checkpointing → then CPU/NVMe offload → then shard (Ch 28)
Branch B — Inference
INFERENCE → Prefill (compute-bound) or Decode (memory-bound)? Usually both — optimize each.
DECODE, low latency / single user (memory-bound): weight-only INT4/NVFP4 (≈4× fewer bytes) + INT8/FP8 KV-cache + GQA. Smallest model that meets quality.
THROUGHPUT serving (many users): batch hard (continuous batching, PagedAttention) until compute-bound, then W8A8 INT8 or FP8 so the now-saturated math is cheap.
Have Sparse Tensor Cores + retraining budget + still compute-bound? → add 2:4 sparsity for ~2× on top.

When to Pick Each Format — the One-Liner Each

Format Pick it when… Why
FP32 numerical reference / tiny models / debugging full range + precision; ~no hardware ML acceleration
BF16 training default same 8-bit exponent range as FP32 (no loss-scaling drama), half the bytes, native on every modern tensor core
FP16 legacy training / older GPUs half bytes, but 5-bit exponent → narrow range → needs loss scaling; superseded by BF16 for training
FP8 (E4M3/E5M2) Hopper+ and compute-bound (training matmuls, prefill) ~2× compute & bandwidth over BF16; needs per-tensor scaling
INT8 (W8A8) mature inference, throughput serving, edge ~2× everything, widest hardware support; activations need care
INT4 / NVFP4 memory-bound decode, local/single-GPU, weight-only ~4× memory & bandwidth; accept calibration (GPTQ/AWQ) and some quality work
2:4 sparsity have Sparse Tensor Cores + a retraining budget, compute-bound ~2× matmul + ~2× storage; structure must be retrained in

Why Each Default Exists — the Reasoning You Should Internalize

The defaults the field has converged on are not arbitrary; each encodes one of the three-resource tradeoffs. Understanding why lets you break the default when your situation differs.

Why training defaults to BF16 + FP32 master weights

Training needs dynamic range, not precision. Gradients span many orders of magnitude; weight updates can be tiny relative to weights. BF16 keeps FP32’s full 8-bit exponent (range ≈ $10^{\pm38}$) while halving storage and doubling tensor-core throughput — so it almost never underflows/overflows and needs no loss-scaling babysitting (unlike FP16, whose 5-bit exponent has range only ≈ $10^{\pm4.8}$). But BF16’s 7-bit mantissa is too coarse for accumulating millions of small updates, so the optimizer keeps an FP32 master copy of the weights (and FP32 optimizer moments): compute in BF16 for speed, accumulate in FP32 for correctness. This is mixed precision, and it is the training default precisely because it spends almost no accuracy to buy ~2× compute and memory.

Why inference loves weight-only INT4 for local/memory-bound use

Local LLM inference is batch=1 decode → memory-bound (Chapter 29). The token rate is HBM_BW / model_bytes, so the single most effective lever is fewer weight bytes. INT4 weight-only (W4A16) cuts weight bytes 4× → up to ~4× decode throughput and makes a 70B model fit where BF16 (140 GB) couldn’t. Activations stay in FP16, so accuracy loss is contained to the weights (which quantize well with GPTQ/AWQ calibration). You don’t need fast INT4 math — you’re memory-bound, the dequant FLOPs are free.

Why activations are harder to quantize than weights

Weights are a fixed, well-behaved distribution you can calibrate offline. Activations are dynamic and have outliers — a few channels in LLMs carry values 10–100× the median, and quantizing the whole tensor to that range crushes the rest into a handful of levels. This is why weight-only quantization (W4A16, W8A16) is easy and popular, while activation quantization (W8A8, and especially below 8 bits) needs tricks: per-channel/per-token scaling, outlier handling (SmoothQuant-style migration of scale from activations to weights), or simply keeping activations at higher precision. It is also why the KV-cache (which is activations) quantizes to INT8/FP8 but rarely cleanly to INT4. (Chapter 25 covers the mechanisms.)

Why KV-cache quantization specifically targets long context

The KV-cache is negligible at short context and dominates at long context (≈98% of weight size at 128k tokens; multiples of the weights at high batch — Chapter 29). So KV quantization is the right lever exactly and only when context/batch are large enough that the cache, not the weights, is your capacity-and-bandwidth problem. At 2k context it’s not worth the accuracy risk; at 128k it’s often the difference between fitting and not.

Why FP8 needs scaling

FP8 has very few bits (E4M3 = 4 exponent, 3 mantissa). Its representable range is narrow, so tensors must be scaled into that range per-tensor (or per-block, as in MXFP/microscaling — Chapter 23) before casting, and unscaled after. Without scaling, values overflow to inf or underflow to zero and training diverges. Hopper’s Transformer Engine automates this with running amax statistics. The lesson: FP8 is a ~2× compute win if the framework manages scaling; it is not a drop-in cast.

Why you must not pick a format your GPU can’t accelerate

A datatype is only fast if the silicon has a datapath for it (Chapter 24). FP8 on a pre-Hopper GPU is emulated — slower than BF16, not faster. INT4 math needs an INT4 path; on hardware without one, INT4 is a storage format that you dequantize to FP16 to compute (still great for memory-bound decode, useless for compute-bound). 2:4 sparsity needs Sparse Tensor Cores (Ampere+); without them the structured zeros buy storage but no compute. Always check the support matrix before choosing a format — the wrong choice can be a slowdown.

Format × Hardware: Is There a Native Datapath?
Ampere (A100, 2020)
FP32, TF32, BF16, FP16, INT8, INT4, 2:4 sparse. No FP8.
Hopper (H100, 2022)
Adds FP8 (E4M3/E5M2) + Transformer Engine. BF16/FP16/INT8/2:4 as before.
Blackwell (B200, 2024)
Adds FP4 / NVFP4 microscaling + FP6; 2nd-gen FP8. Native low-precision throughput leaps.

Honest Tradeoff Table: Speedup vs Accuracy Risk

Numbers below are typical on supported hardware for transformer LLMs; your mileage varies with model and task. “Speedup” is the regime where the technique actually helps.

Technique Resource bought Typical speedup / saving Accuracy risk Hardware needed
FP32 → BF16 compute, bw, capacity ~2× compute, 2× memory negligible Ampere+
BF16 → FP8 (training/prefill) compute, bw ~1.6–2× compute low w/ scaling; watch loss curves Hopper+
FP16/BF16 → INT8 W8A8 (decode/serving) bw, capacity, compute ~1.5–2× low (good calibration); activation outliers the risk Turing+
INT8 → INT4 weight-only (decode) capacity, bw up to ~2× more (4× vs FP16) moderate; GPTQ/AWQ recover most dequant path or FP4
KV-cache FP16 → INT8 capacity (KV), bw 2× KV; enables larger batch/context low–moderate (long-context quality) any
Dense → 2:4 sparse compute, capacity ~2× matmul (compute-bound only) needs sparse retraining; ~recoverable Sparse Tensor Cores
Full model → distilled smaller all three proportional (e.g. 70B→13B ≈ 5×) task-dependent, can be large none
Single GPU → FSDP/TP shard per-GPU capacity fits N× bigger (adds comm cost) none (exact) NVLink/IB, N GPUs

Read the accuracy-risk column as the price tag. “Negligible/none” techniques (BF16, fusion, checkpointing, sharding, GQA) are nearly free — apply them by default. The lossy ones go on a budget: spend INT8 freely, INT4/FP8 with validation, 2:4 only when you have the retraining budget and the Sparse Tensor Cores to cash it in.


Worked Scenarios: Reasoning End to End

Each scenario walks the decision tree and cites the chapter behind each step. These are the templates you adapt Monday morning.

(a) Serve a 70B model on 1×80 GB GPU, low latency (single user)

  • Fit check (Ch 29): BF16 weights = 140 GB > 80 GB. Won’t fit. Capacity problem first.
  • Regime (Ch 11): single user → batch=1 decode → memory-bound.
  • Choice: INT4 weight-only → 35 GB weights, fits with room for KV-cache. Decode ceiling jumps from infeasible to 3.35 TB/s ÷ 35 GB ≈ 96 tok/s (Ch 29). Add INT8 KV-cache + GQA so context room is generous. Activations stay FP16; accept GPTQ/AWQ calibration work (Ch 25).
  • Why not FP8/INT8? They’d need 70 GB (INT8) — fits but leaves little KV room and only ~48 tok/s. INT4 is the latency and capacity win here because we’re memory-bound, so the extra dequant is free.

(b) Max throughput batch serving (many users, throughput per GPU-dollar)

  • Regime: batch hard → AI ≈ batch → push past the ridge (~295) → compute-bound (Ch 11).
  • Choice: continuous batching + PagedAttention (Ch 29) to raise batch until HBM (KV-cache) fills; then W8A8 INT8 (or FP8 on Hopper+) so the now-saturated matmuls are cheap. KV-cache quant + GQA to fit more concurrent sequences (batch is throughput here).
  • Why not INT4 weight-only? Once compute-bound, weight bytes aren’t the bottleneck; you need cheaper math (INT8/FP8 native datapath), not just smaller storage.

(c) On-device 7B on a phone NPU

  • Constraints: tiny memory (a few GB), strict power budget, NPU often INT8/INT4-native, no FP8 (Ch 17, Ch 24).
  • Choice: INT4 weight-only (3.5 GB fits; matches mobile memory and the energy advantage of fewer-bit switching, $E \propto CV^2$ from Ch 1), INT8 activations where the NPU accelerates them. Possibly distill to a smaller model. Verify the NPU’s actual supported formats — pick what its datapath accelerates, not what’s theoretically smallest.

(d) Train a model that won’t fit

  • Fit check (Ch 29): weights + FP32 master + optimizer moments + activations (which dominate at long sequence) exceed HBM.
  • Order of operations (cheapest accuracy-free lever first): gradient checkpointing (~+33% compute, $O(\sqrt{L})$ activation memory) → FP8 matmuls if Hopper+ and compute-bound (2× compute, keep FP32 master) → FSDP/ZeRO sharding of params/grads/optimizer across GPUs (Ch 28) → CPU/NVMe offload as the last resort (capacity at steep bandwidth cost). Keep BF16 + FP32 master throughout for stability.

Python: A Tiny Optimization Advisor

Give it the model size, your GPU’s two numbers (capacity + bandwidth), and the regime; it names the binding constraint and suggests a precision/technique. It encodes the decision tree above. No dependencies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from dataclasses import dataclass

@dataclass
class GPU:
    name: str
    hbm_gb: float        # capacity
    hbm_bw_tbs: float    # bandwidth (TB/s)
    has_fp8: bool        # Hopper+
    has_fp4: bool        # Blackwell+
    has_sparse: bool     # Sparse Tensor Cores (Ampere+)

H100 = GPU("H100", 80, 3.35, has_fp8=True,  has_fp4=False, has_sparse=True)
A100 = GPU("A100", 80, 2.04, has_fp8=False, has_fp4=False, has_sparse=True)
B200 = GPU("B200", 192, 8.0, has_fp8=True,  has_fp4=True,  has_sparse=True)

RIDGE = lambda g, peak_flops_bf16=989e12: peak_flops_bf16 / (g.hbm_bw_tbs * 1e12)

def advise(n_params: float, gpu: GPU, regime: str,
           batch: int = 1, kv_gb: float = 0.0):
    """
    regime ∈ {"train", "decode", "prefill", "serve"}
    Prints the binding constraint and a precision/technique recommendation.
    """
    print(f"\n{'='*60}\n{n_params/1e9:.0f}B params on {gpu.name} | regime={regime} | batch={batch}")

    # 1) Capacity check at a few precisions
    for label, bpw in [("BF16", 2.0), ("INT8", 1.0), ("INT4", 0.5)]:
        need = n_params * bpw / 1e9 + kv_gb
        ok = "fits" if need <= gpu.hbm_gb else "OOM"
        print(f"   weights {label:>4}: {need:6.1f} GB / {gpu.hbm_gb:.0f} GB  -> {ok}")

    fits_bf16 = n_params * 2.0 / 1e9 + kv_gb <= gpu.hbm_gb
    fits_int8 = n_params * 1.0 / 1e9 + kv_gb <= gpu.hbm_gb

    # 2) Regime-specific advice
    if regime == "train":
        print("   CONSTRAINT: compute + activation capacity")
        rec = ["BF16 compute + FP32 master weights (default)"]
        if gpu.has_fp8: rec.append("FP8 matmuls (2x compute) w/ scaling")
        rec.append("gradient checkpointing if activations OOM, then FSDP/ZeRO shard (Ch 28)")
        _print_rec(rec)

    elif regime in ("decode", "serve") and batch <= 8:
        ceiling = lambda bpw: gpu.hbm_bw_tbs * 1e12 / (n_params * bpw + kv_gb * 1e9)
        print(f"   CONSTRAINT: memory BANDWIDTH (AI≈{batch} << ridge≈{RIDGE(gpu):.0f})")
        print(f"   decode ceiling: BF16 {ceiling(2.0):.0f}  INT8 {ceiling(1.0):.0f}  INT4 {ceiling(0.5):.0f} tok/s")
        rec = []
        if not fits_bf16: rec.append("MUST quantize to fit: " + ("INT8" if fits_int8 else "INT4"))
        rec.append("weight-only INT4/NVFP4 for ~4x fewer bytes (memory-bound: dequant is free)")
        rec.append("INT8/FP8 KV-cache + GQA for long context")
        _print_rec(rec)

    elif regime == "serve":  # large batch
        ridge = RIDGE(gpu)
        bound = "COMPUTE" if batch > ridge else "still bandwidth"
        print(f"   CONSTRAINT: {bound} (AI≈{batch} vs ridge≈{ridge:.0f})")
        rec = ["continuous batching + PagedAttention to raise batch (Ch 29)"]
        if batch > ridge:
            rec.append("W8A8 INT8" + (" or FP8" if gpu.has_fp8 else "") + " so saturated matmuls are cheap")
            if gpu.has_sparse: rec.append("2:4 sparsity for ~2x more (needs retraining)")
        _print_rec(rec)

    elif regime == "prefill":
        print(f"   CONSTRAINT: COMPUTE (big GEMM, AI > ridge≈{RIDGE(gpu):.0f})")
        rec = ["FlashAttention", "FP8/INT8 matmul" if gpu.has_fp8 else "BF16 matmul",
               "this governs time-to-first-token"]
        _print_rec(rec)

def _print_rec(items):
    print("   RECOMMEND:")
    for x in items:
        print(f"     - {x}")

# --- Run the worked scenarios ---
advise(70e9, H100, "decode", batch=1, kv_gb=4.0)   # (a) 70B low-latency
advise(70e9, H100, "serve",  batch=512, kv_gb=20)  # (b) max throughput
advise(7e9,  A100, "decode", batch=1)              # (c)-ish edge/no-FP8 -> INT4
advise(70e9, H100, "train",  batch=8)              # (d) training that won't fit

Sample output (abridged):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
============================================================
70B params on H100 | regime=decode | batch=1
   weights BF16:  144.0 GB / 80 GB  -> OOM
   weights INT8:   74.0 GB / 80 GB  -> fits
   weights INT4:   39.0 GB / 80 GB  -> fits
   CONSTRAINT: memory BANDWIDTH (AI≈1 << ridge≈295)
   decode ceiling: BF16 23  INT8 45  INT4 86 tok/s
   RECOMMEND:
     - MUST quantize to fit: INT8
     - weight-only INT4/NVFP4 for ~4x fewer bytes (memory-bound: dequant is free)
     - INT8/FP8 KV-cache + GQA for long context
============================================================
70B params on H100 | regime=serve | batch=512
   CONSTRAINT: COMPUTE (AI≈512 vs ridge≈295)
   RECOMMEND:
     - continuous batching + PagedAttention to raise batch (Ch 29)
     - W8A8 INT8 or FP8 so saturated matmuls are cheap
     - 2:4 sparsity for ~2x more (needs retraining)

The advisor is deliberately small, but notice it does exactly what an experienced practitioner does: check capacity at several precisions, locate the workload on the roofline, name the binding resource, and recommend the technique that buys that resource — never a technique that helps a resource you aren’t short of.


Why This Matters for Model Optimization

The Monday-Morning Checklist
1. Name the scarce resource
Capacity (won't fit), bandwidth (slow decode), or compute (slow training/prefill)? Run the Ch 29 budget and the Ch 11 roofline. Everything follows from this.
2. Apply the free levers first
BF16, fusion, GQA, checkpointing, paging, sharding cost ~zero accuracy. Exhaust them before spending any quality.
3. Spend accuracy in proportion
INT8 freely; INT4/FP8 with validation; 2:4 only with a retraining budget. Buy back exactly the resource you're short of.
4. Match format to silicon
Check the Ch 24 support matrix. FP8 needs Hopper+, FP4 needs Blackwell, 2:4 needs Sparse Tensor Cores. The wrong format is a slowdown.
5. Memory-bound ≠ compute-bound
Decode wants fewer bytes (weight/KV quant); training/prefill/serving-at-scale want cheaper math (FP8/INT8/2:4). Same word, different tool.
6. Measure, don't assume
The framework here predicts order-of-magnitude. Always confirm with a profiler and a quality eval — the accuracy price is task-specific.

The whole guide collapses to one habit: identify which of the three resources binds you, then spend the least accuracy to buy it back, using a format your hardware actually accelerates. Quantization, sparsity, batching, parallelism, checkpointing — they are not a grab-bag of tricks but a set of well-defined purchases against a fixed hardware budget. When you can say “I’m bandwidth-bound at batch=1, so I’ll go INT4 weight-only because the dequant is free and my GPU has the path,” you are doing exactly what the silicon was begging you to do all along.


Key Takeaways

  • Every optimization buys back one of three resources — memory capacity, memory bandwidth, or compute throughput — and you pay in accuracy. Name the scarce resource and the technique follows.
  • Classify first with the roofline. Memory-bound (decode) wants fewer bytes (weight/KV quant, fusion, batching); compute-bound (training, prefill, large-batch serving) wants cheaper math (FP8/INT8/2:4). The same technique helps in only one regime.
  • The free levers cost ~zero accuracy — BF16, GQA, operator fusion, gradient checkpointing, PagedAttention, sharding. Exhaust them before spending any model quality.
  • The defaults encode the tradeoffs: BF16 + FP32 master for training (range + stable accumulation); weight-only INT4 for memory-bound local decode (fewer bytes = faster + fits); KV-quant for long context; FP8 needs scaling; activations are harder than weights because of outliers.
  • Never pick a format your GPU can’t accelerate. FP8 = Hopper+, FP4/NVFP4 = Blackwell, 2:4 = Sparse Tensor Cores (Ch 24). The wrong format is emulation — a slowdown, not a speedup.
  • Walk the worked scenarios: 70B single-GPU low-latency → INT4 weight-only + INT8 KV + GQA; max-throughput serving → batch hard then W8A8/FP8; on-device → INT4 matched to the NPU’s datapath; training that won’t fit → checkpointing → FP8 → shard → offload.
  • This is the chapter you return to: identify the binding constraint, apply free levers, then spend accuracy in proportion, matched to your hardware — and verify with a profiler and an eval.

Next: Chapter 31 — Chip Design Flow, where we leave the practitioner’s seat and follow how the silicon you’ve been optimizing for is actually designed — spec to RTL to synthesis to place-and-route to tapeout.

← Back to Table of Contents