MODULE 10  ยท  GPU & Hardware

Multi-GPU Setups: Splitting Models Across GPUs

Llama 3 405B in FP16 is 810 GB. The biggest GPU has 192 GB. You need at least 5 GPUs. Here's how model parallelism works.

๐Ÿ“… Mar 2026
โฑ 10 min read
๐ŸŽฏ Episode 66 of 98
Multi-GPUModel ParallelismNVLinkScaling
In this episode
snippet
code
Llama 3 405B in FP16 is 810 GB. The biggest single GPU has 192 GB of VRAM. You need a minimum of 5 GPUs just to hold the weights โ€” and that's without KV cache, activations, or any breathing room.

When your model doesn't fit on one GPU, you split it across multiple GPUs. But how you split it matters enormously. The wrong strategy can make 8 GPUs slower than 4. The right strategy scales nearly linearly.

There are three fundamental approaches โ€” data parallelism, tensor parallelism, and pipeline parallelism โ€” and most real systems use all three simultaneously. This episode is your guide to when and why.

Data Parallelism: Same Model, Different Data

The simplest approach. Every GPU holds a complete copy of the model. Each GPU processes a different batch of data.

GPU 0: Full model copy โ†’ processes batch 0 โ†’ gradients_0

GPU 1: Full model copy โ†’ processes batch 1 โ†’ gradients_1

GPU 2: Full model copy โ†’ processes batch 2 โ†’ gradients_2

GPU 3: Full model copy โ†’ processes batch 3 โ†’ gradients_3

example
code
โ†“
          All-Reduce: average gradients across GPUs
                    โ†“
          All GPUs update their model copy

When Data Parallelism Works

Situation Works? Why

Model fits on 1 GPUโœ…Each GPU has full copy
Model doesn't fit on 1 GPUโŒCan't copy what doesn't fit
Training with big datasetsโœ…Linear throughput scaling
Inferenceโš ๏ธWastes VRAM (N copies of model)

The Communication Cost

After each training step, GPUs must synchronize their gradients. This is the All-Reduce operation:

Data to communicate = 2 ร— model_size (send + receive gradients)

For a 7B model in FP32:

snippet
code
All-Reduce data = 2 ร— 28 GB = 56 GB per step
With NVLink (900 GB/s):   56 / 900 = 0.062 seconds
With PCIe (64 GB/s):      56 / 64 = 0.875 seconds  โ† 14x slower!

This is why interconnect bandwidth matters. PCIe-connected multi-GPU training can spend more time communicating than computing.

DDP and FSDP

snippet
code
DDP (Distributed Data Parallel): Standard PyTorch data parallelism. Each GPU has a full model copy. Simple and efficient.
FSDP (Fully Sharded Data Parallel): Instead of each GPU holding a full model copy, each GPU holds a shard (fraction) of the model. Parameters are gathered on-demand when needed, then discarded. This means a model that doesn't fit on one GPU CAN be trained with data parallelism.

DDP with 4 GPUs:

snippet
code
GPU 0: full 7B copy (28 GB) + optimizer (56 GB) = 84 GB  โ† Needs A100 80GB

GPU 1: full 7B copy (28 GB) + optimizer (56 GB) = 84 GB

FSDP with 4 GPUs:

snippet
code
GPU 0: 1/4 of 7B (7 GB) + 1/4 optimizer (14 GB) = 21 GB  โ† Fits on RTX 4090!

GPU 1: 1/4 of 7B (7 GB) + 1/4 optimizer (14 GB) = 21 GB

FSDP trades communication for memory. More communication (gathering parameters before each layer), but far less VRAM per GPU.

โšก

Tensor Parallelism: Splitting Individual Layers

Tensor parallelism splits each layer across GPUs. Instead of each GPU running a complete layer, each GPU runs a slice of every layer.

Without Tensor Parallelism (1 GPU):

snippet
code
Layer 1: Weight matrix [4096 ร— 4096] โ†’ full computation on GPU 0

With Tensor Parallelism (4 GPUs):

Layer 1: Split weight [4096 ร— 4096] into 4 pieces

example
code
GPU 0: Weight slice [4096 ร— 1024] โ†’ partial result
    GPU 1: Weight slice [4096 ร— 1024] โ†’ partial result
    GPU 2: Weight slice [4096 ร— 1024] โ†’ partial result
    GPU 3: Weight slice [4096 ร— 1024] โ†’ partial result
    โ†’ All-Reduce: combine partial results โ†’ full output

How Matrix Multiply Gets Split

For a weight matrix W of shape [N ร— M], with tensor parallelism degree P:

Column parallel (split output):

W = [Wโ‚Wโ‚‚Wโ‚ƒWโ‚„] (split columns across 4 GPUs)

GPU 0: x ร— Wโ‚ = yโ‚ (each GPU gets partial output)

GPU 1: x ร— Wโ‚‚ = yโ‚‚

GPU 2: x ร— Wโ‚ƒ = yโ‚ƒ

GPU 3: x ร— Wโ‚„ = yโ‚„

