Muon is silently disabled under ZeRO-3 when the model is built with zero.Init - #8438
Muon is silently disabled under ZeRO-3 when the model is built with zero.Init#8438alanhuangyoo wants to merge 2 commits into
Conversation
zero.Init replaces a partitioned parameter's data with a flat placeholder and records the layer's shape as ds_shape, so param.shape is 1-D for every parameter in the model. The width check then confirms nothing and the flag raises on a model whose layout it could read perfectly well. Same root cause as deepspeedai#8438, which fixes the use_muon test on master; this applies it to the tagger's shape reads as well. Signed-off-by: alanhuangyoo <alanhuangyoo@gmail.com>
|
Note on the red check: the Three other branches of mine hit the same timeout today while four went green, so it is the runner rather than this tree. I cannot re-run it myself; any maintainer re-running the job should be enough. |
|
Ran this together with the other two Muon fixes I have open (#8440, #8442) on a real Llama, since all three touch optimizer setup and I wanted to know they compose. Merged onto master they apply cleanly, and: 14 Muon matrices over 4 steps is 56 orthogonalizations, which is the right count, and the two weight decays are the ones the caller asked for rather than the config's. The
The full Muon suite on the merged tree is running; I will post the number when it finishes. |
|
The merged-tree number I promised: 190 passed in 28:51. That is Re-ran it after #8442 changed shape (it now implements the stage-0 Newton-Schulz rather than refusing the configuration), so the number covers the current state of all three. |
deepspeed.zero.Init replaces a partitioned parameter's data with a flat placeholder - torch.Size([0]) on ranks that do not hold it - and records the shape it has as a layer in ds_shape. set_optimizer_flags tests p.ndim >= 2 because Muon is defined on matrices, so under zero.Init every parameter in the model looks 1-D, none are tagged, ZeRO-3 finds no sub-group using Muon, and training continues with every parameter on the AdamW branch. Nothing reports it. Measured on a 2-layer Llama, ZeRO-3, Muon: without zero.Init 14 parameters tagged and muon_update called 84 times over 6 steps; with zero.Init 0 and 0. After this change the two agree. zero.Init is how models that do not fit on one device are built, so this is the configuration ZeRO-3 exists for. Signed-off-by: alanhuangyoo <alanhuangyoo@gmail.com>
|
Rebased onto current master (4 commits since this branch was cut) — no conflicts, and it re-triggers the CI job that was cancelled at the 1h30m timeout on the previous run, so the red check should resolve on its own. 5 passed on the rebased branch; yapf and flake8 clean. |
64a2c7e to
ee385e1
Compare
Muon is silently inactive under ZeRO-3 whenever the model is built with
deepspeed.zero.Init. Training runs, the loss falls, and every parameter is on the AdamW branch.What happens
set_optimizer_flagsdecidesuse_muonper parameter:The test is right — Muon is defined on matrices — but
p.shapeis not the layer's shape underzero.Init. ZeRO-3 replaces a partitioned parameter's data with a flat placeholder and records the shape it has as a layer inds_shape:So every parameter in the model reports as 1-D, none are tagged, and
stage3.py'sfinds no sub-group using Muon.
muon_updateis never reached.Measurement
2-layer Llama, ZeRO-3,
{"optimizer": {"type": "Muon"}},muon_updatewrapped with a counter, 6 steps. Only the model construction differs between the two rows:use_muonmuon_updatecallszero.InitWith this change the second row reads 14 and 84, and the loss falls over the 6 steps (4.8924 -> 4.1229).
zero.Initis how a model that does not fit on one device is built, which is the case ZeRO-3 exists for, so this is not an edge configuration.The change
Read the shape the parameter has as a layer —
ds_shapewhen ZeRO-3 has recorded one,shapeotherwise — the same thing_shape_before_zero3_partitioninmodule_inject/layers.pyalready does for AutoTP. Nothing else changes: the rank test and theembed/lm_headexclusions are unchanged, and a genuine 1-D parameter is still excluded becauseds_shapeis read for its rank rather than assumed to be a matrix.Tests
tests/unit/runtime/zero/test_muon_use_muon_under_zero_init.py, 5 cases. Three are CPU-only and build the ZeRO-3 shape directly (a flat placeholder plusds_shape): matrices are tagged unpartitioned, matrices are still tagged once partitioned, and a partitioned vector is not promoted. Two run a realzero.Initanddeepspeed.initializeunder ZeRO-3 and assertmuon_updateis reached.On master,
test_muon_update_is_called[True]fails withand
test_matrices_are_still_tagged_once_zero3_has_partitioned_themfails too; the other three pass on both sides, which is what pins that nothing widened. 5 passed with the change. yapf and flake8 clean.