Repository navigation
perf(moe): pin the GC replay's NF4 expert stacks by default above a size floor - #2095
Open
TanishGudise wants to merge 1 commit into
Open
TanishGudise wants to merge 1 commit into
TanishGudise wants to merge 1 commit into
Conversation
…ult above a size floor Under gradient checkpointing a frozen NF4 stack is dequantized three times per layer per step. The replay pin (UNSLOTH_MOE_GC_REPLAY_PIN, opt-in since unslothai#1331) lets the backward reuse the replay's stack. Turn it on by default for stacks of at least _REPLAY_PIN_MIN_BYTES (512 MiB) that fit (_momentary_pin_fits), so tiny MoEs (stacks under 512 MiB) keep the recompute; unslothai#1331 measured +12% peak memory with no step-time gain on a tiny MoE. UNSLOTH_MOE_GC_REPLAY_PIN=1 keeps the previous opt-in (no floor), =0 turns the pin off, and UNSLOTH_MOE_RECOMPUTE still overrides both. Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Summary
Under gradient checkpointing, a frozen NF4 expert stack is dequantized three times per layer per step: in the forward, in the checkpoint replay, and again in the backward. The replay pin (
UNSLOTH_MOE_GC_REPLAY_PIN, opt-in since #1331) lets the backward reuse the replay's stack. This PR turns it on by default for stacks of at least_REPLAY_PIN_MIN_BYTES(512 MiB) that fit (_momentary_pin_fits, unchanged).UNSLOTH_MOE_GC_REPLAY_PIN=1(ortrue/on/yes) keeps the previous opt-in: no size floor.UNSLOTH_MOE_GC_REPLAY_PIN=0(orfalse/off/no) turns the pin off.UNSLOTH_MOE_RECOMPUTEstill overrides both ways, and everything outside a replay is unchanged.The floor is checked per decision, against the stack that decision is about:
forward_native_grouped_mm(which the dispatcher falls back to when it declines, and which other callers such as the sonic fallback reach directly) checks each projection alone. At the default only stacks of at least 512 MiB pin there. On Qwen3-30B-A3B the gate_up stack (768 MiB) can pin and the down stack (384 MiB) recomputes. On gemma-4-26B the down stack (484 MiB) also stays under the floor.Why revisit the opt-in, and what the floor does and doesn't cover
#1331 kept this off by default because it raised training peak memory (1.744 to 1.961 GiB on a tiny NF4 MoE, 23.7 to 24.0 GiB on gemma-4-26B) and the step-time gain did not reproduce on a quiet GPU.
test_gc_recompute_pass_recomputes_for_4bit_by_defaultkeeps passing unchanged, because its stacks are far below the floor.Performance
unsloth/Qwen3-30B-A3Bloaded byFastLanguageModelwithload_in_4bit=True(3-D nested NF4 expert stacks, blocksize 64), LoRA r=16,use_gradient_checkpointing="unsloth",adamw_8bit, bf16, fixed 2048-token wikitext-2 sequences with the same data order and learning-rate schedule in every run. Three fresh processes per arm, alternating default / pin. Tokens/s over the steady steps (first 10 steps and the 2 profiled steps excluded); intervals are 95% t-intervals over the three runs, and the speedup interval is on the per-pair log ratio. torch 2.14.1+cu130, Triton 3.8.0, bitsandbytes 0.50.2, transformers 5.17.0, unsloth @ df4b4a5a83, unsloth_zoo @ ca97c8c. The pin arm setsUNSLOTH_MOE_GC_REPLAY_PIN=1, which takes the same dispatcher path this PR takes by default for these stacks (gate_up 768 MiB, above the floor). The end-to-end runs were not repeated on this branch.Numerics
Per layer, the pin is bit-identical to recompute. The check, on an RTX A5000 with this branch: a Qwen3-30B-A3B-shaped experts layer (random NF4 gate_up and down stacks of 128 experts, expert LoRA r=16), forward + backward inside the gradient-checkpoint replay marker, at 4,096 and 16,384 tokens, through both
forward_moe_backend_bnb4bit(the pathFastLanguageModeltakes) andforward_native_grouped_mm, with the pin arm at the new default (variable unset) and at=1.=1; the recompute run did not take it.End-to-end losses still vary run to run in both arms. Maximum per-step |difference| over all steps:
Validation
tests/test_moe_bnb4bit_adaptive_recompute.pygives 1 failed and 19 passed on main (8b50cc4); the failure is the new default-pin test,['provider'] != ['swap']. With this PR it gives 20 passed. The five other MoE test files (test_moe_recompute_gc_adaptive.py,test_moe_bnb4bit_selective_dequant.py,test_moe_sonic_dispatch_fallback.py,test_moe_selective_dequant_backward_view.py,test_moe_nf4_grouped.py): 103 passed, 1 skipped on both. The full suite was not run._momentary_pin_fitsreturned True above and False below in all 8 cases.Params4bit), and gradient checkpointing modes other than"unsloth".Happy to keep it opt-in if you prefer; the data is here either way.
AI disclosure: I used Claude while writing this change and its tests; I reviewed every line, ran the tests on a rented GPU, and can answer questions about any of it.