AI Infra Interviews logo
Distributed Training & Parallelism / 05
mediumNewMetaMicrosoftDatabricks

FSDP or DeepSpeed ZeRO-3: which would you pick for a new training codebase today, and why?

Same algorithm, two implementations, one of which now lives inside PyTorch and composes with everything else there. The differences that decide it in 2026: per-parameter sharding, DTensor, torch.compile, and the two features DeepSpeed still owns outright.

Updated Sep 2026 · Grounded in real AI infrastructure interview loops and written to a senior-engineer editorial bar, with every number worked and every diagram hand-built.

TL;DR: Both are ZeRO stage 3: shard weights, gradients and optimizer state across data-parallel ranks, all-gather weights per layer, reduce-scatter gradients. The choice is about surfaces, not math. FSDP2 shards each parameter on dimension 0 as a DTensor, which composes with tensor parallelism, context parallelism, torch.compile and distributed checkpointing without wrappers; it is the default for a new PyTorch codebase. DeepSpeed still wins when you need ZeRO-Offload or ZeRO-Infinity to train on GPUs too small for the sharded state, or when an existing config-driven stack already runs on it.

How to approach it

Neutralize the false framing first: they implement the same algorithm, and any memory or throughput argument at the level of "ZeRO-3 vs FSDP" is really about buffer management and prefetch, which are tunable in both. Then compare the surfaces: how a model is wrapped, how parameters are represented, what else composes with each, and how checkpoints are written. Give the default recommendation and the two conditions that override it. If the interviewer works at a company with an existing stack, ask which one it is before recommending a migration.

A strong answer

A typical situation: a team is starting a 30B pretraining codebase on 256 H100s and has engineers who have used both. The static training state is 30e9 × 16 B = 480 GB, so full sharding is required either way; at n = 256 that is 1.9 GB per rank plus activations, and either library handles it. The decision is about what the codebase will need next year.

What FSDP2 changed. FSDP1 flattened every parameter in a wrapped module into one contiguous FlatParameter and sharded that buffer. It worked, but the flat parameter hid the individual tensors, so anything that wanted to look at a parameter (a custom optimizer, a per-layer learning rate, a quantization hook, a tensor-parallel sharding) had to work around it. FSDP2 (fully_shard in torch.distributed.fsdp) shards each parameter on its own dimension 0 and represents the shard as a DTensor with a device mesh and a placement. The consequences are the ones the choice turns on:

  • Tensor parallelism and context parallelism compose by adding mesh dimensions, so a 2D or 3D layout is one DeviceMesh with FSDP on one axis and TP on another, no second library.
  • torch.compile traces through it, because there is no runtime flattening to break the graph.
  • Distributed checkpointing writes DTensors natively and reshards on load to a different world size.
  • Mixed precision is per parameter group, so an fp8 or bf16 policy can differ across layers.
  • Memory is slightly higher than FSDP1 at the same settings, because per-parameter all-gathers are less contiguous; in practice it is inside noise once prefetch is on.

What DeepSpeed offers. ZeRO-3 with a JSON config that turns on sharding, prefetch bucket sizes, activation checkpointing, and communication settings without touching the model code. ZeRO++ adds quantized weight all-gathers (int8 or fp8 on the wire) and hierarchical partitioning that keeps a secondary copy of weights inside each node, so the cross-node all-gather traffic drops by up to 4×. ZeRO-Offload moves optimizer state to host memory, and ZeRO-Infinity moves it to NVMe, which lets a 70B fine-tune run on a single node at a fraction of the throughput. DeepSpeed-MoE and its inference engine are separate tools that share the config surface.

The per-step traffic is the same in both by construction:

ZeRO-3 / FSDP traffic per rank per step, model of N params in bf16 (2 B):
  forward  all-gather of weights:      (n−1)/n × 2N bytes
  backward all-gather of weights:      (n−1)/n × 2N bytes
  backward reduce-scatter of grads:    (n−1)/n × 2N bytes
  total ≈ 3 × 2N = 6N bytes per rank (for large n)

for N = 30e9: 6 × 30e9 = 180 GB per rank per step
  at 50 GB/s per NIC: 3.6 s
compute per rank per step at 16k tokens per rank:
  6 × 30e9 × 16,384 ÷ (989e12 × 0.4) ≈ 7.4 s

sanity: communication is half the compute time, so prefetch has to hide it; that is the same
        problem in either library, and both hide it with one-layer-ahead all-gathers.

ZeRO++'s hierarchical partitioning is the one implementation feature that changes this number: with a node-local secondary copy, the cross-node all-gathers are replaced by intra-node ones over NVLink and the NIC only carries the reduce-scatter. FSDP2's equivalent is hybrid sharding (HSDP), which shards within a group and replicates across groups; it reduces cross-group traffic to an all-reduce of gradients at the cost of replicating weights per group, which is a different trade with the same intent.

Decision axisFSDP2DeepSpeed ZeRO-3
Parameter representationper-parameter DTensor on a meshpartitioned flat buffers, gathered on demand
Composes with TP / CP / compilenatively, same meshvia Megatron-DeepSpeed or custom code
Checkpoint reshardingtorch.distributed.checkpointuniversal checkpoint converter
Quantized all-gathernot built inZeRO++
CPU / NVMe offloadCPU offload for params and optimizerZeRO-Offload, ZeRO-Infinity, more mature
Config surfacePythonJSON plus launcher flags

