Skip to content

Make AdEMAMix32bit inherit AdEMAMix so it allocates the double state buffer - #2076

Open
caiotheodoro wants to merge 1 commit into
bitsandbytes-foundation:mainfrom
caiotheodoro:ademamix32bit-double-buffer
Open

Make AdEMAMix32bit inherit AdEMAMix so it allocates the double state buffer#2076
caiotheodoro wants to merge 1 commit into
bitsandbytes-foundation:mainfrom
caiotheodoro:ademamix32bit-double-buffer

Conversation

@caiotheodoro

Copy link
Copy Markdown

Fixes #2075.

AdEMAMix32bit and PagedAdEMAMix32bit subclassed Optimizer2State directly, so state1 was allocated as p.shape instead of (2, *p.shape) and the t_alpha/t_beta3 scheduler in AdEMAMix.update_step never ran. On the CPU and default backends the first step() raised RuntimeError: output with shape [] doesn't match the broadcast shape [4096]. This re-parents AdEMAMix32bit onto AdEMAMix with optim_bits=32, mirroring AdEMAMix8bit. PagedAdEMAMix32bit inherits the change. The constructor signature and defaults are unchanged.

New test test_ademamix32bit_matches_ademamix steps both classes next to AdEMAMix(optim_bits=32) for 5 steps, scheduled and unscheduled, and asserts state1.shape == (2, 4096) plus equal state1, state2 and parameters. On main it fails 6 of 6 with the RuntimeError above. On this branch 6 pass and 2 skip (paged on CPU, following the existing convention in test_optimizer32bit).

Checks run on macOS arm64 (CPU build plus MPS), torch 2.14.0, Python 3.13.12:

  • pytest tests/test_optim.py -k ademamix -n 4: 32 failed, 90 passed, 26 skipped on this branch; 32 failed, 84 passed, 24 skipped on main. The 32 failures are the same MPS-only cases on both trees (optimizer_update_8bit_blockwise and paged buffers are not implemented on MPS).
  • 180 CPU configurations (5 AdEMAMix classes x fp32/fp16/bf16 x 3 shapes x scheduler on/off x weight_decay 0/0.01, 5 steps each) compared against _ReferenceAdEMAMix on main and on this branch. The 72 AdEMAMix32bit and PagedAdEMAMix32bit cases go from RuntimeError to parameters bit-identical with AdEMAMix(optim_bits=32). The other 108 cases produce identical bytes on both trees.
  • pre-commit run --all-files: all hooks pass.

I could not run the CUDA kernel. kOptimizer32bit2State loads m2 from state1[n + i], so on CUDA the old single-size buffer was read past its end.

Drafted with Claude Opus / Fable 5.1. Reviewed by Muse Spark 1.3 and GLM 5.3 as judges before submission.

…buffer

AdEMAMix32bit and PagedAdEMAMix32bit subclassed Optimizer2State directly,
so they never used AdEMAMix.init_state and allocated state1 with the shape
of the parameter instead of (2, *p.shape). The ademamix kernels read m2
from the second half of state1, so on the CPU and default backends the
first step raised RuntimeError, and the t_alpha/t_beta3 schedulers were
silently ignored. Subclass AdEMAMix with optim_bits=32, mirroring
AdEMAMix8bit, and add a test comparing both classes against
AdEMAMix(optim_bits=32).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AdEMAMix32bit and PagedAdEMAMix32bit allocate a single-size state1 and fail on the first step

1 participant