[Qwen2MoE] Fix gradient alignment: remove fake_path and use clear_grad(set_to_zero=False)#4405
Open
a31413510 wants to merge 1 commit into
Open
[Qwen2MoE] Fix gradient alignment: remove fake_path and use clear_grad(set_to_zero=False)#4405a31413510 wants to merge 1 commit into
a31413510 wants to merge 1 commit into
Conversation
## Problem When training Qwen2MoE with PaddleFormers, post-optimizer weights diverge from HuggingFace (PyTorch) starting from step 2. Two root causes were identified, both related to MoE expert activation behavior. ## Root Causes & Fixes ### Fix 1: Remove fake_path from Qwen2MoeSparseMoeBlock (`modeling.py`) The original code iterated over all 64 experts, using a "fake path" for inactive ones: `expert_layer(x * 0)`. This produced grad=0 tensors for all inactive expert parameters. AdamW treats grad=0 differently from grad=None — it still applies weight_decay to parameters with grad=0, causing inactive expert weights to drift away from the HuggingFace reference after each optimizer step. Fix: replace the all-experts loop + fake_path with `nonzero()`-based iteration that only processes experts with at least one assigned token, matching the HF implementation exactly and keeping inactive expert gradients as None. ### Fix 2: `clear_grad(set_to_zero=False)` in trainer (`trainer.py`) The default `clear_grad()` (equivalent to `set_to_zero=True`) zeros out all gradients including those of inactive experts, which revives the grad=0 problem for the next step. Using `set_to_zero=False` keeps grad=None for parameters that were not activated, so AdamW correctly skips them — matching PyTorch/HF behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Thanks for your contribution! |
|
This Pull Request is stale because it has been open for 60 days with no activity. 当前Pull Request 60天内无活动,被标记为stale。 |
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
When training Qwen2MoE with PaddleFormers, post-optimizer weights diverge from HuggingFace (PyTorch) starting from step 2. Two root causes were identified, both related to MoE expert activation behavior.
Root Causes & Fixes
Fix 1: Remove fake_path from
Qwen2MoeSparseMoeBlock(modeling.py)The original code iterated over all 64 experts for every step, using a "fake path" for inactive ones:
This produced grad=0 tensors for all inactive expert parameters. AdamW treats
grad=0differently fromgrad=None— it still appliesweight_decayto parameters withgrad=0, causing inactive expert weights to slowly drift away from the HuggingFace reference after each optimizer step.Fix: Replace the all-experts loop + fake_path with
nonzero()-based iteration that only processes experts with at least one assigned token — matching the HF implementation exactly and keeping inactive expert gradients asNone.Fix 2:
clear_grad(set_to_zero=False)intrainer.pyThe default
clear_grad()(equivalent toset_to_zero=True) zeros out all gradients at the end of each step, which revives thegrad=0problem for the next step even after Fix 1. Usingset_to_zero=Falsekeepsgrad=Nonefor parameters that were not activated, so AdamW correctly skips them — matching PyTorch/HF behavior.This fix is consistent with the same change already applied for Qwen3MoE in PR #4358.
Verification
Tested on
Qwen2-57B-A14B-Instruct(reduced to 3 hidden layers for speed). Training loss aligned with Swift/HuggingFace reference across 50 steps (MAE = 0.0, bit-exact).Related
clear_grad(set_to_zero=False)fix for Qwen3MoE