Tensor Parallelism › Worked Example: Column-Parallel FFN

Michael BrenndoerferJanuary 19, 20262 min read
Language AI HandbookAll chapters
Part 31 of 67Training Infrastructure
Chapter 223Tensor Parallelism › Worked Example: Column-Parallel FFN
Reading section 8 of 12 · Worked Example: Column-Parallel FFN · 2 minSection 8 of 12 · 2 min

Book contents

Section 8 of 12 · 2 min read

Tensor Parallelism › Worked Example: Column-Parallel FFNOne section · Sections in this chapter8 / 12 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Let's trace through a specific numerical example to make the computation concrete. Suppose we have a feed-forward network with input dimension d=4d = 4, hidden dimension h=8h = 8, and we are using N=2N = 2 GPUs.

The full weight matrix W1∈R4×8W_1 \in \mathbb{R}^{4 \times 8} is split column-wise:

W1=[W1,0∣W1,1]W_1 = [W_{1,0} \mid W_{1,1}]

where W1,0∈R4×4W_{1,0} \in \mathbb{R}^{4 \times 4} lives on GPU 0 and W1,1∈R4×4W_{1,1} \in \mathbb{R}^{4 \times 4} lives on GPU 1.

Given an input X∈R2×4X \in \mathbb{R}^{2 \times 4} (batch of 2 tokens, each with 4 features), both GPUs have the full input. GPU 0 computes:

Z0=XW1,0∈R2×4Z_0 = X W_{1,0} \in \mathbb{R}^{2 \times 4}

and GPU 1 computes:

Z1=XW1,1∈R2×4Z_1 = X W_{1,1} \in \mathbb{R}^{2 \times 4}

After the GeLU nonlinearity applied locally on each GPU, the activations Z^0\hat{Z}_0 and Z^1\hat{Z}_1 together form the full intermediate representation [Z^0∣Z^1]∈R2×8[\hat{Z}_0 \mid \hat{Z}_1] \in \mathbb{R}^{2 \times 8}. Neither GPU needed to communicate with the other to reach this point.

The second weight matrix W2∈R8×4W_2 \in \mathbb{R}^{8 \times 4} is split row-wise:

W2=[W2,0W2,1]W_2 = \begin{bmatrix} W_{2,0} \\ W_{2,1} \end{bmatrix}

where W2,0∈R4×4W_{2,0} \in \mathbb{R}^{4 \times 4} on GPU 0 and W2,1∈R4×4W_{2,1} \in \mathbb{R}^{4 \times 4} on GPU 1.

GPU 0 multiplies its activation shard by its weight shard: Y0=Z^0W2,0∈R2×4Y_0 = \hat{Z}_0 W_{2,0} \in \mathbb{R}^{2 \times 4}. GPU 1 multiplies its activation shard by its weight shard: Y1=Z^1W2,1∈R2×4Y_1 = \hat{Z}_1 W_{2,1} \in \mathbb{R}^{2 \times 4}.

The final output is obtained by all-reducing (summing) across GPUs:

Y=Y0+Y1∈R2×4Y = Y_0 + Y_1 \in \mathbb{R}^{2 \times 4}

This is identical to the full computation Y=GeLU(XW1)W2Y = \text{GeLU}(XW_1) W_2, but computed with weight matrices that fit on individual GPUs. The only communication is the final all-reduce that sums Y0Y_0 and Y1Y_1.

What makes this example particularly illuminating is the absence of intermediate communication. Between the column-parallel step and the row-parallel step, GPUs 0 and 1 proceed completely independently. GPU 0 never needs to know what Z1Z_1 looks like. GPU 1 never needs to know what Z0Z_0 looks like. They only need to coordinate once, at the very end, to produce the final output. This one communication per two linear layers is the core efficiency of Megatron-style tensor parallelism.