6.1.7 · D2Scaling & Efficient Architectures

Visual walkthrough — Model parallelism (tensor, pipeline)

1,952 words9 min readBack to topic

The parent note told you that tensor parallelism "partitions individual weight matrices... across multiple devices" and that the Transformer MLP uses a column-parallel then row-parallel pattern that needs only one all-reduce per block. That is the central result. This page earns every piece of it with a picture, starting from what a matrix multiply even looks like.

We will build up to this claim:

Prerequisites we lean on: Transformer Architecture (what an MLP block is), GPU Memory Hierarchy (why one GPU runs out of room), and the sibling idea Data Parallelism (which copies the whole model instead of cutting it). Parent: Model parallelism.


Step 1 — What a matrix multiply actually is

WHAT. Before splitting anything, we must agree on what means. A matrix is just a grid of numbers. Multiplying (the input, one row per example in the batch) by (the weights) produces (the output).

Read the symbols slowly:

  • ::: how many examples we push through at once (the batch).
  • ::: how many numbers describe each input example.
  • ::: how many numbers come out per example.

WHY. The whole reason we care about splitting matrices is that is enormous — in GPT-3 a single weight grid can hold hundreds of millions of numbers, more than one GPU can hold (see GPU Memory Hierarchy). So we must understand its shape before we cut it.

PICTURE. One output number is a row of dotted against a column of — slide across, multiply pairwise, add up. That "column of decides one column of " fact is the seed of everything.


Step 2 — The one fact that lets us cut into columns

WHAT. We chop vertically into side-by-side slabs, each a bunch of columns:

  • The bars ::: mean "placed next to each other, side by side" (concatenation of columns).
  • ::: device 's slab — shape .
  • ::: how many output columns each device owns.

Then, from Step 1's fact that each column of independently makes one column of :

WHY this tool — concatenation, not addition. We could have split into rows instead, but a column split has a magic property: each slab produces a whole, finished slice of the output, needing no help from the other devices. No sum, no talking. That independence is exactly what we exploit next.

PICTURE. Colour each column-slab of a different colour; the output inherits the same coloured stripes. Device 1 owns the cyan stripe, device 2 the amber stripe — they never look at each other's stripe.


Step 3 — Column-parallel costs a copy of , not a conversation

WHAT. Each device computes locally: Device ends up holding only its stripe (shape ).

  • ::: every device needs the full input — so we broadcast one copy to all.
  • ::: only of the output lives on each device.

WHY. This is the memory win the parent promised: each device stores output columns and of 's numbers instead of all of them. The price is duplicating — but is tiny compared to , so this is a great trade.

PICTURE. Two GPU boxes. The same arrow feeds both; each box lights up only its own coloured output stripe. Notice: no arrow runs between the boxes. That empty gap is the point.


Step 4 — GELU is applied element-by-element, so the split survives

WHAT. In the real MLP the first layer is . is a nonlinearity: it takes each single number and bends it (roughly, it softly zeroes out negatives).

The crucial property:

  • ::: acts on one number at a time — it never mixes columns together.
  • ::: our already-split hidden stripes.

WHY this matters. If mixed columns (like a softmax across the whole row would), we'd be forced to gather back together before applying it — a full communication step. Because is element-wise, device can apply it to its own stripe and stay split. This is precisely why the parent could say "No communication yet!" after .

PICTURE. Each hidden stripe passes through its own little GELU curve; the stripes never touch. The colour boundaries are preserved.


Step 5 — Now switch to a row-split for so the pieces recombine

WHAT. The hidden state is split into column-stripes . The second weight maps . We split the other way — into rows:

Because is split by columns and by matching rows, the multiply becomes a sum of partial products:

  • ::: device 's hidden stripe (from Step 4).
  • ::: device 's matching row-slab of .
  • ::: a full-width, partial output — right shape, but only part of the true value.
  • ::: add all the partials to get the real .

WHY row-split now. A row-split of lines up perfectly with the column-split of : dimensions match so each device can multiply its own by its own with no reshuffling of . The only debt we incur is the final .

PICTURE. Each device produces a faint, full-size output tile (correct shape, partial value). Stacked and summed, the faint tiles add up to the solid true output.


Step 6 — The single all-reduce (and why it's exactly one)

WHAT. The devices each hold a partial . Getting the true onto every device is one collective operation called an all-reduce.

  • ::: each device's partial contribution.
  • The all-reduce ::: performs and broadcasts it — one round of talking.

WHY only one. Trace the whole block: broadcast (input, cheap) → column-parallel (silent) → GELU (silent) → row-parallel (silent, produces partials) → one all-reduce. The clever column-then-row pairing pushed all the communication into a single point. A naive design that gathered after and after would need two rounds and move far more data.

PICTURE. Two GPUs holding faint partial tiles; amber arrows converge into a central "" node and fan back out carrying the solid full result to both.


Step 7 — Edge and degenerate cases (never leave the reader stranded)

WHAT / WHY / PICTURE, three quick corners:

  1. (one device). The sum collapses to plain . No split, no all-reduce — tensor parallelism gracefully becomes ordinary computation. Good sanity check.
  2. not divisible by . Our slab width must be a whole number of columns. If , you cannot split evenly. Real systems pad up to a multiple of (or choose dividing it) — e.g. attention heads, which are already an integer count, split cleanly.
  3. The backward pass mirrors the forward. The parent note showed — a sum over devices, i.e. another all-reduce, but now on the input-gradient. Forward's all-reduce sits at the block output; backward's sits at the block input. Symmetric bookends.

The one-picture summary

The full journey on one blueprint: broadcast → column-split (silent) → element-wise GELU (silent) → row-split (silent, partials) → one all-reduce → .

Recall Feynman retelling — say it back in plain words

Imagine a big multiplication job written on a giant sheet too heavy for one worker to hold. We cut the first weight-sheet into vertical strips and give each worker one strip plus a photocopy of the input. Each worker finishes their own vertical stripe of the answer without talking to anyone — that's the free lunch of a column split. Then a bending step (GELU) that only ever looks at one number at a time keeps those stripes separate, so still nobody talks. For the second weight-sheet we cut it into horizontal strips that line up with everyone's stripe, so each worker again multiplies just their own pieces — producing a full-size but incomplete answer. Finally everyone tosses their incomplete answer into one pile, we add them up, and hand the finished total back to all of them. That single "throw it in the pile and share the total" step is the one all-reduce. Because we cleverly went column-first then row, we only had to talk once per MLP block — and the backward pass does the exact same trick, just at the other end.


Quick self-check

Bubble-free understanding check
In a column-parallel layer, why does each device need the whole input but only part of ?
Answer
Because a column of the output depends on all of but only one column of ; the columns of are independent, so each device owns some output columns and needs full to compute them.
Why one all-reduce, not two?
Column-parallel produces split output, element-wise GELU preserves the split, and row-parallel turns the split back into a single summable set of partials — so communication is deferred to exactly one point.