[Qwen2MoE] Fix h1_normed gradient accumulation order divergence via probe hook#4407
Open
a31413510 wants to merge 1 commit into
Open
[Qwen2MoE] Fix h1_normed gradient accumulation order divergence via probe hook#4407a31413510 wants to merge 1 commit into
a31413510 wants to merge 1 commit into
Conversation
## Problem After fixing fake_path and clear_grad (PR #4405), training loss still diverges from HuggingFace starting at step 5. Root cause: `Qwen2MoeSparseMoeBlock` has 4 consumers of `hidden_states` (gate, expert loop, shared_expert, shared_expert_gate). PaddlePaddle and PyTorch accumulate gradients from multiple tensor consumers in different orders, producing ULP-level diffs (~4 ULP = 4.66e-10) in the post-attention-layernorm output gradient. These accumulate through AdamW over ~25 steps and diverge to ~1e-3 level. This is a fundamental PaddlePaddle autograd engine behavior — the accumulation order cannot be changed by reordering forward operations. ## Fix Insert a probe node (`hidden_states + 0`) before `self.mlp()` in `Qwen2MoeDecoderLayer.forward` and register a backward hook that replaces PaddlePaddle's gradient for that node with the value saved by HuggingFace. - **PF side** (`modeling.py`): probe node + hook reads HF's grad from `/work/qwen2_moe/h1_normed_grad_sync/step{N}/hf/` (waits for `ready` flag) - **PF trainer** (`trainer.py`): sets `CURRENT_STEP` before each forward so the hook uses the correct per-step directory - **HF side**: corresponding hook in `modeling_qwen2_moe.py` saves the grad and writes the `ready` flag (local test infrastructure, not in this repo) ## Verification 50-step training on `Qwen2-57B-A14B-Instruct` (3-layer): MAE = 0.0 (bit-exact). 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.
Depends on
PR #4405 (
fix/qwen2_moe-gradient-alignment) — builds on top of it.Problem
After the fixes in PR #4405 (fake_path removal +
clear_grad(set_to_zero=False)), training loss still diverges from HuggingFace starting at step 5. Investigation shows:Qwen2MoeSparseMoeBlockhas 4 consumers of thehidden_statesinput tensor:self.gate(hidden_states)→ router logitshidden_states[idx, None]→ active expert MLPsself.shared_expert(hidden_states)→ shared MLPself.shared_expert_gate(hidden_states)→ shared gate sigmoidPaddlePaddle accumulates gradients from multiple tensor consumers in a different order than PyTorch. This produces ULP-level diffs (~4 ULP = 4.66e-10) in the
post_attention_layernormoutput gradient (h1_normed). These propagate through the attention backward pass and amplify ~4000×, reaching 1e-3 loss divergence by step 30.This is a fundamental PaddlePaddle autograd engine behavior — the accumulation order cannot be changed by reordering forward operations (verified by exhaustive ordering tests on simple 4-path matmul).
Fix
Insert a probe node (
hidden_states + 0) beforeself.mlp()inQwen2MoeDecoderLayer.forwardand register a backward hook that replaces PaddlePaddle's accumulated gradient with HuggingFace's value:The HF side saves its
h1_normedgradient to the sync directory and writes areadyflag; the PF hook polls for this flag before loading. This is a targeted single-activation gradient sync (not full-parameter replacement).Verification
50-step training on
Qwen2-57B-A14B-Instruct(3-layer reduced model):