Decision: FSDP2 for a new PyTorch codebase, because a pretraining stack acquires tensor parallelism, context parallelism, compile and distributed checkpointing within a year, and FSDP2 gives all of them on one device mesh. The conditions that reverse it: the run needs offload to fit on hardware that cannot hold the sharded state even at maximum n, or the organization already operates a DeepSpeed or Megatron-DeepSpeed stack with the operational knowledge that comes with it, in which case the migration cost is real and the technical gap is small.

SAME ALGORITHM, DIFFERENT NEIGHBOURS composes with TP, CP, DTensor, torch.compile FSDP2 in PyTorch its own stack, its own pipeline and MoE support DeepSpeed ZeRO-3 separate Start new work on FSDP2 and leave running jobs where they are: a migration for 4% is not free. Check what the checkpoint format costs in a migration. That is usually the real blocker.

The reversal condition: an existing DeepSpeed codebase with working pipeline and MoE support and no appetite for a migration. Both implement the same algorithm, so the choice is operational, and ZeRO and FSDP covers what they share. TORCH_LOGS on the first run is where a misconfigured shard shows up. Model Memory Footprint is where the per-rank arithmetic comes from.

What interviewers probe next

  • "Which one is faster?" Neither, at equal tuning; measured differences of 5 to 10% in either direction come from prefetch and bucket settings, and a candidate who quotes a benchmark without saying the settings has not run one.
  • "How do you get tensor parallelism with DeepSpeed?" Megatron-DeepSpeed, which pairs Megatron's TP and PP with ZeRO for the data-parallel axis; the coupling is at the code level rather than the mesh level.
  • "What does hybrid sharding buy?" At n = 512, full sharding all-gathers over 511 remote ranks per layer; HSDP with groups of 8 all-gathers over NVLink and all-reduces gradients across the 64 groups, which moves the heavy traffic onto the fast link at the cost of 8× replicated weights.
  • "How does FSDP2 handle a parameter that must not be sharded?" fully_shard accepts an ignored_params set, and a DTensor placement of Replicate() on the FSDP mesh dimension does the same at the tensor level.

Common mistakes

  • Arguing memory: "ZeRO-3 uses less memory than FSDP". The static state is 16 B/param divided by n in both; differences are in transient buffers and are settings.
  • Not knowing FSDP2 exists and describing FSDP1's flat parameters and auto_wrap_policy as the current design.
  • Recommending a migration off a working DeepSpeed stack for a fine-tuning team that will never add tensor parallelism.
  • Forgetting offload as DeepSpeed's remaining differentiator.

Key takeaways

  • Same algorithm: shard all three states, all-gather weights per layer twice per step, reduce-scatter gradients once; about 6N bytes per rank per step.
  • FSDP2 shards per parameter as DTensors on a device mesh, which is why TP, CP, compile and checkpoint resharding compose with it.
  • DeepSpeed keeps ZeRO++ quantized collectives and Offload/Infinity as its distinct features.
  • New PyTorch codebase: FSDP2. Existing DeepSpeed stack or a need for offload: stay.
That one was free — and so are 10 answers per topic without an account. Signing in doubles that to 20, opens the Plus lessons in the courses, and remembers which topics you keep getting wrong.no card · Google sign-in · nothing to cancel
HOW DID IT GO?
0
READING SIGNED OUT

Signing in doubles your free answers, from 10 to 20 per topic, and the site starts remembering you: mastery per topic, bookmarks, and a next-focus recommendation. Free, no card.

Sign in free

The concepts behind this question

Ranked by how closely each one overlaps this question's topic, so the first card is the thing to read if the answer above moved too fast.

Core
🕸️ Distributed TrainingSign in
ZeRO and FSDPZeRO and FSDP keep data parallelism's simple programming model but shard the optimizer state, gradients and parameters across ranks, cutting per-GPU memory from 16 bytes per parameter toward 16/N. The price is 1.5x DDP's communication and a dependence on tokens per GPU that decides when sharding stops paying and tensor parallelism takes over.
Foundational
🕸️ Distributed Training
Data Parallelism and DDPData parallelism gives every GPU a full copy of the model, feeds each a different slice of the batch, and averages the gradients with an all-reduce so every replica takes the same optimizer step. It is the first parallelism every training job uses, and the tokens-per-GPU arithmetic behind it decides whether the communication hides behind the backward pass or dominates the step.
Advanced
Kernels & Compilers🔒 Premium
torch.compile and CUDA Graphstorch.compile captures Python into a graph with Dynamo, fuses it into Triton kernels with Inductor, and can wrap the result in a CUDA graph so a whole forward pass is one launch. CUDA graphs are what make batch-1 decode fast in every serving engine, and graph breaks, recompiles and static-shape rules are what make both bite in production. Interviewers ask when compile helps, when it hurts, and how you would know.
Advanced
🧮 Napkin Math & Capacity🔒 Premium
Communication Volume EstimatesEvery parallelism strategy is a promise to move a certain number of bytes between GPUs every step, and the fabric either affords it or it does not. This page derives the per-rank volume for data parallelism, ZeRO/FSDP, tensor parallelism, pipeline parallelism and expert parallelism, works each for a 70B model at 8 and 64 ranks, and turns the bytes into seconds on NVLink and on a 400 Gb/s NIC. The result is the rule that decides every 3D layout: per-layer traffic stays on NVLink, per-step traffic can cross the fabric.
UP NEXT ON YOUR JOURNEY
FEDITOR'S NOTE

Scored on saying the algorithm is the same before arguing about the implementation, on knowing what FSDP2 changed (per-parameter DTensor sharding, no flat parameter), and on naming the cases where DeepSpeed still wins.

DISCUSSION · 0

No comments yet — be the first to share your approach.