Repository navigation
Conversation
Folding rejected all ZeRO offload until the per-family gradient corrections were shown to survive it. Under ZeRO-3 the corrections run before every reduce-scatter on the path shared with and without offload, and the offloaded norm uses the same folding-aware counting as the device norm, so CPU optimizer offload leaves gradients, norm and update unchanged. Accept offload_optimizer.device "cpu" with ZeRO-3. Keep rejecting optimizer offload with ZeRO-1/2 and to NVMe, parameter offload, and Muon with optimizer offload, each with a specific message. Treat device "none" as no offload. Test losses, gradients, the global norm and the clipped update against the unfolded reference, with and without offload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
0z5a
requested review from
hwchen2017,
loadams,
tjruwase and
tohtana
as code owners
October 15, 2026 13:55
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
pengdurice
approved these changes
Oct 20, 2026
pengdurice
enabled auto-merge
October 20, 2026 01:54
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
#8670 left optimizer and parameter offload rejected for AutoEP + AutoTP folding ("not validated yet ...
run a follow-up proof for per-family replica groups"). This PR provides that proof for ZeRO-3 with the
optimizer offloaded to the CPU, and accepts that configuration:
{ "zero_optimization": {"stage": 3, "offload_optimizer": {"device": "cpu"}}, "tensor_parallel": {"autotp_size": 2}, "expert_parallel": {"enabled": true, "autoep_size": 2} }Everything else stays rejected, now with a message that names the unsupported part: optimizer offload
with ZeRO stages 1 and 2, NVMe optimizer offload, parameter offload, and Muon with optimizer offload.
An explicit
"device": "none"is treated as no offload (it was rejected before).Why ZeRO-3 + CPU optimizer offload is already correct
_apply_autoep_folding_tp_correction:AVERAGE for TP-replicated parameters,
/tp_sizefor routed experts, SKIP for TP-sharded ones) inreduce_independent_p_g_buckets_and_remove_grads, before every reduce-scatter. That path is the samewith and without offload; offload only changes where the reduced partitions are stored.
complete_grad_norm_calculation_for_cpu_offload) uses the same folding-awarecounting as the device norm (
_grad_norm_counts_every_rankplus the expert-parallel all-reduce), fromper-partition norms recorded at the accumulation boundary.
The test below checks the claim end to end instead of relying on this reading.
Changes
validate_folding_global/validate_autoep_config: take the offload devices instead of"offload configured" booleans (
offload_optimizer_device,offload_param_device); accept stage 3 +"cpu"; reject the rest as above. Internal helpers; the two in-repo callers are updated.DeepSpeedEngine: passes the configured devices.gradients on its own path, which this PR does not validate (and which overlaps ongoing Muon offload work).
autoep.rst.Tests
test_autoep_autotp_folding_config.py: accepted and rejected offload combinations (replaces theblanket-rejection test; the duplicate in
test_autoep_autotp_grad_parity.pyis removed).test_autoep_autotp_sharded_attention.py, newTestFoldedZero3ClippedUpdate: reuses AutoEP + AutoTP folding under ZeRO-3 #8670'sper-gradient comparison against an unfolded ZeRO-0 reference and adds one clipped SGD step. For each
of 4 folding shapes (world 4; TP x EP = 2x2, 2x4, 4x2, 4x4),
zero.Initon/off, and offload on/off,it compares losses, every gradient, the global norm, and every parameter's update. Clipping (clip
1e-2, lr 1/clip) makes the update depend on the norm the optimizer computed, so a wrong offloaded norm
fails the test; the comparison allows one fp32 ulp of the parameter for recovering an update as
after - before, and asserts that a 0.1% error in the update is still detected.Results (on-device)
Hardware: 1 node, 4x NVIDIA H100 (64 GB, NVLink NV6 between all pairs), driver 595.91.07 (CUDA 13.2),
torch 2.12.1+cu130, NCCL 2.29.7, transformers 5.15.1, Python 3.12.1 (MareNostrum 5 ACC).
tests/)1c862f7dfpytest unit/v1/moe/test_autoep_autotp_sharded_attention.py -k TestFoldedZero3ClippedUpdatepytest unit/v1/moe/test_autoep_autotp_sharded_attention.py -k "not TestFoldedZero3ClippedUpdate"pytest unit/v1/moe/test_autoep_autotp_{bf16_folding_parity,checkpoint,deepcompile_reject,dispatch,folding_config,folding_groups,grad_parity,runtime,zero1_overlap_folding}.pypytest unit/v1/moe/test_autoep_autotp_folding_config.py(CPU)The 2 failures are
TestTiedOutputHead::test_row_parallel_tied_head_is_refused[False/True]("AutoTP sharded anoutput head whose weight is tied to the input embedding"). They fail identically on the unpatched base in
the same job, so they are pre-existing and unrelated to this change (likely AutoTP tied-head detection
with transformers 5.15.1); not addressed here. The global norms match the reference exactly, for example
folded 2.380656 vs reference 2.380656 (TP 2) and 3.552228 vs 3.552228 (TP 4).
8-rank shapes skip on the 4-GPU node. The GPU runs used base
1c862f7df; the branch is rebased onto5f266e26dwithout conflicts (the 4 commits in between touch DeepEP slicing, XPU op builders, ZeRO-2partition storage and a test footprint, none of the paths changed here).
pre-commit run --fileson thechanged files passes (yapf, flake8, codespell, check-torchdist, check-license, check-torchcuda).
Compatibility matrix
Validated: ZeRO-3 x optimizer offload {none, cpu} x
zero.Init{off, on} x fp32 x folding TP {2, 4}x EP {2, 4} (world 4), torch SGD on the offloaded CPU fp32 partitions.
Not validated (and either rejected or left unchanged): DeepSpeedCPUAdam's offloaded step (the tests run
torch SGD on the CPU fp32 partitions with
zero_force_ds_cpu_optimizer: false; DeepSpeedCPUAdam stepsthe same partitions but through its own kernel), bf16/fp16 with offload, 8-rank shapes, NVMe offload
(rejected), parameter offload (rejected), ZeRO-1/2 optimizer offload (rejected; its offloaded norm path is
being changed by #8823), Muon with offload (rejected).
Not a duplicate
No open or merged PR enables offload with AutoEP + AutoTP folding (searched "folding offload",
"AutoEP offload", "AutoTP offload"). #8823 fixes ZeRO-1/2 routed-expert clipping under folding and does not
touch ZeRO-3 or offload; ZeRO-1/2 offload is left rejected so the two do not interact. Tracked in the
Q4 roadmap #8672 (AutoEP + AutoTP folding milestone).