Return a copy from OnebitLamb.get_lamb_coeffs - #8227
Conversation
step() starts by doing `del self.lamb_coeffs[:]` to drop the previous step's stats, and get_lamb_coeffs handed back that same list object. A caller who reads the coefficients to log them keeps a reference that the next step() empties in place, so the snapshot silently becomes [] rather than the values that were read. FusedLamb has the same pair of methods and is not affected, because its accessor builds a new list. Return a copy here so both optimizers behave the same way. Signed-off-by: Vineeth Sai <vineethsai4444@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f9bf6fcd8
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return self.lamb_coeffs | ||
| # step() clears lamb_coeffs in place before recomputing them, so hand back | ||
| # a copy or the next step() empties the list the caller is holding. | ||
| return list(self.lamb_coeffs) |
There was a problem hiding this comment.
Add the missing Signed-off-by trailer
This reviewed commit is a non-merge commit with one parent, but its commit message has no Signed-off-by: trailer; the repository requires every non-merge commit to include one, so the DCO/custom CI check will reject this change until the commit is amended with --signoff.
AGENTS.md reference: AGENTS.md:L8-L8
Useful? React with 👍 / 👎.
Problem
OnebitLamb.step()opens by dropping the previous step's stats in place:and
get_lamb_coeffs()handed back that same list object:So a caller who reads the coefficients (to log them, or to watch the trust ratios during warmup) is holding the optimizer's own list, and the next
step()empties it under them. The snapshot silently becomes[]instead of the values that were read.Running the two accessors as they exist today, with the one
step()statement that touches the list:FusedLambhas the identicaldel self.lamb_coeffs[:]in itsstep()and the identical accessor name, and is not affected only because its version builds a new list on the way out. So the two optimizers disagree today about whether the value they hand you survives the next step.Fix
Return a copy, so both optimizers behave the same way:
One thing I deliberately did not change
FusedLamb.get_lamb_coeffsreturns Python floats ([c.item() for c in self.lamb_coeffs]) while this one returns the tensors. Making them match would mean changing the element type this method has always returned, which is a separate call from fixing the aliasing, so I left it alone rather than folding a behaviour change into a bug fix. Happy to align it here or in a follow-up if you would rather the two accessors were identical.Test
test_onebit_lamb_get_lamb_coeffs_returns_a_copyintests/unit/runtime/half_precision/onebit/test_onebit.py. It needs no accelerator and no distributed backend: the accessor is pure Python, and sinceOnebitLamb.__init__asserts on an initialized backend, the test builds the instance with__new__and gives it only the attribute the accessor reads. It sits with the other 1-bit Lamb tests rather than in a new file, and it runs incpu-torch-latestsince that job runs all ofunit/and this module has no accelerator-level skip.Fails before the change (
step() emptied the list returned to the caller) and passes after.Checks
pre-commit run --files deepspeed/runtime/fp16/onebit/lamb.py tests/unit/runtime/half_precision/onebit/test_onebit.pyis clean, including yapf, flake8, check-torchdist, check-license and codespell. Commit is signed off.