All-Gather: y = [yโ‚, yโ‚‚, yโ‚ƒ, yโ‚„] (combine outputs)

Row parallel (split input):

snippet
code
W = [Wโ‚; Wโ‚‚; Wโ‚ƒ; Wโ‚„]  (split rows across 4 GPUs)

GPU 0: xโ‚ ร— Wโ‚ = partial_0

GPU 1: xโ‚‚ ร— Wโ‚‚ = partial_1

GPU 2: xโ‚ƒ ร— Wโ‚ƒ = partial_2

GPU 3: xโ‚„ ร— Wโ‚„ = partial_3

All-Reduce: y = partial_0 + partial_1 + partial_2 + partial_3

In practice, transformers alternate between column-parallel and row-parallel splits across the two linear layers in FFN and the QKV projections in attention. This cancels out communication โ€” each layer only needs one All-Reduce.

When Tensor Parallelism Works

Situation Works? Why

Model doesn't fit on 1 GPUโœ…Splits weights across GPUs
Inference latency-sensitiveโœ…All GPUs work on every token
Trainingโœ…Standard for large models
GPUs connected via NVLinkโœ…Fast communication
GPUs connected via PCIeโš ๏ธCommunication bottleneck
GPUs across different serversโŒToo much inter-node traffic

Critical requirement: Tensor parallelism needs high-bandwidth interconnect (NVLink). Every token requires All-Reduce across GPUs. With PCIe, the communication overhead destroys performance.

Communication per layer per token (All-Reduce):

snippet
code
Data = 2 ร— hidden_dim ร— bytes_per_value / TP_degree

For Llama 3 70B, FP16, TP=8:

Per layer: 2 ร— 8192 ร— 2 / 8 = 4 KB per token per layer

ร— 80 layers = 320 KB per token

At NVLink (900 GB/s): 0.36 ฮผs per token โ† Fine

At PCIe (64 GB/s): 5 ฮผs per token โ† Significant overhead

๐Ÿ”ง

Pipeline Parallelism: Splitting by Layers

Pipeline parallelism puts different layers on different GPUs:

GPU 0: Layers 0-19 (Embedding + first 20 layers)

GPU 1: Layers 20-39

GPU 2: Layers 40-59

GPU 3: Layers 60-79 (last 20 layers + output head)

Data flows: GPU 0 โ†’ GPU 1 โ†’ GPU 2 โ†’ GPU 3

The Pipeline Bubble

The problem: GPUs are idle while waiting for data from the previous stage.

Time โ†’

GPU 0: [Batch 0] [idle] [idle] [idle] [Batch 1] ...

GPU 1: [idle] [Batch 0] [idle] [idle] [idle] ...

GPU 2: [idle] [idle] [Batch 0] [idle] [idle] ...

GPU 3: [idle] [idle] [idle] [Batch 0] [idle] ...

Each GPU is idle 75% of the time! This is the "pipeline bubble."

Micro-batching: The Fix

Split each batch into micro-batches and pipeline them:

Time โ†’

GPU 0: [ฮผ0] [ฮผ1] [ฮผ2] [ฮผ3] [idle] [idle]

GPU 1: [ฮผ0] [ฮผ1] [ฮผ2] [ฮผ3] [idle]

GPU 2: [ฮผ0] [ฮผ1] [ฮผ2] [ฮผ3]

GPU 3: [ฮผ0] [ฮผ1] [ฮผ2] [ฮผ3]

Much better! GPUs are busy most of the time.

Bubble fraction โ‰ˆ (num_stages - 1) / num_microbatches

With 4 pipeline stages and 32 micro-batches, the bubble is only (4-1)/32 โ‰ˆ 9% โ€” much more efficient.

When Pipeline Parallelism Works

Situation Works? Why

GPUs across serversโœ…Low communication (only activations between layers)
PCIe connectionsโœ…Transfers are sequential, not all-to-all
Inferenceโš ๏ธPipeline bubble hurts single-request latency
Training with large batchesโœ…More micro-batches = smaller bubble

Key advantage: Pipeline parallelism only transfers activations between GPUs โ€” a single vector per layer per token. Much less data than tensor parallelism's All-Reduce.

Inter-GPU transfer per token:

Tensor Parallelism: 320 KB (All-Reduce every layer)

Pipeline Parallelism: 16 KB (one activation vector at stage boundary)

๐Ÿ“Š

Combining All Three: The 3D Approach

Real production systems combine all three methods:

Example: Training 405B model on 128 GPUs

Data Parallelism: DP=4 (4 model replicas, different data)

Tensor Parallelism: TP=8 (each layer split across 8 GPUs)

Pipeline Parallelism: PP=4 (layers split into 4 stages)

Total GPUs: 4 ร— 8 ร— 4 = 128

example
code
DP Group 0              DP Group 1
                โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

Pipeline Stage 0โ”‚ TP: 8 GPUs โ”‚ โ”‚ TP: 8 GPUs โ”‚

Pipeline Stage 1โ”‚ TP: 8 GPUs โ”‚ โ”‚ TP: 8 GPUs โ”‚

