Read DeepSpeed from its engine boundary through ZeRO state ownership, layer-time gathers, CPU and NVMe offload, pipeline limits, checkpoint recovery, governance, and source code.
Personalize this lesson
Adapt explanations and teaching visuals to your background and preferred voice.
A model can fit in GPU memory for inference and still fail before its first training step. Training also keeps gradients, optimizer moments, master weights, and activations. For mixed-precision Adam, model states alone can consume roughly eight times the low-precision parameter file.
DeepSpeed turns those copies into explicit ownership decisions. Its best-known mechanism, ZeRO (Zero Redundancy Optimizer), partitions optimizer state, gradients, and eventually parameters across data-parallel ranks. The model's math stays the same; where each tensor lives and when it moves change.[1]
Ordinary PyTorch code owns the model, optimizer, backward call, gradient synchronization, and step. deepspeed.initialize(...) wraps that stack in a DeepSpeedEngine. The engine tracks microsteps, accumulation boundaries, distributed groups, precision, gradient reduction, optimizer stepping, monitoring, and checkpoints.[2][3]
The user-facing loop stays small:
1engine, optimizer, dataloader, scheduler = deepspeed.initialize(
2 model=model,
3 model_parameters=model.parameters(),
4 training_data=dataset,
5 config="ds_config.json",
6)
7
8loss = engine(batch)
9engine.backward(loss)
10engine.step()That compact API hides a serious contract. DeepSpeed must know global batch arithmetic, gradient-accumulation boundaries, data-parallel groups, parameter ownership, precision, and checkpoint layout. A wrong config can preserve execution while silently changing effective batch size, update frequency, or throughput.
💡 Key insight: DeepSpeed is an execution engine, not a memory-only switch. It owns enough of the training step to reschedule state and communication. That control makes config review and checkpoint testing necessary.
Let be parameter count. A common mixed-precision Adam setup keeps low-precision parameters and gradients plus three FP32 arrays: master weights, first moment , and second moment .
| Model state | Typical bytes per parameter | Why it exists |
|---|---|---|
| FP16 or BF16 parameter | 2 | Forward and backward compute |
| FP16 or BF16 gradient | 2 | Backward result before update |
| FP32 master parameter | 4 | Stable optimizer update |
| FP32 first moment | 4 | Adam momentum estimate |
| FP32 second moment | 4 | Adam variance estimate |
| Total before activations | 16 | Replicated model state under plain data parallelism |
This estimate is a planning model, not a universal allocator receipt. Optimizer implementation, gradient dtype, flat buffers, fragmentation, temporary gathers, and quantized states can change it. Activations, attention workspaces, and CUDA runtime memory sit outside the table.
For four data-parallel ranks, the idealized per-rank state becomes:
At stage 1, parameters and gradients remain replicated, costing , while of optimizer and master state is sharded. Stage 2 also partitions the gradient block. The third stage shards every listed state. Temporary buffers and live layers make observed peaks higher.
The following copy-runnable estimator makes rank count and parameter count easy to change. It reports decimal gigabytes and leaves activation memory out on purpose.
1parameters = 1_000_000_000
2data_parallel_ranks = 4
3
4bytes_per_param = {
5 "DDP": 16,
6 "ZeRO-1": 4 + 12 / data_parallel_ranks,
7 "ZeRO-2": 2 + 14 / data_parallel_ranks,
8 "ZeRO-3": 16 / data_parallel_ranks,
9}
10
11for name, value in bytes_per_param.items():
12 memory_gb = parameters * value / 1e9
13 print(f"{name:7s} {memory_gb:4.1f} GB per rank before activations")1DDP 16.0 GB per rank before activations
2ZeRO-1 7.0 GB per rank before activations
3ZeRO-2 5.5 GB per rank before activations
4ZeRO-3 4.0 GB per rank before activationsEach stage adds one partitioned state type. Higher isn't automatically better. Choose the lowest stage that fits while meeting throughput and recovery targets.[4]
| Stage | Partitioned across data ranks | What remains replicated | Main new cost |
|---|---|---|---|
| ZeRO-1 | Optimizer states and master weights | Parameters and gradients | Sharded optimizer bookkeeping |
| ZeRO-2 | Optimizer states and gradients | Parameters | Reduce-scatter and gradient partition flow |
| ZeRO-3 | Optimizer states, gradients, parameters | Current gathered working set | Parameter all-gathers, prefetch, release, harder checkpoints |
Stage 1 is useful when Adam state dominates memory and full weights still fit. The second stage often gives a strong fine-tuning balance because parameters stay resident while gradients and optimizer state shard. Move to stage 3 when even replicated parameters are too large.
The original DeepSpeed ZeRO tutorial demonstrates a 1.5-billion-parameter GPT-2-style model on eight 32 GB V100 GPUs. It reports 18 GB of Adam state, then reduces that block to 2.25 GB per device with ZeRO-1 by partitioning it eight ways.[4] Treat those numbers as one documented setup, not a multiplier for newer hardware or every optimizer.
A DeepSpeed JSON file selects precision, batch decomposition, optimizer, and ZeRO behavior. For a four-rank run, the configuration below uses BF16 and ZeRO-2.
1{
2 "train_batch_size": 64,
3 "train_micro_batch_size_per_gpu": 2,
4 "gradient_accumulation_steps": 8,
5 "bf16": { "enabled": true },
6 "zero_optimization": {
7 "stage": 2,
8 "contiguous_gradients": true,
9 "overlap_comm": true,
10 "reduce_scatter": true,
11 "reduce_bucket_size": 200000000
12 },
13 "optimizer": {
14 "type": "AdamW",
15 "params": {
16 "lr": 0.00002,
17 "betas": [0.9, 0.999],
18 "eps": 1e-8,
19 "weight_decay": 0.01
20 }
21 }
22}The global batch identity is:
is samples per GPU per microstep, is accumulation steps, and is data-parallel ranks. If the launch uses eight ranks without changing another term, global batch doubles. Learning-rate and schedule assumptions may then be wrong even though training runs.
Bucket size controls another tradeoff. Small buckets start communication early but increase launch overhead. Large buckets use links efficiently but need more temporary memory and may finish too late to hide under backward compute. Measure exposed communication in a timeline rather than copying a round number from another model.
ZeRO-3 stores a parameter shard on each rank during steady state. Before a module computes, ranks all-gather that module's parameter shards into a full working copy. After the module no longer needs the full weights, DeepSpeed can release them and return to shards.[4]
Backward produces gradients for the gathered layer. Reduce-scatter combines those gradients and leaves each rank with the shard it owns. Each rank updates its local optimizer and parameter shard, so no rank needs every Adam moment.
Prefetch and persistence settings decide how aggressively DeepSpeed overlaps future gathers and keeps small or frequently reused parameters resident. Too little prefetch exposes communication. Too much prefetch recreates the memory spike sharding was meant to avoid.
Stage 3 expects every rank to gather parameters in compatible order. Dynamic control flow, tied weights, or modules whose parameters are accessed outside their own forward() can break that assumption. DeepSpeed provides mechanisms such as external-parameter registration and leaf-module configuration for these cases.[4]
A useful debugging reduction disables dynamic branches and runs the smallest deterministic batch. Compare loss and parameter updates against an unsharded baseline. Restore model features one at a time after the gather order is stable.
ZeRO-Offload moves optimizer state and optimizer computation toward host CPU memory. ZeRO-Infinity extends the hierarchy so parameters and optimizer state can use CPU memory or NVMe with staging and overlap.[5][6]
The configuration can look small:
1{
2 "zero_optimization": {
3 "stage": 3,
4 "offload_optimizer": {
5 "device": "cpu",
6 "pin_memory": true
7 },
8 "offload_param": {
9 "device": "nvme",
10 "nvme_path": "/local_nvme/deepspeed"
11 }
12 }
13}The performance model isn't small. A step may wait on GPU-to-CPU DMA, CPU Adam work, pinned-memory pressure, NVMe queue depth, filesystem contention, or NUMA placement. Offload can make a model fit while reducing tokens per second enough to miss the training deadline.
Treat the memory hierarchy as a pipeline:
| Tier | Capacity | Relative speed | What to measure |
|---|---|---|---|
| GPU HBM | Smallest | Fastest | Peak allocated and reserved bytes |
| CPU memory | Larger | Slower path over PCIe or coherent link | Transfer overlap, pinning, NUMA locality |
| Local NVMe | Largest | Storage latency and bandwidth | Read/write throughput, queue depth, free space |
⚠️ Common mistake: “Fits” isn't a throughput result. Record step time, tokens per second, exposed transfer time, CPU utilization, and storage bandwidth after every offload change.
DeepSpeed decides which data-parallel group owns a shard, when a bucket is ready, and whether communication should overlap. NCCL executes the GPU collectives on NVIDIA systems. The two projects solve adjacent layers.
ZeRO-2 commonly replaces one replicated gradient all-reduce result with reduce-scatter ownership. ZeRO-3 adds parameter all-gathers around module execution. ZeRO++ adds communication-oriented options such as quantized weight exchange, hierarchical partition groups, and quantized gradients to reduce pressure on slower links.[4]
If a stage change hurts throughput, inspect both sides. DeepSpeed logs and profiler traces show bucket timing and overlap. NCCL traces and network counters show algorithm, route, and achieved communication. Tuning only one layer can misdiagnose a topology problem as a bucket problem.
ZeRO is the center of gravity, but the repository contains more systems:
| Area | Source or API | Job |
|---|---|---|
| Training engine | deepspeed/runtime/engine.py | Wrap model, optimizer, backward, step, batches, monitoring |
| ZeRO-1 and ZeRO-2 | runtime/zero/stage_1_and_2.py | Gradient and optimizer partitions |
| ZeRO-3 | runtime/zero/stage3.py, partition_parameters.py | Parameter gathers, release, gradient shards |
| Offload | runtime/swap_tensor/, ops/aio/, CPU Adam | Move and update state outside HBM |
| Pipeline parallelism | runtime/pipe/ | Partition layers and schedule microbatches |
| Tensor parallelism | module_inject/, AutoTP paths | Replace compatible modules with tensor-parallel forms |
| Expert parallelism | moe/ | MoE groups, experts, routing support |
| Inference | inference/ | Inference engine, kernels, tensor-parallel injection |
| Profiling and monitoring | profiling/, monitor/ | FLOPs, timing, and metric integrations |
DeepSpeed's built-in PipelineEngine is not a promise that every ZeRO stage composes with every pipeline setup. In the pinned snapshot, it rejects ZeRO-2 and ZeRO-3 for that engine path. Separate Megatron-DeepSpeed integrations and other runtimes have different composition contracts.[3]
Feature matrices need source and version context. “DeepSpeed supports pipeline plus ZeRO” is too broad to choose a runtime path. Ask which engine, model wrapper, ZeRO stage, checkpoint format, and tested release combination is involved.
Start at deepspeed/__init__.py. initialize(...) selects the communication backend, initializes distributed state, parses config, and returns the engine plus wrapped optimizer, data loader, and scheduler.[3]
Then follow the selected stage:
runtime/zero/stage_1_and_2.py flattens groups, creates partitions, registers gradient handling, and coordinates reductions.runtime/zero/stage3.py builds sharded optimizer state while partition_parameters.py manages parameter status, gathers, and repartitioning.runtime/swap_tensor/, asynchronous I/O operators, and CPU optimizer code expose the slower memory tier.runtime/pipe/engine.py owns stage IDs, neighbors, microbatches, and pipeline-specific reduction scheduling.The source map prevents a common reading mistake. DeepSpeedEngine.step() isn't where every optimization lives. It delegates to optimizer wrappers, communication layers, hooks, swap engines, and checkpoint utilities selected at initialization.
A ZeRO checkpoint is distributed training state, not automatically one portable model file. Each rank can write shards of parameters, optimizer state, scheduler state, and metadata. World size and parallel layout affect how those shards are interpreted.
DeepSpeed's ZeRO tutorial documents zero_to_fp32.py and get_fp32_state_dict_from_zero_checkpoint for consolidating ZeRO checkpoints.[4] Universal Checkpointing targets resume across different parallel configurations by converting state into a topology-independent form.[7]
Test four paths before a long run:
A directory existing isn't enough. Checkpoint success means the resumed job produces the expected next update and the exported model matches a reference output within the chosen precision tolerance.
These systems overlap, but their default centers differ.
| System | Center of gravity | Strong fit | Main integration cost |
|---|---|---|---|
| DeepSpeed | Config-driven training engine and optimization suite | ZeRO stages, offload, broad training features | Engine ownership, config surface, version combinations |
| PyTorch FSDP | PyTorch-native parameter sharding wrapper | Teams staying inside PyTorch APIs and distributed checkpointing | Wrap policy, state-dict modes, reshard timing |
| Megatron Core | Model-parallel transformer building blocks | TP, PP, CP, EP, specialized large-model schedules | Model architecture and rank-mesh complexity |
FSDP and ZeRO-3 share a core idea: parameters, gradients, and optimizer state can remain sharded until computation needs them. API boundaries, scheduling, checkpoint formats, mixed-precision policies, and ecosystem integration differ.
Megatron can be paired with distributed optimizer or sharding choices and DeepSpeed-based integrations. Don't select by project logo. Select from model shape, network topology, framework ownership, checkpoint requirements, team expertise, and measured end-to-end throughput.
Begin with a small unsharded reference on fixed data. Record loss, gradient norm, optimizer step, global batch, precision, and a checkpoint round trip. That reference tells you whether a later failure changed math or only systems behavior.
Add one mechanism at a time:
| Step | Change | Evidence to record |
|---|---|---|
| 1 | Plain distributed data parallel | Loss parity and baseline tokens/sec |
| 2 | ZeRO-1 or ZeRO-2 | Per-rank state memory and collective timeline |
| 3 | Overlap and bucket tuning | Exposed communication, peak temporary memory |
| 4 | ZeRO-3 | Parameter gather cadence and live working set |
| 5 | CPU offload | Transfer time, CPU optimizer time, NUMA placement |
| 6 | NVMe offload | Storage bandwidth, queueing, free-space guard |
| 7 | Checkpoint conversion | Restore parity and portable export |
For a hang, find the earliest rank error before reading peer timeout stacks. Loss divergence calls for one-update comparison with identical data and math. Throughput drops need a step-time split across compute, collectives, CPU work, I/O, and idle gaps.
Useful questions stay concrete:
DeepSpeed began in Microsoft Research and was part of Microsoft's AI at Scale work. The current project lives in the deepspeedai/DeepSpeed organization and uses a Technical Steering Committee (TSC) under AI & Data, a directed fund of The Linux Foundation.[8]
The pinned committer roster shows a cross-organization group rather than one company team:[9]
| Committer | Affiliation listed in roster |
|---|---|
| Olatunji Ruwase | Snowflake |
| Logan Adams | Microsoft |
| Masahiro Tanaka | Anyscale |
| Jeff Rasley | Snowflake |
| Minjia Zhang | UIUC |
| Ashwin Aji | AMD |
| Sam Foreman | Argonne National Laboratory |
| Zhipeng Wang | |
| Guokai Ma | Intel |
The TSC can add or remove committers and governs technical direction. Public contributions use Developer Certificate of Origin sign-off. DeepSpeed code uses Apache License 2.0; project governance places documentation under Creative Commons Attribution 4.0.[8][10]
DeepSpeed grew through a sequence of systems papers rather than one isolated algorithm.
| Work | Core contribution | Operational lesson |
|---|---|---|
| ZeRO (SC 2020) | Partition redundant optimizer state, gradients, and parameters | Three ownership stages and memory formulas |
| DeepSpeed tutorial (KDD 2020) | System stack for large-model training | Engine-level combination of memory, communication, and parallelism |
| ZeRO-Offload (USENIX ATC 2021) | Move selected state and compute to CPU | Capacity versus host-bandwidth tradeoff |
| ZeRO-Infinity (SC 2021) | Extend offload across heterogeneous memory | GPU, CPU, and NVMe working-set pipeline |
ZeRO names the partitioning family.[1] The KDD tutorial describes DeepSpeed as a broader system of training optimizations.[11] ZeRO-Offload and ZeRO-Infinity push ownership beyond GPU memory, which is why modern DeepSpeed tuning includes DMA and storage measurements alongside GPU kernels.[5][6]
Research results establish that a design can work under reported conditions. A production decision still needs your model, network, optimizer, precision, sequence length, checkpoint cadence, and failure policy.
DeepSpeed's strengths are practical:
Its weaknesses come from that same breadth:
Choose DeepSpeed when its engine, ZeRO, or offload features solve a measured constraint and your team can own the integration. A smaller native stack can be easier when the model already fits and advanced DeepSpeed features add little.
Run the estimator with your parameter count and data-parallel degree. Add measured activation peak, temporary gather buffers, and a safety margin. Predict the lowest ZeRO stage that fits.
Then run a short controlled experiment for plain DDP, your chosen ZeRO stage, and one fallback stage. Keep model, data order, optimizer, precision, and global batch fixed. Record:
Finish with one sentence: “We chose stage X because constraint Y improved by Z, while cost W stayed within limit Q.” That receipt is more useful than a copied config because it explains what the system proved.
Answer every question, then check your score. Score 75% or higher to mark this lesson complete.
8 questions remaining.
ZeRO: Memory Optimizations Toward Training Trillion Parameter Models.
Rajbhandari, S., et al. · 2020 · SC 2020
Training API
DeepSpeed Team · 2026
DeepSpeed Source Repository
DeepSpeed Contributors · 2026
ZeRO Configuration
DeepSpeed Team · 2026
ZeRO-Offload: Democratizing Billion-Scale Model Training
Ren, J., Rajbhandari, S., Aminabadi, R. Y., et al. · 2021 · USENIX ATC 2021
ZeRO-Infinity: Breaking the GPU Memory Wall for Extreme Scale Deep Learning.
Rajbhandari, S., et al. · 2021 · SC 2021
Universal Checkpointing with DeepSpeed: A Practical Guide.
DeepSpeed Team · 2026
DeepSpeed Project Charter and Governance
DeepSpeed Project · 2026
DeepSpeed TSC Committers
DeepSpeed Project · 2026
DeepSpeed Apache License 2.0
DeepSpeed Project · 2026
DeepSpeed: System Optimizations Enable Training Deep Learning Models with Over 100 Billion Parameters
Rasley, J., Rajbhandari, S., Ruwase, O., & He, Y. · 2020 · KDD 2020 Tutorial
Questions and insights from fellow learners.