feat(trainer): MoE loss-free load balancing and block dropout#2953
Open
faresobeid wants to merge 5 commits into
Open
feat(trainer): MoE loss-free load balancing and block dropout#2953faresobeid wants to merge 5 commits into
faresobeid wants to merge 5 commits into
Conversation
46532e0 to
0b8cd33
Compare
0b8cd33 to
6e772cc
Compare
6e772cc to
3a3b78c
Compare
3a3b78c to
be5d783
Compare
be5d783 to
1ce5e9e
Compare
32b8b06 to
99b613c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 99b613c. Configure here.
Add training-time MoE load balancing and per-block dropout to the custom model implementation. MoE load balancing via [model.moe_load_balance] (mode/coeff), off by default. mode='loss_free' applies the DeepSeek auxiliary-loss-free bias update (arXiv:2408.15664) once per optimizer step: expert_bias += coeff * sign(load error), from a per-step usage accumulator (training-mode forwards only, so validation traffic is excluded), with the delta recentered to zero mean (matches torchtitan) so the bias vector doesn't drift a global offset. Expert usage is aggregated across the dp_cp group so balancing targets the whole global batch. Default coeff 1e-3. get_model forces the router expert_bias buffer on when loss_free is requested (several models gate it behind a None-default load_balance_coeff), and raises if a model can't provide one. model.dropout applies dropout at each block's output before the residual add (attention + FFN/MoE), intended for SFT/self-distillation (e.g. 0.15); default 0.0 so RL is unaffected. Covers the shared attention/MLP/MoE layers plus the Laguna gated attention and the Laguna/Qwen3.5 decoder-level shared experts. SFT validation switches to eval mode when dropout or loss_free is active so val/loss stays deterministic and validation doesn't skew expert-usage counts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
99b613c to
7554c6e
Compare
samsja
reviewed
Jul 6, 2026
Signed-off-by: faresobeid <111092724+faresobeid@users.noreply.github.com>
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
Adds training-time MoE load balancing and per-block dropout to prime-rl's custom model implementation. Both are opt-in and off by default.
MoE load balancing
New
[model.moe_load_balance]config (mode=off|loss_free,coeff), wired into both SFT and RL. Before this,load_balance_coeffonly allocated the routerexpert_biasbuffer (loaded from checkpoints and frozen) — there was no active balancing mechanism during training. (torchtitan implements this same path as an optimizer step-pre-hook; prime-rl never wired it up.)loss_free— DeepSeek auxiliary-loss-freeexpert_biasupdate (arXiv:2408.15664), applied once per optimizer step:expert_bias += coeff · sign(load_error), from a dedicated per-step usage accumulator. Details:dp_cpgroup so balancing targets the whole global batch. Defaultcoeff = 1e-3.get_modelforces theexpert_biasbuffer to exist whenloss_freeis requested (several models defaultload_balance_coeff=None), and raises a clear error if a model can't provide one (e.g. MiniMax withuse_routing_bias=False) rather than silently no-op'ing.Block dropout
model.dropout(default0.0) applies dropout at each block's output before the residual add — attention block and FFN/MoE block — set via aset_block_dropoutwalker. Covers all model families: the shared attention/MLP/MoE layers, plus the bespoke blocks (Laguna gated attention + decoder-level shared expert; Qwen3.5-MoE gated/linear-attn mixers + shared expert; GLM-MoE-DSA sparse MLA; AFMoE attention; GPT-OSS attention + MoE; NemotronH Mamba). Intended for SFT/self-distillation (e.g.0.15); wired into the SFT trainer only.SFT validation switches the model to
eval()when dropout or loss-free balancing is active, soval/lossis deterministic and validation forwards don't skew the load-balance counts. With both off (the default), the model stays in train mode (notorch.compilerecompilation).Files
configs/trainer.py—MoELoadBalanceConfig,ModelConfig.dropouttrainer/model.py—set_block_dropout,update_expert_bias, loss-freeexpert_biasenable + validationtrainer/models/layers/{moe,mlp,attn}.py— per-step load accumulator (train-only),dropout_poutput dropouttrainer/models/laguna/…,trainer/models/qwen3_5_moe/…— dropout on bespoke attention and decoder-level shared expertstrainer/{sft,rl}/train.py— bias-update wiring; SFT dropout enable + eval-mode validationdocs/advanced.md— MoE Load Balancing + Block Dropout sectionsTesting
Unit-tested on CPU:
update_expert_biaslowers over-loaded / raises under-loaded experts, its delta sums to zero, and the update is bit-identical for 1× vs 2× (AC-doubled) counts; dropout is a no-op in eval / atp=0; config surface validates (mode∈ {off, loss_free},coeffdefault1e-3).ruff check+ruff format --checkclean. Not yet exercised in a live distributed run.🤖 Generated with Claude Code
Note
Medium Risk
Changes MoE routing via mutable
expert_biasand touches many model forward paths; misconfiguration could skew expert usage, though features are off by default and unsupported models fail at load time.Overview
Adds opt-in MoE load balancing (
[model.moe_load_balance],loss_free) and per-block dropout (model.dropout) for the custom model stack, with docs and trainer wiring.Loss-free balancing runs once per optimizer step in SFT and RL:
update_expert_biasnudges routerexpert_biasfrom a train-onlyexpert_load_acccounter, all-reduced overdp_cp, with a zero-mean delta. MoE layers gainmoe_lb_active/expert_load_acc;get_modelforcesexpert_biasallocation and errors if the architecture has no bias buffer.Block dropout applies
F.dropouton attention/MLP/MoE outputs before residuals across shared layers and bespoke blocks (Laguna, Qwen3.5-MoE, GLM sparse MLA, AFMoE, GPT-OSS, NemotronH Mamba); SFT callsset_block_dropoutwhendropout > 0.SFT validation uses
model.eval()when dropout or load balancing is on so val loss stays deterministic and validation forwards do not feed the balance accumulator.Reviewed by Cursor Bugbot for commit 644a97e. Bugbot is set up for automated code reviews on this repo. Configure here.