Pipeline Stage 2โ”‚ TP: 8 GPUs โ”‚ โ”‚ TP: 8 GPUs โ”‚

Pipeline Stage 3โ”‚ TP: 8 GPUs โ”‚ โ”‚ TP: 8 GPUs โ”‚

example
code
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Which to Use When

Strategy Use When Interconnect Needed Scales

Data ParallelismModel fits on 1 GPU, want throughputAny (NVLink preferred)Throughput
Tensor ParallelismNeed to reduce per-GPU memory + latencyNVLink (required)Latency
Pipeline ParallelismModel spans serversNetwork/PCIe OKMemory
FSDPTraining model that barely doesn't fitAnyMemory
TP + PP (combined)Very large modelsNVLink within node, network betweenBoth

The Decision Tree

Does the model fit on 1 GPU?

โ”œโ”€โ”€ YES โ†’ Use 1 GPU (or Data Parallelism for throughput)

โ”œโ”€โ”€ NO โ†’ Does it fit on GPUs within one server (with NVLink)?

snippet
code
โ”‚   โ”œโ”€โ”€ YES โ†’ Tensor Parallelism (TP=2,4,8)

โ”‚ โ””โ”€โ”€ NO โ†’ Pipeline Parallelism across servers

โ”‚ + Tensor Parallelism within server

โ””โ”€โ”€ Training?

example
code
โ””โ”€โ”€ Add Data Parallelism on top for throughput

NVLink: The Enabler

NVLink makes multi-GPU work viable. Without it, tensor parallelism is impractical:

8 GPU server with NVLink (DGX H100):

GPU-to-GPU: 900 GB/s

Any GPU can talk to any GPU at full speed

TP=8 works beautifully

8 GPU server with PCIe:

GPU-to-GPU: 64 GB/s (through CPU)

14x slower than NVLink

TP=8 is a disaster โ€” communication bottleneck

Rule of thumb:

NVLink โ†’ TP up to 8

snippet
code
PCIe โ†’ TP=2 max, prefer PP instead
๐Ÿ’ก

Inference-Specific Parallelism

For serving models, the strategies differ from training:

Tensor Parallelism for Latency

When you need fast single-request response time, TP reduces latency because all GPUs work on every token:

snippet
code
70B on 1 GPU:  reads 140 GB weights โ†’ limited by bandwidth
70B on 8 GPUs: each reads 17.5 GB weights โ†’ 8x faster (minus communication)

Practical speedup with TP=8: ~5-6x (not full 8x due to communication)

Expert Parallelism for MoE

MoE models have a natural parallelism strategy โ€” put different experts on different GPUs:

Mixtral 8x7B with 8 GPUs:

GPU 0: Expert 0 + shared attention

GPU 1: Expert 1 + shared attention

...

GPU 7: Expert 7 + shared attention

Each token โ†’ router decides experts โ†’ data goes to those GPUs โ†’ results combine

This is Expert Parallelism (EP) โ€” and it maps perfectly to MoE's sparse activation. Since only 2 experts are active per token, only 2 GPUs do real work for each token.

๐Ÿ”ฌ

Practical Multi-GPU Configurations

Model Recommended Setup GPUs Notes

8B FP16Single GPU1ร— RTX 4090Fits easily
70B INT4Single GPU1ร— A100 80GB35 GB + KV cache
70B FP16TP=22ร— A100 80GB70 GB per GPU
70B FP16, high throughputTP=4 or TP=84-8ร— A100Latency + throughput
405B INT4TP=8 or PP=4,TP=28ร— A100Barely fits
405B FP16PP + TP16-32ร— H100Production scale

๐Ÿ›ก๏ธ

Practical Takeaways

Data parallelism for throughput โ€” same model on each GPU, different data, scale training linearly

Tensor parallelism for latency โ€” split layers across GPUs, all work on every token, requires NVLink

Pipeline parallelism for scale โ€” different layers on different GPUs, works across servers

NVLink is mandatory for tensor parallelism โ€” PCIe is 14x slower and kills performance

FSDP lets you train models that don't fit on one GPU โ€” shard weights and optimizer across GPUs

Real systems combine all three โ€” TP within a node, PP across nodes, DP for throughput

๐Ÿ“ฆ

What's Next?

Episode 67: Apple Silicon for AI โ€” Think Macs can't do AI? Think again. Unified memory, Metal, MLX โ€” Apple Silicon has a unique architecture that makes it surprisingly competitive for inference. We'll benchmark it against NVIDIA.

โ† Previous

Ep 65: VRAM Math

Next โ†’

Ep 67: Apple Silicon for AI

Next: Episode 67 โ€” Apple Silicon for AI

A Mac Studio with M4 Ultra can run Llama 3 70B unquantized in FP16. No multi-GPU setup. No $30,000 H100. Here's why.

This is part of a 98-episode series covering AI engineering from tokens to production deployment.

โ† Previous Ep 65: VRAM Math: How to Calculate If a Model Fits