6.1.9Scaling & Efficient Architectures

FSDP and sharded training

2,284 words10 min readdifficulty · medium

What FSDP Actually Does

Fully Sharded Data Parallel is a memory optimization strategy that shards (partitions) three key components across data-parallel workers:

  1. Model parameters (θ\theta)
  2. Gradients (θL\nabla_\theta \mathcal{L})
  3. Optimizer states (momentum, variance for Adam)

Traditional data paralelism keeps full copies of all three on every device. FSDP keeps only 1N\frac{1}{N} of each on each of NN devices.

How FSDP Works: The Three-Phase Protocol

Phase 1: Forward Pass

Before each layer's computation:

  1. Device ii holds shard θl(i)\theta_l^{(i)} for layer ll
  2. All-gather operation: collect {θl(0),θl(1),,θl(N1)}\{\theta_l^{(0)}, \theta_l^{(1)}, \ldots, \theta_l^{(N-1)}\} from all devices
  3. Reconstruct full θl\theta_l temporarily in device memory
  4. Compute layer's forward pass: hl+1=fl(hl,θl)h_{l+1} = f_l(h_l, \theta_l)
  5. Discard borrowed shards, keep only θl(i)\theta_l^{(i)}

Why this step? Each layer needs all its parameters to compute activations correctly. We can't split a matrix multiply y=Wxy = Wx if we only have half of WW.

Phase 2: Backward Pass

For each layer in reverse:

  1. All-gather θl\theta_l again (needed for gradient computation)
  2. Compute local gradients: Lθl\frac{\partial \mathcal{L}}{\partial \theta_l}
  3. Reduce-scatter gradients: each device gets only θl(i)\nabla_{\theta_l^{(i)}} (its shard's gradient)
  4. Discard full θl\theta_l again

Why reduce-scatter? After computing the full gradient, we sum contributions across devices (reduce) and distribute chunks (scatter) so each device updates only its shard.

Phase 3: Optimizer Step

Each device independently updates its shard: θl(i)θl(i)ηAdam(θl(i),ml(i),vl(i))\theta_l^{(i)} \leftarrow \theta_l^{(i)} - \eta \cdot \text{Adam}(\nabla_{\theta_l^{(i)}}, m_l^{(i)}, v_l^{(i)})

Optimizer states (m,v)(m, v) are also sharded, so each device stores only 1N\frac{1}{N} of the momentum/variance bufers.

Communication Primitives

FSDP relies on two collective operations:

Comparison with ZeRO

FSDP is PyTorch's implementation of ZeRO (Zero Redundancy Optimizer) from Microsoft DepSpeed:

  • ZeRO Stage 1: Shard optimizer states only → 4×4\times memory reduction
  • ZeRO Stage 2: Shard optimizer states + gradients → 8×8\times memory reduction
  • ZeRO Stage 3: Shard optimizer states + gradients + parameters → N×N\times memory reduction (FSDP = ZeRO-3)

Why three stages? Each stage introduces more communication overhead. ZeRO-1 is faster for moderate models; ZeRO-3 is necessary only when models exceed single-GPU memory.

Hybrid Sharding Strategies

Modern frameworks allow hybrid paralelism:

FSDP + Pipeline Parallelism:

  • Partition model into stages (layers 1-12 on GPU group A, layers 13-24 on GPU group B)
  • Within each stage, shard with FSDP
  • Benefit: Reduce all-gather scope to intra-stage devices

FSDP + Tensor Paralelism:

  • Split large layers (e.g., 12,288 × 12,288 weight matrix) across GPUs within a node
  • Shard parameters across nodes with FSDP
  • Benefit: Tensor parallelism for computation, FSDP for memory

Formula for effective parallelism: Total GPUs=Ndata×Npipeline×Ntensor\text{Total GPUs} = N_{\text{data}} \times N_{\text{pipeline}} \times N_{\text{tensor}}

Implementation Details

Wrapping granularity: FSDP can wrap individual layers, modules, or the entire model. Finer wrapping reduces temporary memory (smaller all-gather buffers) but increases communication frequency.

Typical strategy:

model = TransformerModel(...)
for layer in model.transformer_layers:
    layer = FSDP(layer)  # Wrap each transformer block
model = FSDP(model)  # Outer wrap for top-level

Mixed precision: FSDP stores shards in fp32 (for optimizer) but communicates in fp16 (for bandwidth). All-gather converts fp32 → fp16 before sending.

CPU offloading: Some FSDP implementations allow offloading inactive shards to CPU RAM, trading PCIe bandwidth for GPU memory. Rarely used due to severe latency penalties.

Recall Explain to a 12-Year-Old

Imagine you and 7 friends are building a huge LEGO castle (the AI model). The castle is so big that one person can't hold all the pieces at once.

Normal way (data parallel): Each of you has a complete copy of all pieces. You each build the same castle 8 times. This wastes a lot of space!

FSDP way: You divide the pieces into 8 boxes. You hold box1, your friend holds box 2, etc. When you need to build the tower (which needs pieces from all boxes), everyone quickly passes their boxes around the circle so you can grab the pieces you need. After building the tower, you give the extra boxes back.

Why does this help? You only need to store1/8 of the pieces permanently. The passing-around takes a bit of time, but it's way better than neding 8× the shelf space. For really massive AI models (like ChatGPT's big brother), this "sharing pieces" trick is the only way to build them without buying impossibly expensive computers.

