Deprecate sparse_gradients - #8504
Conversation
Remove the `sparse_gradients` flag Tracking: deepspeedai#8489 Signed-off-by: pengdurice <pengduhit@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0bb2a5916f
ℹ️ 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".
| "quantize_training": | ||
| "Mixture-of-Quantization (MoQ) / 'quantize_training' has been removed. See " | ||
| f"{_REMOVED_FEATURES_ISSUE}.", | ||
| "sparse_gradients": |
There was a problem hiding this comment.
Add the required commit sign-off
This is a non-merge commit, but its message contains no Signed-off-by trailer, so it does not satisfy the repository's mandatory DCO/CI requirement. Add the author identity using --signoff before merging.
AGENTS.md reference: AGENTS.md:L8-L8
Useful? React with 👍 / 👎.
Remove the
sparse_gradientsflagTracking: #8489
Summary
sparse_gradientsconfig flag, which compressed densetorch.nn.Embedding/EmbeddingBaggradients into DeepSpeed's sparse reduction path._REMOVED_TOP_LEVEL_CONFIG_KEYSso a leftoversparse_gradientsentry raisesDeepSpeedConfigErrorinstead of being silently ignored.sparse_tensor_module_namesbookkeeping and its checkpoint field, which existedonly to serve that flag.
What the flag did, and why it goes
The flag's entire contribution was the dense-input branch of
SparseTensor.__init__:It selected rows whose values sum to something non-zero, so a row like
[1.0, -1.0]was discarded as empty even though it carries a real gradient. That silently dropped updates.
config-json.mdhas described the feature as "essentially deprecated as we don't see usecases for it as much anymore" since #1418 (Sept 2021), and
deepspeed/runtime/zero/contains nosparse handling at all, so the flag never worked together with ZeRO.
What is deliberately NOT removed
Sparse gradient reduction still works at ZeRO stage 0. A model that builds
torch.nn.Embedding(..., sparse=True)itself produces a natively sparse gradient, and thatstill reaches the full DeepSpeed sparse path.
Byte-identical in this PR:
split_half_float_double_sparsesparse_allreduce,sparse_allreduce_bucket,sparse_all_gatherif grad_data.is_sparse:guard and theSparseTensor(param.grad)call itselfSimplified, but behavior-preserving for a sparse gradient:
sparse_allreduce_no_retaindrops anelsebranch that densified and copied back. ASparseTensoris now only ever built from an already-sparse gradient, sois_sparseisalways true and that branch was unreachable.
SparseTensor.__init__drops its dense-input branch in favor of an assertion, andto_dense()goes with it, since that removedelsebranch was its only caller.Both remaining sparse tests are kept and still cover that path. They already built
EmbeddingBag(..., sparse=True), so the only change to them is dropping the now-rejected"sparse_gradients": trueline from their config.The single construction site is
engine.py:Reached through
backward()orstep()→allreduce_gradients()→buffered_allreduce_fallback()→_get_gradients_for_reduction(). All of the gates inallreduce_gradientsmust pass, which in practice means: DeepCompile inactive, ZeRO stage 0,and a gradient accumulation boundary. ZeRO stages 1, 2, and 3 all divert to the ZeRO optimizer
before that line.
Open question for review. Because it only works at ZeRO stage 0, that whole path is a
candidate for deprecation too. Doing so would remove
sparse_tensor.py,split_half_float_double_sparse, the foursparse_allreduce*methods,sparse_all_gather,and the two remaining sparse tests. This PR deliberately leaves that decision open rather
than bundling it.
Three
SparseTensormembers now have no caller anywhere:add(),sparse_size(), andtype(). They are independent of the removed flag and are left for a separate dead-code pass.Behavior changes
"sparse_gradients": truecompressed dense embedding gradientsDeepSpeedConfigError"sparse_gradients": falseparsed and did nothingDeepSpeedConfigErrorEmbedding(sparse=True)reduced sparsely at ZeRO stage 0sparse_tensor_module_namesfieldPresence of the key raises regardless of its value, matching how #8490 treats
mics_hierarchical_params_gather, also a boolean whose default isFalse.A checkpoint written by an older release still loads. Its leftover
sparse_tensor_module_nameskey is no longer recognized, so it now appears in theclient_statereturned byload_checkpointrather than being filtered out.Test plan
Run with
slurm_scripts/test_deprecate_sparse_gradients.slurm(1 node, 2 GPUs). The jobasserts that the branch under test is the tree actually imported before running anything.
tests/unit/runtime/test_ds_config_dict.py— the newtest_sparse_gradients_config_is_rejected, plus the four existing removed-key testsas a regression check on
config.pytests/unit/runtime/sparse_tensor/— sparse reduction at ZeRO stage 0 still correctwith the config key gone
tests/unit/checkpoint/test_latest_checkpoint.py,tests/unit/checkpoint/test_lr_scheduler.py— cover the editedtests/unit/checkpoint/common.pyhelperDiffstat
Two deleted test files asserted only on removed members:
test_sparse.pyonsparse_tensor_module_names, andtest_csr.pyon the dense constructor andto_dense().