Drop the documented grad_hooks ZeRO option, which does not exist - #8242
Drop the documented grad_hooks ZeRO option, which does not exist#8242vineethsaivs wants to merge 1 commit into
Conversation
ebarkhordar
left a comment
There was a problem hiding this comment.
The central claim holds, and the history makes it stronger than the body puts it. grad_hooks was not removed at some point, it was never wired up. cfa63f5da ("ZeRO stage 1 refresh", #1042) added the doc entry and zero_grad_hooks() in the same commit, and added the field to neither the ZeRO config nor the constants module:
$ git show cfa63f5da:deepspeed/runtime/zero/config.py | grep -i grad_hook # no output
$ git show cfa63f5da:deepspeed/runtime/zero/constants.py | grep -i grad_hook # no output
$ git show cfa63f5da -- deepspeed/runtime/engine.py docs/_pages/config-json.md | grep grad_hooks
+ def zero_grad_hooks(self):
+ return self._config.zero_config.grad_hooks
+<i>**grad_hooks**</i>: [boolean]
Naming that commit in the body would answer the "did we break this, and should we restore it instead" question up front.
The dead-accessor claim holds too. An ast sweep over every .py in the master tree finds zero_grad_hooks exactly once, its own definition at deepspeed/runtime/engine.py:1290, and .grad_hooks exactly once, on the line inside it. Removing it cannot break a caller, since any call raises AttributeError: 'DeepSpeedZeroConfig' object has no attribute 'grad_hooks' today.
I ran your new guard, because CI has not. On this head sha cpu-torch-latest, Formatting, python, nv-pre-compile-ops and DCO / required are all sitting at action_required, so modal-torch-latest is the only leg that has executed. In a clean python:3.11-slim container with torch 2.13.0+cpu and pydantic 2.13.4:
$ python -m pytest tests/unit/runtime/zero/test_zero_config.py -q
7 passed
It also bites, which is the part worth knowing: re-adding the grad_hooks doc block and rerunning gives AssertionError: documented but not accepted by DeepSpeedZeroConfig: ['grad_hooks']. Your parser finds 22 keys against its floor of 15, and the six stage3_* entries among them are accepted through their pydantic aliases rather than as declared fields, so filtering on extra_forbidden is the right call there.
For scope, not a request: the drift runs both ways. 28 fields DeepSpeedZeroConfig declares have no entry in that doc section, zenflow, leaf_module, sub_group_size and mics_shard_size among them. This PR guards the direction that actually breaks users, which seems like the right half to take on here.
tohtana
left a comment
There was a problem hiding this comment.
Hi @vineethsaivs,
Thank you for this PR! It is good to remove grad_hooks.
The test could be useful to prevent regressions, but it's a bit fragile and can cause false failures. I think this type of validation shouldn't run in CI. Would it be okay to remove the test?
config-json.md documents grad_hooks as a ZeRO option with a default of True, but
DeepSpeedZeroConfig has no such field and DeepSpeedConfigModel sets
extra="forbid", so following the docs is a hard failure:
DeepSpeedZeroConfig(**{"stage": 1, "grad_hooks": False})
pydantic_core._pydantic_core.ValidationError: 1 validation error
grad_hooks
Extra inputs are not permitted
The option was never wired up rather than removed later. cfa63f5 ("ZeRO stage 1
refresh", deepspeedai#1042) added the doc entry and DeepSpeedEngine.zero_grad_hooks() in the
same commit without ever adding the field to the config or to the constants
module, and it is absent from deepspeed/runtime/zero/config.py in every release
back to v0.3.0. So there is nothing to restore, and zero_grad_hooks() reads
zero_config.grad_hooks, which can only raise AttributeError. Nothing in the
package or the tests calls it.
Remove the doc entry and the dead accessor.
Signed-off-by: Vineeth Sai <vineethsai4444@gmail.com>
6eefc91 to
0449b34
Compare
|
Thanks @tohtana, that is a fair call and the test is gone. Pushed as You are right about the fragility. The guard parsed The PR is now a two file deletion: the doc entry and @ebarkhordar, thank you for finding Both of your verification notes match what I get, including the |
Problem
config-json.mddocumentsgrad_hooksas a ZeRO option with a default ofTrue:DeepSpeedZeroConfighas no such field, andDeepSpeedConfigModelsetsextra="forbid", so anyone who follows the docs gets a hard failure out ofdeepspeed.initialize:The option was never wired up rather than removed later, so there is nothing to restore.
cfa63f5da("ZeRO stage 1 refresh", #1042, thanks @ebarkhordar for pinning it down) added the doc entry andDeepSpeedEngine.zero_grad_hooks()in the same commit and never added the field todeepspeed/runtime/zero/config.pyor to the ZeRO constants module. It is absent from both in every release back to v0.3.0.zero_grad_hooks()readsself._config.zero_config.grad_hooks, which can only raiseAttributeError, and nothing in the package or the tests calls it.Fix
Remove the doc entry and the dead accessor. If the intent is that the option should exist, that is a feature rather than a fix and I would rather leave it to you than invent a semantic for it.
Test
No test. An earlier revision of this PR added a guard to
tests/unit/runtime/zero/test_zero_config.pythat checked every ZeRO keyconfig-json.mddocuments is oneDeepSpeedZeroConfigaccepts. @tohtana asked for it to be dropped as too fragile for CI, which is fair, so it is gone and this is now a two file deletion.What was checked instead, on CPU:
ValidationErrorabove reproduces onmasterand the doc entry is what invites it.astsweep over every.pyin the tree findszero_grad_hooksexactly once, its own definition atdeepspeed/runtime/engine.py:1290, and.grad_hooksexactly once, on the line inside it. Removing it cannot break a caller, since any call raisesAttributeErrortoday.python -m pytest tests/unit/runtime/zero/test_zero_config.pygives 6 passed before and after, unchanged, and that file is now untouched by this PR.yapf --style .style.yapfandflake8 --config .flake8are clean ondeepspeed/runtime/engine.py, and clean on the unmodified tree as a control.How it was found
Cross-checking every
<i>**key**</i>inconfig-json.mdagainst agrepfor that literal indeepspeed/. Of 126 documented keys only two came back unreferenced:Compression, which is a section name, and this one.For scope rather than as a request: the drift runs the other way too, with 28 fields
DeepSpeedZeroConfigdeclares having no entry in that doc section. That direction misleads rather than crashes, so it is left alone here.