Repository navigation
Conversation
Reuse FP32 gradients directly when no scaling is needed and requantize Adam's variance before reusing its dequantized buffer as the denominator. This avoids full-size transient allocations while preserving bitwise results. AI assistance (Cursor) was used for this change. Co-authored-by: Cursor <cursoragent@cursor.com>
Author
|
Closing this, as I'm focusing my contributions elsewhere. Sorry for the noise. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The CPU blockwise 8-bit optimizer update creates several full-size FP32 temporaries on every step. In particular,
g.float() * 1.0copies an already-FP32 gradient, and Adam/LAMB build a separate denominator from the dequantized variance. For large parameters, these allocations substantially increase step latency and peak memory.Cause
The CPU implementation used allocation-producing expressions even when the input already had the required dtype and scale. It also retained the updated FP32 variance while materializing another full-size denominator, although the variance only needs to be requantized before the parameter update.
Change
Benchmark
Environment: Intel Xeon Platinum 8352Y, one pinned CPU core,
OMP_NUM_THREADS=1,MKL_NUM_THREADS=1, Python 3.11.18, PyTorch 2.15.0+cpu, native Release CPU backend.Workload: one 20,000,000-element FP32 parameter with
Adam8bit, one warmup step followed by seven timed steps. Each result below is the median of per-process medians from three fresh processes.Parameter and optimizer-state hashes were bitwise identical in all six benchmark processes.
A separate baseline comparison covered Adam, LAMB, Momentum, LARS, Lion, RMSprop, Adagrad, and AdEMAMix with FP32, FP16, and BF16 parameters for five steps each. All 24 configurations produced bitwise-identical parameters and optimizer states. A
gnorm_scale=0.25case was also bitwise identical and left the input gradient unchanged.Tests
BNB_TEST_DEVICE=cpu python -m pytest tests/test_optim.py -q -k 'test_optimizer8bit and adam8bit_blockwise'— 9 passedtest_optimizer8bitcases for Lion, Momentum, RMSprop, AdEMAMix, and scheduled AdEMAMix across FP32, FP16, and BF16 — 15 passedpre-commit run --all-files— passedNot run: accelerator tests or the full test suite. The changed implementation is CPU-only, and the repository guidance asks for targeted tests.
AI assistance (Cursor) was used for this change.