Quick recap
The key takeaways of every lesson on one page. Read it in ten minutes to refresh the whole track; open a lesson when a point feels unclear.
01 GPU architecture
- A GPU trades fast single threads for throughput: an H100 has 132 SMs with 128 fp32 lanes each, and needs many independent pieces of work.
- A kernel runs over a grid of thread blocks; each block runs on one SM; the SM schedules warps of 32 threads that execute one instruction together (SIMT). Divergent branches in a warp run one after the other.
- Blocks are independent and are not all resident at once; the blocks that run together form a wave, and a launch just above a full wave pays for a mostly idle extra wave (the tail effect).
- An SM hides the latency of HBM loads (hundreds of cycles) by switching between resident warps at no cost. Little's law: data in flight = bandwidth × latency, about 1.3 MB (10 KB per SM) on an H100.
- Occupancy = resident warps / 64; it is limited by registers (65,536 per SM), shared memory (228 KB), threads (2,048) and blocks (32). It is a means, not a goal.
- Memory hierarchy of an H100: registers and shared memory/L1 (256 KB each per SM), L2 (50 MB, ≈ 5.5 TB/s), HBM (80 GB, 3.35 TB/s). Weights and activations live in HBM, so kernels read and write HBM.
- A tensor core computes on small low-precision tiles with fp32 accumulation; an H100 does 989 TFLOP/s dense bf16 on tensor cores and 67 TFLOP/s fp32 on CUDA cores, about 15× less.
02 Roofline and arithmetic intensity
- Arithmetic intensity = FLOPs / bytes moved between HBM and the chip; ridge point (H100 bf16 ≈ 295, fp8 ≈ 591, A100 bf16 ≈ 153 FLOP/byte).
- Roofline bound: ; a kernel with is memory-bound and reaches at most FLOP/s.
- Elementwise ops and norms have below 5: memory-bound on every GPU, so they speed up by the bandwidth ratio (H100/A100 ≈ 1.6×), not the FLOP/s ratio.
- A matmul has : about for small , at most .
- It is compute-bound for , about for large (345 tokens for on an H100); fp8 leaves about the same.
- counts the tokens that share one weight read: micro-batch × sequence length in training and prefill, the number of sequences in decode.
- Decode attention has (MHA) or (GQA) at any batch size, because every sequence reads its own KV cache.
- The four-step estimate: count FLOPs, count bytes, divide by and BW, take the larger time.
03 Kernels, tiling and fusion
- A CUDA kernel runs a grid of independent blocks; threads of one block share shared memory and synchronize with
__syncthreads(), which every thread of the block must reach. Triton programs one tile per program instance, with a mask at the boundary. - Global memory is read in 32-byte sectors. A warp load is coalesced when consecutive threads read consecutive addresses; a column read of a row-major fp32 matrix uses only 12.5% of the fetched bytes.
- Shared memory has 32 banks of 4 bytes; word is in bank . different words in one bank cost passes; padding
tile[32][32]totile[32][33]removes the column conflict. - Each kernel costs about , with a launch cost of a few µs in eager PyTorch.
- Fusing a chain of unary elementwise ops cuts the traffic from to elements and the launches from to 1. Large tensors gain the ratio of bytes, tiny tensors the ratio of launches.
- A tiled matmul reads elements instead of ; the bf16 intensity per step is .
- The tile size is limited by shared memory: (227 KB per block on an H100 gives in bf16). Real GEMMs reach the peak through L2 reuse across blocks and register tiling.
04 FlashAttention and online softmax
- The online softmax keeps a running max , sum and output per query; when the max grows, it multiplies and by , and at the end is the exact softmax average.
- The rescale is exact because the factor is the same for every old term; every exponent is , so nothing overflows.
- Two partial results over disjoint key sets merge as and : a weighted, not a plain, average.
- FlashAttention keeps a tile on chip, streams tiles, and never writes or to HBM; it writes only and one lse per row.
- HBM traffic per head: standard attention ; FlashAttention , with the query tile height.
- The backward pass recomputes instead of storing it: 25% more matmul FLOPs, far fewer bytes, faster, because attention is memory-bound.
- FlashAttention-2 reduces non-matmul FLOPs, parallelises over query tiles and splits query rows across warps; split-KV (flash-decoding) splits the KV cache into chunks and merges the partials, so decoding uses all SMs.
05 Mixed-precision training
- Exponent bits give range, mantissa bits give precision: bf16 (1/8/7) has the range of fp32 and ; fp16 (1/5/10) has but a largest value of 65504 and underflows below about .
- Stagnation theorem: if , then . A sum of equal terms stops after about terms (256 in bf16, 2048 in fp16).
- Long sums are fixed by fp32 accumulation (tensor cores: 16-bit inputs, fp32 adds), pairwise summation or Kahan summation.
- fp32 master weights are needed because an update below about is lost in a -bit format; the optimizer step runs in fp32.
- Softmax, norms, losses and large reductions run in fp32; elementwise ops stay in 16 bits.
- Loss scaling multiplies the loss by , so every gradient is multiplied by ; unscale before clipping and the update. Dynamic scaling skips the step and halves on inf, and doubles after 2000 clean steps.
- bf16 needs no loss scaling (fp32 range); FP8 needs a scale factor per tensor or block, with E4M3 for weights and activations and E5M2 for gradients.
06 Training memory and checkpointing
- Training memory = model states (depend on the model) + activations (depend on the tokens) + logits + buffers. Keep 10–20% of the GPU free.
- Mixed-precision Adam keeps 16 bytes per parameter: bf16 weights 2, bf16 gradients 2, fp32 master weights 4, Adam 4, Adam 4. So a 7B model needs 112 GB of model states.
- A GPT-style layer has parameters, so for large .
- Every operation keeps what its backward pass needs. One transformer layer keeps bytes; the attention core grows with .
- FlashAttention and selective recomputation remove the core ( left) at almost no cost. Full checkpointing keeps per layer for about 33% more FLOPs.
- Memory peaks when the backward pass starts. Checkpointing every layers gives a peak of about , smallest at ; for transformers is 1 to 3.
- The fp32 logits take bytes. Data parallelism and ZeRO do not reduce activations.
07 Collectives and the α-β model
- α-β model: a message of bytes takes ; is the latency per message, is one over the bandwidth.
- All-reduce = reduce-scatter + all-gather. All-to-all is a block transpose: rank receives block of every rank.
- Ring all-reduce: . Each rank sends about bytes for any ; only the latency term grows with .
- No all-reduce can make its busiest rank send fewer than bytes, so the ring is bandwidth-optimal.
- Recursive doubling: . It wins below the crossover size (latency regime); the ring wins above it (bandwidth regime).
- Pairwise all-to-all: ; on a real network it is limited by bisection bandwidth and by the largest block.
- busbw = algbw × for all-reduce (× for reduce-scatter, all-gather and all-to-all); compare busbw, not algbw, with the link speed.
- Hierarchical all-reduce: reduce-scatter on NVLink, all-reduce of across nodes on all network cards in parallel, all-gather on NVLink.
08 Data parallelism, ZeRO and FSDP
- Data parallelism: each GPU computes the gradient of its own micro-batch; the all-reduce averages them. With equal micro-batches and a mean loss this equals one-GPU training on the whole batch, and the copies stay identical.
- Plain data parallelism keeps bytes of model states on every GPU.
- ZeRO-1, -2 and -3 shard the optimizer states, then the gradients, then the weights: , , bytes per GPU.
- ZeRO-1 and ZeRO-2 send elements per GPU per step, like DDP (reduce-scatter, update, all-gather). ZeRO-3 sends (two all-gathers and one reduce-scatter), 1.5 times DDP.
- ZeRO and FSDP shard model states only, never activations.
- DDP overlaps a bucketed all-reduce with the backward pass; the last bucket (the first layers) is always exposed.
- FSDP gathers one unit at a time before forward and backward, frees it after use, and reduce-scatters the gradients. HSDP shards inside a node and replicates across nodes.
- The all-reduce hides when the tokens per GPU per step satisfy (twice that for fp32 gradients). The model size cancels.
09 Tensor and pipeline parallelism
- Megatron TP: split the first matrix of a block by columns and the second by rows; then each block needs one all-reduce in the forward pass () and one in the backward pass (): 2 + 2 per transformer layer.
- An elementwise function (GeLU) can sit between a column split and a row split; splitting the first matrix by rows would need an extra all-reduce before it.
- TP communication over compute per layer is : independent of the tokens , worse with , better with ; about 0.6 on NVLink and 5.6 on InfiniBand for , so TP stays inside a node.
- Pipeline bubble of GPipe and 1F1B: of the step time ( of the ideal time); interleaving with chunks gives at times the messages.
- GPipe keeps micro-batches per stage; 1F1B keeps at most on stage : it saves memory, not time.
- : at a fixed global batch, more data parallelism means fewer micro-batches and a larger bubble; aim for .
- Layout rules: TP inside the NVLink domain, PP across nodes with just large enough to fit, DP outermost; the Llama 3 order is [TP, CP, PP, DP].
10 Sequence, context, expert parallel
- Only attention mixes tokens; norms, dropout, residual adds, projections, MLPs and MoE routing are token-wise and can be split along the sequence for free.
- Megatron sequence parallelism shards the norm and dropout regions along inside the TP group; each all-reduce becomes a reduce-scatter plus an all-gather with the same bytes, and the activation memory per layer becomes .
- Ring attention keeps the queries on each rank and sends the K/V blocks around a ring of ranks; partial results merge exactly with the logsumexp formula, in any order.
- Ring attention hides the K/V transfer when the block size is (multi-head attention, bf16); GQA divides the bound by , a balanced causal mask multiplies it by 2.
- With a causal mask, contiguous blocks give about 50% efficiency; the zig-zag layout (rank holds chunks and ) gives every rank the same work in every round.
- DeepSpeed-Ulysses uses two all-to-alls (sequence → heads → sequence) and sends about bytes per GPU and layer, but its degree is limited by the number of (K/V) heads and its communication is not overlapped.
- An MoE layer with top- routing uses of experts per token: FLOPs follow the active parameters, memory follows all parameters.
- Expert parallelism sends bytes per GPU per MoE layer (dispatch plus combine, uniform routing); the busiest GPU sets the time, so capacity factors and load-balancing losses keep the load even.
11 Quantization
- Uniform affine quantization: , . Symmetric: , . Asymmetric: , .
- Inside the range the error is at most ; if the error is uniform (data spread over many steps), the mean squared error is . Outside the range the clipping error has no bound.
- Clipping trade-off: a smaller range gives a smaller but clips more values; the MSE has a minimum (about for Gaussian data at 4 bits).
- When values share a scale, the largest one sets : one outlier makes the step coarse for all the others.
- An integer matmul can use scales on the outer dimensions (per token, per output channel); scales on the reduction dimension (per input channel, group-wise) must be applied inside the sum. int4 with fp16 scales per group of 128 costs 4.125 bits per weight.
- SmoothQuant: exactly; moves range from activation outliers into the weights, at no run-time cost.
- PTQ uses a calibration set (RTN, GPTQ, AWQ); QAT trains through fake quantization with the straight-through estimator (gradient 1 inside the range, 0 outside).
- W4A16 removes weight bytes: it speeds up memory-bound decode (up to 4×), not compute-bound prefill. W8A8/FP8 halves the bytes and doubles the FLOP/s: up to 2× in both regimes.
12 LLM inference serving
- KV cache per token: bytes (128 KiB for Llama-3-8B in bf16); the batch that fits is .
- A decode step reads bytes and does about FLOPs (bf16). Its intensity is a byte-weighted average of (shared weights) and (private caches), so decode is memory-bound in practice.
- Prefill is compute-bound (intensity about ); decode is memory-bound. TTFT measures the first, TPOT the second; a larger batch raises throughput and TPOT together.
- Continuous batching re-decides the batch before every step: finished sequences leave, waiting ones join, and no slot idles while requests wait.
- PagedAttention stores the KV cache in fixed-size blocks mapped by a block table: waste below one block per sequence, sharing by reference counts, copy-on-write, and preemption of the newest request (swap or recompute).
- Speculative sampling accepts a draft token with probability and resamples from on rejection; every token then has exactly the target distribution.
- With acceptance rate and draft length , one target pass gives tokens on average; the speed-up is that divided by .
- Long prompts make TPOT spike; chunked prefill hides prompt chunks in the idle compute of decode steps, and disaggregation moves prefill to other GPUs at the cost of a KV transfer.
13 Profiling, MFU and compilation
- Training FLOPs per token of a dense decoder: (PaLM convention, = attention width); full recomputation makes the hardware run .
- with the dense peak ; HFU also counts recomputation. MFU is the comparable number because it does not reward repeated work.
- Training time ; GPU-hours time, nearly independent of at a fixed MFU.
- A step splits into compute, exposed communication and idle time; a timeline shows which part is large.
- Launch-bound criterion: the GPU is busy at most of the time; a host-device sync (
.item(),.cpu(),print(tensor)) empties the queue. - Overhead-bound work is fixed by fewer launches (CUDA graphs, fusion, larger batch), memory-bound work by fewer bytes (fusion), compute-bound work only by faster arithmetic or fewer FLOPs.
torch.compile: TorchDynamo captures graphs with guards (graph breaks at untraceable code, recompiles when a guard fails), AOTAutograd builds the backward, TorchInductor fuses ops into generated Triton (GPU) or C++ (CPU) kernels.- Method: estimate, measure steady-state steps, profile, fix the largest gap first, measure again.