Connections

  • Data Paralelism — FSDP extends data parallelism with sharding
  • Model Parallelism — FSDP is orthogonal; can combine both
  • Mixed Precision Training — FSDP leverages fp16 communication, fp32 computation
  • Gradient Accumulation — Accumulate over microbatches to reduce per-step communication
  • Activation Checkpointing — Essential complement to FSDP for activation memory
  • ZeRO Optimizer — FSDP implements ZeRO-3 from DepSpeed
  • Communication Collectives — All-gather, reduce-scatter are FSDP's primitives
  • Pipeline Parallelism — Hybrid: pipeline + FSDP within stages

#flashcards/ai-ml

What are the three components FSDP shards across devices? :: Model parameters, gradients, and optimizer states (momentum, variance).

What collective operation does FSDP use to reconstruct full parameters forward pass?
All-gather (each device broadcasts its shard to all others).
What is the memory reduction factor for ZeRO-3/FSDP with N devices?
Approximately N× reduction for persistent memory (parameters + gradients + optimizer states).
Why does FSDP discard borrowed parameter shards after each layer?
To minimize peak memory usage—keeping full parameters would negate the sharding benefit.
What is the difference between ZeRO-2 and ZeRO-3?
ZeRO-2 shards optimizer states + gradients. ZeRO-3 additionally shards model parameters.
When should you NOT use FSDP?
When the model fits in GPU memory with standard data parallelism, because FSDP's communication overhead reduces throughput.
What memory component does FSDP not shard?
Activations (they remain per-device and scale with batch size).
What is the communication cost of all-gather for a shard of size S on N devices?
N1N×S\frac{N-1}{N} \times S per device (each device receives N-1 shards from others).
What technique complements FSDP to handle activation memory?
Activation checkpointing (recompute activations during backward instead of storing).
In hybrid FSDP + pipeline parallelism, what does FSDP shard?
Parameters/gradients/optimizer states within each pipeline stage (not across stages).

Concept Map

too costly for large models

uses

shards

enables

kept as 1 over N per device

needed for

forward uses

backward uses

produces shard gradient

feeds

discard borrowed shards

Data Parallel replicates full model

FSDP Fully Sharded Data Parallel

Sharding partition tensor across N devices

Shards params grads optimizer states

All-gather reconstruct full layer

Forward pass compute activations

Reduce-scatter distribute gradient chunks

Backward pass compute gradients

Optimizer step update local shard

Memory per device 24P over N

Hinglish (regional understanding)

Intuition Hinglish mein samjho

FSDP matlab Fully Sharded Data Parallel ek aisi technique hai jo bahut bade AI models ko train karne ke liye use hoti hai. Samjho ki tumhare paas ek bohot bada model hai, jaise GPT-3 with 175 billion parameters—isko ek GPU me fit karna impossible hai kyunki itna memory hi nahi hota. Traditional data parallelism me har GPU pe pora model copy hota hai, lekin FSDP me har GPU sirf apna assigned "shard" (piece) rakhta hai.

Jab forward pass chalti hai, toh har GPU temporarily dosre GPUs se unke shards mang leta hai (all-gather operation), puri layer compute karta hai, aur fir extra shards ko discard kar deta hai—sirf apna piece rakhta hai. Backward pass me same chez hoti hai: gradients compute hone ke bad, har GPU sirf apne shard ka gradient rakhta hai (reduce-scatter operation). Isse memory usage N GPUs ke sath N times kam ho jata hai—matlab 64 GPUs use karke tum 64× bada model train kar sakte ho bina memory overflow ke.

Lekin ek tradeoff hai: FSDP me communication overhead badh jata hai kyunki har layer ke liye all-gather aur reduce-scatter operations hote hain. Agar tumhara model already GPU me fit ho raha hai, toh FSDP use karna actually slower ho sakta hai. Isliye FSDP ko tab use karo jab model ka size GPU memory sezyada ho—warna normal data parallelism hi better rehta hai. Activation memory bhi separately handle karni padti hai activation checkpointing se, kyunki FSDP sirf parameters, gradients, aur optimizer states ko shard karta hai, activations ko nahi.

Go deeper — visual, from zero

Test yourself — Scaling & Efficient Architectures

Connections