Support Muon in BF16_Optimizer with FP32 gradient accumulation - #8526
Conversation
Signed-off-by: 0z5a <0z5a@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 319f913637
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| see_memory_usage('begin bf16_optimizer', force=True) | ||
| self.timers = timers | ||
| self.optimizer = init_optimizer | ||
| from deepspeed.runtime.zero.muon.muon_optimizer import MuonWithAuxAdam |
There was a problem hiding this comment.
Add the required sign-off trailer
This non-merge commit has no Signed-off-by: trailer, so it does not satisfy the repository's mandatory commit-signing requirement and may be rejected by DCO enforcement. Recreate the commit with --signoff using the configured author identity.
AGENTS.md reference: AGENTS.md:L8-L8
Useful? React with 👍 / 👎.
| @@ -0,0 +1,25 @@ | |||
| --- | |||
There was a problem hiding this comment.
Add the mandatory license header to the new tutorial
This newly added file begins directly with front matter and omits the license header required for all new files in this repository. Add the prescribed SPDX and DeepSpeed Team header without disrupting the documentation front matter.
AGENTS.md reference: AGENTS.md:L12-L16
Useful? React with 👍 / 👎.
| padding_start = max(0, min(partition_size, offset - start)) | ||
| partition.grad[padding_start:].zero_() | ||
| staged[padding_start:].zero_() | ||
| staged_momenta.append((committed, staged)) |
There was a problem hiding this comment.
Avoid retaining every staged momentum partition
When an optimizer has multiple Muon parameter groups, each group's full local FP32 momentum clone is appended here and retained until after optimizer.step(). Consequently, the staging peak is proportional to the sum of all local Muon partitions—not the largest group as documented—and can add an entire FP32 model shard in common per-layer or per-rate groupings, causing otherwise viable large-model runs to OOM.
Useful? React with 👍 / 👎.
| # These equal matrices land on exact DP partition boundaries. | ||
| assert len(calls) == 2 // deepspeed.comm.get_world_size() |
There was a problem hiding this comment.
Validate updates for matrices split across partitions
At world size two, the two 32×32 matrices deliberately end exactly at partition boundaries, so this test never exercises the newly added left/right slicing for a matrix owned by multiple ranks. Counting private kernel calls and checking that some weight changed would still pass if the wrong cross-rank slice were copied; use irregular matrix sizes and compare complete weights and momentum against an independently derived Muon step.
AGENTS.md reference: AGENTS.md:L30-L33
Useful? React with 👍 / 👎.
|
Hi @0z5a , all_gather_into_tensor fetches the full group momentum, but each rank only needs the slices of matrices it owns part of. In _prepare_muon_updates(), every rank all-gathers the entire group's momentum, including matrices it owns none of. What each rank actually needs is only the cross-partition slices of matrices its partition intersects. A single dist.all_to_all_single with precomputed send/recv split tables (layout is static, computed once in init) delivers exactly that, still as one fused collective: comm volume drops from ~full group momentum per rank to just the cross-boundary matrix slices; |
Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
53911b8 to
6006dc2
Compare
|
Thanks for the suggestion. I updated the implementation in 6006dc2 to avoid gathering the full momentum buffer. The BF16 Muon path now precomputes static send/receive split tables and uses a single I also extended the distributed test with irregular matrix shapes that cross the partition boundary and compare the complete weights and gathered momentum against an independent full-matrix reference. In addition, I ran a real 2-GPU BF16 ZeRO-1 training job for 5 optimizer steps with mixed Muon/Adam parameter groups and three microbatches per step. The weights matched the reference exactly at every step (maximum error 0.0), and the gathered momentum matched exactly as well. The full test file passes with 10 tests. |
| @@ -0,0 +1,25 @@ | |||
| --- | |||
| title: "Muon with BF16 weights and FP32 gradient accumulation" | |||
There was a problem hiding this comment.
We don't need a seperate tutorial for muon+bf16. Also should not explain internals in tutorial. Can we remove this file?
Signed-off-by: 0z5a <dezhen.lu@student.uni-tuebingen.de>
|
@0z5a can you take a look at test failure? Thanks! |
ok, i will see tomorrow. |
Compiler fusion can round BF16 intermediates differently for standalone matrices and partition views. Keep the full-matrix oracle and optimizer step eager for the exact weight and momentum comparisons. Signed-off-by: 0z5a <0z5a@users.noreply.github.com>
|
@delock , tried to fix again, PTAL. |
|
@0z5a let me investigate sandbox in another context, can you revert sandbox timeout change? Thanks! |
4e4b8b5 to
86c3993
Compare
|
Reverted — thanks @delock. |
BF16 weights with FP32 gradient accumulation and ZeRO stage 1 select
BF16_Optimizer. Muon currently refuses that configuration because this wrapper hands the optimizer flat partitions without first applying Newton–Schulz. This change computes Muon updates on the original matrices after gradient reduction and global clipping, then copies only each rank's owned intersections into the optimizer update.Momentum remains FP32 and partitioned like the master weights. The implementation gathers one group's momentum as temporary workspace, stages local momentum until the optimizer step, and excludes alignment padding. Auxiliary Adam groups retain their existing update path. The initial support boundary is dense data parallelism with two-dimensional Muon matrices; model-parallel MPU, expert groups and graph harvesting remain rejected. This adds communication and temporary memory proportional to the largest Muon group; it is a correctness change, with no performance claim.
Validation on two NVIDIA L20 GPUs (PyTorch 2.13.0+cu130):
atol=1e-4, rtol=1e-3; checkpoint replay remains exactThe compiled comparison is a same-input per-step check. Independently evolving BF16 trajectories can diverge after a rounding difference; these results do not establish bitwise compiled equivalence.
Repository regression command:
This addresses the missing orthogonalization in
BF16_Optimizer. It is separate from #8483's ZeRO-1/2 gradient/momentum dtype reconciliation and #7748's checkpoint dtype conversion.Fixes #8461.