Sequence, context and expert parallelism
Before this lesson: the online-softmax merge (lesson 4), activation memory (lesson 6), reduce-scatter, all-gather and all-to-all (lesson 7), tensor parallelism (lesson 9). Attention with heads (deep learning 9); mixture of experts is defined again here (more in deep learning 15). Time: about 80 minutes, plus the notebook.
Why this matters #
Activation memory grows with the sequence length . Take one Llama-2-7B-like layer (), micro-batch , FlashAttention, and tokens. The layer stores about GB of activations (lesson 6). 32 layers need 584 GB. Tensor parallelism with sequence parallelism over 8 GPUs still leaves 73 GB per GPU, almost all of an 80 GB H100. Long context needs one more axis of parallelism: split the sequence itself. The same problem appears in science: a global 0.25° weather grid has million points, so even patches give about 65,000 tokens per field and time step.
Mixture-of-experts models have the opposite problem: many parameters, few FLOPs per token. Mixtral 8x7B has about 47B parameters but uses about 13B per token. DeepSeek-V3 has 671B parameters and activates 37B per token. The weights do not fit on one GPU, so the experts are spread over many GPUs, and every MoE layer moves every token to its experts and back.
1. Predict first #
2. The picture #
Only attention mixes tokens #
Look at one transformer layer and ask, for each operation: does the output for token need any other token?
| Operation | Needs other tokens? |
|---|---|
| LayerNorm / RMSNorm, dropout, residual add | no: each token alone |
| Q, K, V and output projections, MLP | no: the same matrix for each token |
| MoE router and experts | no: each token chooses its experts alone |
| attention | yes: query needs all visible keys |
Simplest case: 2 GPUs, 4 tokens. GPU 0 holds tokens 0–1 and GPU 1 holds tokens 2–3. All the token-wise operations run with no communication. For attention there are three ways out, and they are the three methods of this lesson:
- Megatron sequence parallelism (SP). Keep tensor parallelism (TP) for attention and the MLP (lesson 9). Shard along the sequence only the regions that TP leaves replicated (a full copy on every GPU).
- Ring attention / context parallelism (CP). Shard everything along the sequence. Each GPU keeps its queries, and the key/value (K/V) blocks visit every GPU in turn.
- DeepSpeed-Ulysses. Shard along the sequence, but just before attention switch to sharding by heads: each GPU gets all tokens for a subset of heads.
| Method | What is sharded | What moves | Collective |
|---|---|---|---|
| Megatron SP | norm/dropout regions by tokens; attention and MLP by heads/columns (TP) | activations between regions | reduce-scatter + all-gather (inside the TP group) |
| Ring attention (CP) | everything by tokens | K and V blocks | point-to-point sends around a ring |
| Ulysses | everything by tokens, attention by heads | Q, K, V and the output | two all-to-alls |
Ring attention: queries stay, keys and values travel #
Cut the sequence into blocks of tokens; rank holds block of , and . Attention for the queries of rank needs every K/V block. Instead of collecting them, the ranks form a ring. In each round, every rank computes attention of its queries against the K/V block it holds now, and at the same time sends that block to the next rank and receives a new one from the previous rank. After rounds every query has seen every key. The partial results are merged with the logsumexp formula of lesson 4, so the result is exact.
With a causal mask, query sees only keys . Then the order of the tokens on the ranks matters a lot, as the figure shows.
Press Next round to rotate the K/V blocks. The grid is the score matrix: rows are queries, columns are keys, and each rank owns the rows of its tokens. Blue cells are computed in this round, faint blue cells were computed before, and grey cells are masked. The bars show the work of each rank in this round; violet is idle time, because all ranks wait for the slowest one. Switch to zig-zag and watch the idle time disappear.
Ring attention with , a causal mask and the contiguous layout (rank holds block ). Which rank sets the time of rounds 1, 2 and 3, and how much of the total time are the ranks busy on average for long sequences?
Rank needs only K/V blocks . Rank 0 computes half a block (the diagonal) and then waits; rank computes in every round. The ring takes block-times for an average load of blocks, so the ranks are busy about . Seeing every block once is not the same as computing on every block: masked blocks cost nothing but still take a round.
3. Definitions and main results #
Megatron sequence parallelism #
With TP alone, the activation memory per layer is (Korthikanti et al. 2022, Eq. 2)
The term is not divided by . It comes from the replicated regions, which every GPU of the TP group stores in full:
| Stored tensor | Bytes |
|---|---|
| inputs of the two LayerNorms | |
| LayerNorm outputs = inputs of the QKV matmul and of the first MLP matmul | |
| the two dropout masks (1 byte per element) | |
| total |
These regions are token-wise, so SP shards them along : GPU keeps only tokens . Two operators convert between the regions (Korthikanti et al., Fig. 5–6):
- : all-gather along in the forward pass, before the column-parallel matmul (which needs all tokens); reduce-scatter in the backward pass;
- : reduce-scatter along in the forward pass, after the row-parallel matmul; all-gather in the backward pass.
Switch between TP and TP + SP. The strip is one transformer layer; each box shows which part of the activation GPU 0 stores. Blue: split by heads or columns (TP). Violet: a full copy on every GPU (wasted memory). Magenta: split by tokens (SP). The aqua markers are the collectives. Notice that SP turns every violet box magenta and every all-reduce into a reduce-scatter (RS) and an all-gather (AG), and the bytes readout does not change.
Claim: SP costs no extra bandwidth.
- TP needs one all-reduce after each row-parallel matmul: two per layer in the forward pass.
- A ring all-reduce of bytes over GPUs is a reduce-scatter followed by an all-gather (lesson 7). Each half sends bytes per GPU.
- SP does the reduce-scatter half right after the matmul. GPU now holds the summed output for its tokens only.
- Dropout, the residual add and LayerNorm run on these tokens. They are token-wise, so the result equals the replicated result restricted to these tokens.
- The all-gather half runs just before the next column-parallel matmul.
- So per layer and pass, SP runs 2 reduce-scatters and 2 all-gathers instead of 2 all-reduces: the same bytes.
Memory. Now every activation is divided by (Korthikanti et al., Eq. 4):
One detail makes this exact: SP stores only the local shard of each LayerNorm output and repeats the all-gather in the backward pass, overlapped with the gradient computation. With FlashAttention the term is not stored (lesson 4), and the memory is about .
Limits. SP lives inside the TP group, so it scales only as far as TP: usually one NVLink node of 8 GPUs. And every GPU still runs attention over all tokens.
TP degree , one layer, forward pass. With plain TP each GPU sends bytes. How many bytes does each GPU send with TP + SP?
An all-reduce is a reduce-scatter followed by an all-gather. SP runs the same two halves, only at different places in the layer (the token-wise ops run in between). Four half-collectives send exactly what two full all-reduces send. The memory goes down; the bytes stay the same.
Ring attention #
Each of the ranks holds a block of queries and the matching K/V block. In round :
- rank computes attention of its queries against the K/V block of rank ;
- it merges this partial result into its running result;
- at the same time it sends the K/V block to rank and receives the next one from rank (no send in the last round).
After shifts every query has seen every key.
Why the merge is exact. For one query, let and be the output and the logsumexp over a key set (scores ). For a disjoint key set :
(lesson 4 proves it). The result is the exact softmax over , and the merge is associative and commutative. So the ring may visit the blocks in any order.
Theorem (minimum block size). For multi-head attention in bf16, ring attention hides the K/V transfer behind the attention compute when
Proof.
- In one round, a rank computes for queries and keys over all heads: FLOPs (each of heads does , and ). Then : another . Total FLOPs, time .
- In the same round it sends one K block and one V block: elements of 2 bytes, so bytes, time .
- Sending and computing run at the same time. The transfer is hidden if .
- Divide both sides by : .
The bound does not depend on or on the number of ranks. Three refinements matter in practice:
- GQA. K and V have only columns, so the bytes shrink to while the FLOPs stay : .
- Causal mask. With a balanced layout (below), each round does only half a block of work, FLOPs, so .
- Backward pass. dK and dV travel with K and V (about twice the bytes), and the attention backward does about 2.5 times the forward FLOPs (five matmuls instead of two), so the condition is about the same. For other formats, multiply the bound by .
Memory per rank: the Ring Attention paper counts six blocks per host (the query block, the current K and V blocks, the K and V blocks being received, and the output). This is linear in and does not depend on .
Move the block size and switch the link. The blue line is the compute time per round, ; the aqua line is the K/V transfer time, . Left of the crossing the transfer is exposed; right of it, it is hidden. Change : both times change, but does not move. GQA and NVLink move to the left; the causal mask moves it to the right.
Ring attention, causal mask, zig-zag layout, GQA with , InfiniBand at GB/s, and you achieve TFLOP/s on attention. What is the smallest block size that hides the K/V transfer?
. GQA divides the bytes by : . The causal mask halves the work per round, so the bound doubles: tokens per rank. Forgetting the causal factor gives ; forgetting GQA gives .
Causal load balancing #
With a causal mask and contiguous blocks, rank needs only K/V blocks . Count work in units of one full block, where a diagonal block costs . Rank 0 does block; rank does blocks. All ranks move in lockstep, so the ring takes block-times, while the average load is : about 50% efficiency.
Zig-zag layout. Cut the sequence into chunks of tokens. Rank gets chunk (early) and chunk (late).
Proposition. With the zig-zag layout, every rank does the same work in every round, so the ring takes block-times: the optimum.
Proof. Measure work in chunk pairs. Rank holds query chunks and . In some round it holds the K/V chunks and of rank . Check the four chunk pairs:
- queries , keys : fully visible if , fully masked if ;
- queries , keys : always masked, because ;
- queries , keys : always visible, because ;
- queries , keys : visible if , masked if .
Exactly one of pairs 1 and 4 is visible, and pair 3 is visible. So every rank does 2 chunk pairs ( block) in every round with . In round 0 () the rank does the two diagonal chunk pairs and pair 3: chunk pairs as well. All ranks are equal in all rounds, so no rank waits.
Llama 3 uses exactly this split: "the i-th CP rank received both the i-th and the (2×CP−1−i)-th chunks" (Llama 3 paper, §3.3.2).
DeepSpeed-Ulysses #
Activations are sharded along . Before attention, one all-to-all on Q, K and V switches to head sharding: rank receives all tokens for heads. Attention then runs locally with any kernel (FlashAttention, causal or sparse masks), because each head needs nothing from the other heads. A second all-to-all on the output switches back to sequence sharding.
An all-to-all is a block transpose (lesson 7): think of the tensor as an grid of blocks (token blocks × head groups). Before, rank holds row of the grid; after, it holds column . Each rank keeps 1 block and sends blocks.
Press All-to-all to switch from sequence sharding to head sharding and back. The grid is one tensor ( tokens × 8 heads); each cell shows the rank that holds it, and the cells of the selected rank are magenta. Cells with an aqua border just arrived over the network. Then reduce the number of K/V heads below the number of ranks and read the warning.
Bytes per GPU and layer (forward, , bf16, multi-head attention):
| Method | Bytes sent per GPU | Overlapped with compute? |
|---|---|---|
| Megatron SP (degree ) | partly | |
| Ring attention (degree ) | yes, if | |
| Ulysses (degree ) | no |
Where the Ulysses line comes from: each rank holds tokens of Q, K, V and the output, bytes each; an all-to-all sends of it; there are four such tensors. With GQA, ring attention sends times fewer bytes, and Ulysses' K and V terms shrink by .
For multi-head attention, Ulysses sends times fewer bytes than ring attention, and its bytes per GPU stay constant when and grow together (the term does not change). Its limits:
- Head-count limit. Each rank needs whole heads, so cannot exceed the number of heads. With GQA, K and V have only heads, so unless K/V heads are copied.
- Exposed communication. The all-to-all sits on the critical path; attention cannot start before it ends. Across nodes, with slow links, this hurts.
Ring attention has no head limit (it needs only to hide its transfers) and works across nodes. The two combine: Ulysses inside a node, ring attention across nodes.
A model has 32 query heads and 8 K/V heads (GQA). You want context parallelism over 16 GPUs with Ulysses alone. What goes wrong?
After the all-to-all, a GPU computes attention for its query heads, and it needs the K/V head of each of them. With 8 K/V heads and 16 GPUs, two GPUs share each K/V head, so it must be copied to both. The usual fix is Ulysses over 8 GPUs (inside a node) and ring attention over the remaining factor of 2.
Mixture of experts and expert parallelism #
Parameters vs active parameters. Each token uses only of the experts. So the FLOPs per token follow the active parameters (the chosen experts plus attention), and the memory follows all parameters. Mixtral 8x7B: about 47B parameters, about 13B active per token.
Expert parallelism (EP). Put experts on each of GPUs. The attention part stays data-parallel: each GPU holds a different set of tokens. An MoE layer then runs in four steps:
- route: each GPU runs the router on its own tokens;
- dispatch (all-to-all): each token vector is sent to the GPUs that hold its experts;
- expert compute: each GPU runs its experts on the tokens it received;
- combine (all-to-all): the expert outputs go back to the GPU that holds the token, which forms the weighted sum .
Proposition (all-to-all bytes). With uniform routing, one copy of the token vector per (token, expert) pair, and bytes per element, each GPU sends per MoE layer in the forward pass
Proof.
- A GPU holds tokens, and each token has chosen experts: (token, expert) pairs.
- Each pair sends one token vector of elements, bytes, to the GPU of its expert.
- With uniform routing, the expert lies on any of the GPUs with probability . With probability it is on the same GPU, and nothing is sent. So the expected bytes of the dispatch are .
- The combine returns one output vector of elements per pair, on the same paths in reverse: the same number of bytes.
- Add the two.
The notebook checks this with a simulation. Compare it with the expert compute. Each pair costs FLOPs in a two-matrix MLP with inner width ( with SwiGLU, which has three matrices). For the two-matrix MLP in bf16, the time ratio is
So the all-to-all is cheap only when is large compared with . Over NVLink ( at peak) this is often true; over InfiniBand () it is not. So EP is cheapest inside a node. When it must cross nodes, systems limit how many nodes a token may visit and overlap the all-to-all with other work (see the folded box below).
The busiest GPU sets the time. Routing is learned, so it is not uniform. The all-to-all and the next layer wait for the slowest GPU. If one expert gets twice the mean load, its GPU computes twice as long, and every other GPU waits. Two tools fight this:
- Capacity factor. Each expert accepts at most tokens, where is the number of tokens routed together and is the mean load (Switch Transformer writes it for ). A token over the capacity is dropped for that expert: its update skips the expert and the token passes on through the residual connection. leaves room for imbalance but costs memory and padding.
- Load-balancing loss (Switch Transformer). Add to the loss, where is the fraction of tokens sent to expert and the mean router probability of expert . It equals for uniform routing and grows when a few experts get many tokens and high probability; the paper uses .
Move the router skew to make some experts popular. Each dot is one (token, expert) copy, stacked on the expert that receives it; the dashed line is the capacity. Blue copies are computed, magenta copies are dropped. The lower bars are the load of each GPU, and violet is the time the other GPUs wait for the busiest one. Set the capacity factor to "none": nothing is dropped, but the slowest GPU sets the step time.
Expert parallelism over 8 GPUs, one expert per GPU, no capacity limit. The router sends twice the mean load to expert 3 and slightly less than the mean to the others. What sets the time of the MoE layer?
The combine all-to-all can finish only when every expert has finished. GPU 3 has twice the mean work, so the layer takes about twice as long as with balanced routing, and the other seven GPUs sit idle part of that time. The total work is the same; its distribution is not. A capacity limit would cap the time but drop tokens.
Beyond the basic recipe
- Dropless MoE. MegaBlocks (Gale et al. 2022) computes all experts as one block-sparse matmul, so no token is dropped and no padding to the capacity is needed.
- DeepSeek-V3 (2024) trains with 64-way EP spread over 8 nodes. Each token is sent to at most 4 nodes, and custom all-to-all kernels use InfiniBand and NVLink together. It balances the load without a large auxiliary loss: a bias per expert is added to the routing scores only, and after each step it is decreased for overloaded experts and increased for underloaded ones.
- With (DeepSeek-V3's experts) and InfiniBand, the ratio above is far larger than 1. That is why such systems limit how many nodes a token may visit and overlap the all-to-all with the computation of other micro-batches.
Putting the axes together #
- Order from inner to outer. Llama 3 405B orders its axes as [TP, CP, PP, DP]: TP (with SP) inside the node, where the bandwidth is highest, then CP, then PP, then DP. For the 131,072-token stage it used TP 8, CP 16, PP 16 and DP 8 on 16,384 GPUs (Llama 3 paper, Table 4).
- Gradients. CP ranks hold the same weights but different tokens, so their weight gradients must be summed: Megatron reduces gradients over the DP × CP group. Under SP, the LayerNorm weight gradients are partial (each GPU saw tokens) and are all-reduced over the TP group.
- EP and DP. Non-expert weights are replicated over the data-parallel GPUs; expert weights are split over the EP group. So expert gradients are reduced only over the copies of each expert.
Answers to section 1. (1) It stays the same: an all-reduce is a reduce-scatter plus an all-gather. (2) About 20,000: tokens for multi-head attention, and about 4,900 with GQA at . (3) 8 times the parameters, but only about 2 times the FLOPs per token (2 experts run, plus a tiny router). Memory follows all parameters; compute follows the active ones.
4. Worked example #
(a) SP on a toy #
, 4 tokens, . After the row-parallel matmul, GPU 0 holds the partial sums and GPU 1 holds .
- TP: all-reduce. Both GPUs get , and both store the dropout and LayerNorm activations for 4 tokens. Sent per GPU: elements.
- SP: reduce-scatter. GPU 0 sends and gets ; GPU 1 sends and gets . Each runs dropout and LayerNorm on 2 tokens and stores 2 tokens. The all-gather before the next matmul sends 2 more elements each. Total: 4 elements, as before.
(b) SP memory for a 7B-like model #
, , , , FlashAttention, so :
- no parallelism: GB per layer;
- TP: MB per layer, 14.0 GB for 32 layers;
- TP + SP: MB per layer, 4.6 GB for 32 layers.
At the replicated part is of the TP memory, so SP saves a factor of 3.1.
(c) Causal ring attention with zig-zag, every block #
ranks, tokens, causal mask. We count work in (query, key) pairs with key ≤ query. The whole sequence has such pairs, so the best possible is per rank.
Zig-zag. chunks of one token. Rank holds tokens and : rank 0 has , rank 1 , rank 2 , rank 3 . In round , rank holds the K/V tokens of rank .
| Round | rank 0: Q | rank 1: Q | rank 2: Q | rank 3: Q | round time |
|---|---|---|---|---|---|
| 0 | K/V : (0,0) (7,0) (7,7) = 3 | : (1,1) (6,1) (6,6) = 3 | : (2,2) (5,2) (5,5) = 3 | : (3,3) (4,3) (4,4) = 3 | 3 |
| 1 | : (7,3) (7,4) = 2 | : (1,0) (6,0) = 2 | : (2,1) (5,1) = 2 | : (3,2) (4,2) = 2 | 2 |
| 2 | : (7,2) (7,5) = 2 | : (6,3) (6,4) = 2 | : (2,0) (5,0) = 2 | : (3,1) (4,1) = 2 | 2 |
| 3 | : (7,1) (7,6) = 2 | : (6,2) (6,5) = 2 | : (5,3) (5,4) = 2 | : (3,0) (4,0) = 2 | 2 |
| total | 9 | 9 | 9 | 9 | 9 |
Each entry lists the visible pairs (query, key). Every rank does 9 pairs, and the ring takes pair-times: the optimum.
Contiguous. Rank holds tokens and . Against its own block a rank does 3 pairs, against an earlier block 4 pairs, against a later block 0. The work per rank is . Rank 3 holds an earlier block in rounds 1, 2 and 3, so the ring takes pair-times. Zig-zag is times faster here. For long blocks (where the diagonal costs half a block) the ratio is for .
The merge for one query. Rank 0's query 7 meets keys , then , then , then . After each round it merges the new into its running pair. The order differs from , but the merge is exact in any order, so the result equals full causal attention (the notebook checks this to ).
(d) Ring attention at 128K tokens #
on H100s, so ; , multi-head attention, at peak.
- Compute per round: FLOPs, 4.45 ms at 989 TFLOP/s.
- Transfer per round: MB. Over NVLink (450 GB/s): 0.60 ms, hidden. Over a 50 GB/s network: 5.37 ms, not hidden, as predicts.
- With GQA at : 67 MB, 1.34 ms, hidden again.
- Per layer, ring attention sends GB per GPU. Ulysses would send MB, times less, but on the critical path.
(e) One MoE layer #
A Mixtral-like layer: , experts on GPUs, top-2, SwiGLU experts with , tokens per GPU, bf16, uniform routing, at peak.
- All-to-all bytes per GPU: MB. Over NVLink: 0.52 ms. Over InfiniBand: 4.70 ms.
- Expert FLOPs per GPU: copies, each MFLOP: FLOPs, 5.84 ms.
- Ratio: 0.09 over NVLink, 0.80 over InfiniBand. Check with the formula (SwiGLU has 1.5 times the FLOPs): . Across nodes, the all-to-all costs almost as much as the experts.
5. In code #
NumPy checks of sections 3 and 4: sequence parallelism, the causal work per round, the minimum block size, and the MoE bytes.
import numpy as np
rng = np.random.default_rng(0)
# (a) Sequence parallelism: reduce-scatter + token-wise op + all-gather
t, s, h = 4, 8, 16 # TP degree, tokens, hidden size
partials = rng.standard_normal((t, s, h)) # row-parallel matmul output on each GPU
def layer_norm(x): # token-wise: each row is normalised alone
mu, var = x.mean(-1, keepdims=True), x.var(-1, keepdims=True)
return (x - mu) / np.sqrt(var + 1e-5)
tp = layer_norm(partials.sum(0)) # TP: all-reduce, then every GPU runs LN on all s tokens
shards = [partials[:, i*s//t:(i+1)*s//t].sum(0) for i in range(t)] # reduce-scatter
sp = np.concatenate([layer_norm(x) for x in shards]) # LN on s/t tokens, all-gather
print(np.abs(sp - tp).max()) # 0.0
n = s * h * 2 # bytes of the activation in bf16
print(2 * (t-1)/t * n, (t-1)/t * n + (t-1)/t * n) # all-reduce vs RS + AG: 384.0 384.0
# (b) Causal work per round, token level (s = 8 tokens, N_c = 4 ranks)
Nc, s = 4, 8
layouts = {"contiguous": [[2*r, 2*r+1] for r in range(Nc)],
"zig-zag": [[r, 2*Nc-1-r] for r in range(Nc)]}
for name, tok in layouts.items():
# round k: rank r holds the K/V tokens of rank (r - k) mod N_c; count pairs with key <= query
w = np.array([[sum(kk <= q for q in tok[r] for kk in tok[(r-k) % Nc]) for r in range(Nc)]
for k in range(Nc)])
print(f"{name:10s} per rank {w.sum(0)} per round max {w.max(1)} ring time {w.max(1).sum()}")
# contiguous per rank [ 3 7 11 15] per round max [3 4 4 4] ring time 15
# zig-zag per rank [9 9 9 9] per round max [3 2 2 2] ring time 9
# (c) Minimum block size c >= F / W (bf16, multi-head attention)
F = 989e12 # H100 dense bf16 peak, FLOP/s
for name, W in [("NVLink", 450e9), ("InfiniBand", 50e9)]:
print(name, round(F / W)) # NVLink 2198, InfiniBand 19780
# (d) MoE dispatch: bytes per GPU, simulated vs formula
Ne, E, k, T, h, e = 8, 64, 2, 4096, 1024, 2
experts_per_gpu = E // Ne
sent = []
for g in range(Ne): # tokens of GPU g pick k distinct experts uniformly
choice = np.argsort(rng.random((T, E)), axis=1)[:, :k]
sent.append((choice // experts_per_gpu != g).sum() * h * e)
print(2 * np.mean(sent) / 1e6, 2 * k * T * h * e * (Ne-1) / Ne / 1e6) # MB: dispatch + combine
# 29.425152 29.360128
The simulated bytes differ from the formula by 0.2%: the formula is the expected value, and the simulation draws random experts.
6. Where it shows up #
- Long-context LLM training. Llama 3 trains up to 128K tokens with CP (Llama 3 paper, §3.3.2). It uses the zig-zag split, but it all-gathers K and V instead of passing them around a ring: with GQA, K and V are much smaller than Q, and an all-gather makes masks such as document masks easy. The exposed all-gather is , while attention is .
- Mixture-of-experts models. Switch Transformer, GShard, Mixtral and DeepSeek-V3 all use expert parallelism with dispatch and combine all-to-alls. Load balancing (a loss, a capacity factor, or a routing bias) is part of every recipe.
- ML for science. Global weather and climate grids, long DNA sequences, long seismic records and video all give – tokens. Ring attention is domain decomposition for attention: a stencil code exchanges only halos with its neighbours, but global attention needs every block, so the blocks travel around the ring.
- Inference. The same ideas split the prefill of very long prompts and the attention of video diffusion transformers. MoE serving also spreads the experts over GPUs with EP.
7. Common mistakes #
- "SP adds communication." It replaces each all-reduce by its two halves. The bytes are the same.
- Forgetting the gradient sums. Under SP each GPU sees only tokens, so the LayerNorm weight gradients are partial and must be all-reduced over the TP group. Under CP, weight gradients must be summed over the CP ranks too.
- Contiguous causal sharding. It wastes about half of the compute. Use zig-zag (or a striped layout).
- Using blindly. With a causal mask the work per round halves (); with GQA the bytes shrink by ; and is the attention FLOP/s you really achieve, not the peak.
- Ulysses with more GPUs than K/V heads. The degree is limited by the head count; beyond it, combine with ring attention.
- "An MoE model with 8 experts costs 8 times the FLOPs." FLOPs follow the active experts; memory follows all .
- Ignoring load imbalance. The all-to-all waits for the busiest GPU. Measure the max load, not the mean.
8. Check yourself #
- Under TP + SP, how many collectives run per layer in one forward and one backward pass?
Answer
Four all-gathers and four reduce-scatters (TP alone: four all-reduces), with the same bytes. Megatron adds one extra all-gather per stored LayerNorm-output shard in the backward pass, overlapped with the gradient computation. - , , , , FlashAttention. Give the activation memory per layer with
TP, and with TP + SP.
Answer
. TP: MB. TP + SP: MB. - Why does the minimum block size double with a causal mask and a zig-zag layout?
Answer
Each round a rank computes only half a block ( FLOPs), but it still sends full K and V blocks ( bytes): . - Why can the ring visit the K/V blocks in any order?
Answer
The logsumexp merge gives the exact softmax over the union of disjoint key sets, and it is associative and commutative. - A model has 32 query heads and 8 K/V heads. What is the largest Ulysses degree without copying K/V
heads, and what can you use beyond it?
Answer
8: each rank needs whole K/V heads. Beyond it, combine Ulysses with ring attention (ring across groups of 8), or copy K/V heads at a higher communication cost. - EP over GPUs, tokens per GPU, top-1, , bf16, uniform routing. How
many bytes does each GPU send per MoE layer in the forward pass?
Answer
bytes MB: dispatch and combine, each of bytes.
Which regions does Megatron sequence parallelism shard, and along which axis?
The regions that TP leaves replicated (LayerNorm, dropout, residual add), along the sequence axis , inside the TP group.
Why does sequence parallelism send the same bytes as plain TP?
An all-reduce is a reduce-scatter plus an all-gather. SP runs the same two halves at different places in the layer, with the token-wise ops in between.
Activation memory per layer with TP alone, and with TP + SP?
TP: . TP + SP: . The replicated term is what SP removes.
State the minimum block size for ring attention and its derivation in one line.
: compute must cover the transfer (bf16, multi-head attention).
Ring attention on H100s: TFLOP/s, GB/s, multi-head attention. Minimum tokens per rank?
tokens (about 4,900 with GQA at ; double these with a causal mask).
In the zig-zag layout with ranks, which chunks does rank hold?
Chunks and of chunks: one early and one late, so the causal work is equal on every rank.
What do the two all-to-alls of DeepSpeed-Ulysses do?
The first switches Q, K, V from sequence sharding to head sharding (all tokens, heads per rank); the second switches the attention output back.
What limits the Ulysses degree ?
The number of heads: each rank needs whole heads. With GQA, the number of K/V heads , unless K/V heads are copied.
Bytes per GPU of the MoE all-to-alls in one forward pass, with uniform routing?
: dispatch and combine each send token vectors, of which go to other GPUs.
What does the capacity factor control in an MoE layer?
The maximum number of tokens per expert, . Tokens above are dropped for that expert and pass on through the residual connection.
9. Interview angle #
- "How would you train with a 1M-token context?" FlashAttention on each GPU, TP + SP inside the node, ring attention (CP) across nodes with a zig-zag layout; check (or with a causal mask and GQA). Activation memory per GPU falls as .
- "SP vs CP?" SP shards only the norm/dropout regions inside the TP group and keeps the bytes of TP. CP shards all activations, attention included, and works across nodes.
- "Ring attention vs Ulysses?" Ring: point-to-point, overlapped, no head limit, needs , more bytes. Ulysses: two all-to-alls, times fewer bytes (multi-head attention), exposed, heads. Combine: Ulysses in the node, ring across nodes.
- "Why is MoE training hard to scale?" Two all-to-alls per MoE layer, with bytes per GPU; slow across nodes unless ; the busiest expert sets the time, so you need capacity factors, a balance loss or a routing bias, and you trade dropped tokens against padding.
- "What is the difference between total and active parameters?" Total sets the memory (all experts are stored); active sets the FLOPs per token (only experts run).
10. Practice #
The notebook for this lesson runs in Colab, with NumPy only. It has five exercises, each with a check cell and a folded solution:
- SP check. Reduce-scatter, a token-wise op and all-gather on a simulated TP group give the same result as all-reduce and the op, with the same bytes.
- Ring attention. Four simulated ranks pass K/V blocks around a ring and merge partial results with the logsumexp formula; check against full (causal) attention.
- Load balance. Work per rank and per round for the contiguous and zig-zag layouts, and the ring time, for several .
- Ulysses. An all-to-all reshard on NumPy arrays (sequence → heads → sequence), attention per head group, checked against full attention; count the bytes.
- MoE dispatch. A top- routing simulator with a capacity factor: dropped-token rate, all-to-all bytes and the max/mean load as the router skew grows.
11. Watch and read #
- Korthikanti et al. (2022), Reducing Activation Recomputation in Large Transformer Models: §4.1 (the count), §4.2.1 (Eq. 2), §4.2.2 (Fig. 5–6, Eqs. 3–4, sequence parallelism).
- Liu, Zaharia and Abbeel (2023), Ring Attention with Blockwise Transformers for Near-Infinite Context: §3 (arithmetic intensity between hosts, memory requirement).
- Jacobs et al. (2023), DeepSpeed Ulysses: System Optimizations for Enabling Training of Extreme Long Sequence Transformer Models: §3.1 (design), §3.2 (communication analysis).
- Llama Team (2024), The Llama 3 Herd of Models: §3.3.2 (context parallelism, zig-zag chunks, all-gather of K/V) and Table 4.
- Fedus, Zoph and Shazeer (2021), Switch Transformers: §2.1–2.2 (routing, capacity factor, load-balancing loss).
- Lepikhin et al. (2020), GShard: top-2 gating and expert placement across devices.
- Jiang et al. (2024), Mixtral of Experts.
- DeepSeek-AI (2024), DeepSeek-V3 Technical Report: §2.1.2 (auxiliary-loss-free load balancing), §3.2 (expert parallelism and all-to-all kernels).
- Gale et al. (2022), MegaBlocks: Efficient Sparse Training with Mixture-of-Experts.
- Hugging Face, The Ultra-Scale Playbook: sections on sequence parallelism, context parallelism (ring and zig-zag) and expert parallelism.
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.
No Google account needed: Python runs inside your browser. The first start downloads about 40 MB; your changes are saved in this browser only.