FSDP and sharded training
What FSDP Actually Does
Fully Sharded Data Parallel is a memory optimization strategy that shards (partitions) three key components across data-parallel workers:
- Model parameters ()
- Gradients ()
- Optimizer states (momentum, variance for Adam)
Traditional data paralelism keeps full copies of all three on every device. FSDP keeps only of each on each of devices.
How FSDP Works: The Three-Phase Protocol
Phase 1: Forward Pass
Before each layer's computation:
- Device holds shard for layer
- All-gather operation: collect from all devices
- Reconstruct full temporarily in device memory
- Compute layer's forward pass:
- Discard borrowed shards, keep only
Why this step? Each layer needs all its parameters to compute activations correctly. We can't split a matrix multiply if we only have half of .
Phase 2: Backward Pass
For each layer in reverse:
- All-gather again (needed for gradient computation)
- Compute local gradients:
- Reduce-scatter gradients: each device gets only (its shard's gradient)
- Discard full 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:
Optimizer states are also sharded, so each device stores only 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 → memory reduction
- ZeRO Stage 2: Shard optimizer states + gradients → memory reduction
- ZeRO Stage 3: Shard optimizer states + gradients + parameters → 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:
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-levelMixed 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?
What is the memory reduction factor for ZeRO-3/FSDP with N devices?
Why does FSDP discard borrowed parameter shards after each layer?
What is the difference between ZeRO-2 and ZeRO-3?
When should you NOT use FSDP?
What memory component does FSDP not shard?
What is the communication cost of all-gather for a shard of size S on N devices?
What technique complements FSDP to handle activation memory?
In hybrid FSDP + pipeline parallelism, what does FSDP shard?
Concept Map
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.