Repository navigation
Conversation
| # The policy loss above is scaled for gradient accumulation (HF auto-scaling is off here), so scale aux too. | ||
| if self.aux_loss_enabled: | ||
| normalizer = self.current_gradient_accumulation_steps if mode == "train" else 1.0 | ||
| loss = loss + self.router_aux_loss_coef * aux_loss / normalizer |
There was a problem hiding this comment.
DAPO aux grad-accum mismatch
Medium Severity
For cispo, dapo, and vespo, policy loss is normalized with num_items_in_batch and is not divided by current_gradient_accumulation_steps, but the MoE auxiliary term is always divided by that step count. With gradient accumulation greater than one, the router aux contribution is scaled down relative to the policy loss and no longer matches the intended router_aux_loss_coef calibration.
Reviewed by Cursor Bugbot for commit 7d97669. Configure here.
There was a problem hiding this comment.
The /grad_accum on the aux term is correct here too; it's what keeps it G-invariant like the
policy loss.
cispo/dapo/vespo skip /grad_accum on the policy loss because their normalizer num_items_in_batch is already the global accumulated-batch token count (same value on every micro-batch, Trainer auto-scaling disabled). So summing the G micro-batch losses is already G-invariant.
The aux loss is a per-micro-batch O(1) scalar, so to add it once per effective batch (not G times) it must be /G. Quick check (G=2, per-batch token-loss sum S over n items, aux A):
- single forward:
S/n + coefΒ·A - accumulated: policy
S/2n + S/2n = S/n, auxcoefΒ·A/2 + coefΒ·A/2 = coefΒ·Aβ same
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
|
|
||
| model_init_kwargs (`dict[str, Any]` or `str`, *optional*): | ||
| Keyword arguments for [`~transformers.AutoModelForCausalLM.from_pretrained`], used when instantiating the | ||
| model from a path. For MoE models, set `{"output_router_logits": True, "router_aux_loss_coef": <coef>}` here |
There was a problem hiding this comment.
not for this pr, but I think it would be nicer to have a dedicated arg. I'll open a separate pr
There was a problem hiding this comment.
Agreed, just followed the how SFTTrainer does it
There was a problem hiding this comment.
Should we wait on #6085 before merging this ?
There was a problem hiding this comment.
Agreed, just followed the how SFTTrainer does it
you did right!
Should we wait on #6085 before merging this ?
no, this one should be merged first
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
β Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fbb9ba7. Configure here.
| if self.aux_loss_enabled: | ||
| normalizer = self.current_gradient_accumulation_steps if mode == "train" else 1.0 | ||
| loss = loss + self.router_aux_loss_coef * aux_loss / normalizer | ||
| self._metrics[mode]["aux_loss"].append(self.accelerator.gather_for_metrics(aux_loss).mean().item()) |
There was a problem hiding this comment.
Missing detach on aux_loss before distributed metrics gathering
Low Severity
The aux_loss tensor participates in the computation graph (it's added to loss for backpropagation) but is passed directly to gather_for_metrics without calling .detach(). The async GRPO trainer correctly uses aux_loss.detach().to(torch.float32) before its reduce call. Passing a grad-tracking tensor through distributed communication is wasteful and inconsistent with the pattern used elsewhere in this same PR.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit fbb9ba7. Configure here.
|
Thanks for adding this @AmineDiro! A scope question: the experimental GRPO variants that override They still inherit Is that intentional for now (MoE aux loss scoped to GRPO/RLOO/AsyncGRPO), or would a follow-up PR propagating it to these variants be welcome? Happy to send one. |


What does this PR do?
Port the MoE load-balancing auxiliary loss (already supported in
SFTTrainer) toGRPOTrainer,RLOOTrainer, and the experimentalAsyncGRPOTrainer.When a model is configured with output_router_logits=True and a router_aux_loss_coef, the policy loss now gets auxilary router loss added to it, matching the model's own reference forward and
SFTTrainer. This keeps experts balanced when post-training MoE models.Enable it via model_init_kwargs, e.g.:
How it works
_compute_lossfolds it into the loss and logs aux_loss.load_balancing_loss_func from router_logits directly (same as SFT's chunked path). Adds
model_init_kwargsto AsyncGRPOConfig.aux_lossmetric is logged when enabled.Notes
with SFT.
Note
Medium Risk
Touches shared
_get_per_token_logps_and_entropiesreturn shape and training loss math across multiple RL trainers; incorrect aux scaling or MoE forward flags could affect MoE training stability, while dense models are unaffected when aux is disabled.Overview
Adds MoE router load-balancing auxiliary loss to RL trainers so post-training on mixture-of-experts models can keep expert usage balanced, aligned with existing
SFTTrainerbehavior.GRPOTrainer/RLOOTrainer:_get_per_token_logps_and_entropiesnow optionally requestsoutput_router_logitsand returns a third value,aux_loss. Init readsoutput_router_logitsandrouter_aux_loss_coeffrom the text config (VLMs viaget_text_config()), warns when logits are on but coef is 0, and_compute_lossaddsrouter_aux_loss_coef * aux_losswith scaling matched to each trainerβs grad-accum regime (GRPO divides by accumulation steps; RLOO adds unscaled).aux_lossis logged when enabled.AsyncGRPOTrainer: Newmodel_init_kwargsonAsyncGRPOConfig(passed intofrom_pretrained). The chunked LM-head path recomputes aux loss viaload_balancing_loss_funcinpatch_chunked_lm_headwhen MoE is enabled; policy loss includes the aux term with the same grad-accum scaling as GRPO.Call-site updates: Experimental GRPO variants (DPPO, GFPO, GMPO, etc.) unpack the new 3-tuple from
_get_per_token_logps_and_entropies.SFTTraineronly gains a warning whenoutput_router_logitsis set but coef is zero.Liger-kernel loss paths are unchanged (no aux term), consistent with SFT.
Reviewed by Cursor Bugbot for commit acd8007. Bugbot is set up for automated code reviews on this repo. Configure here.