check_perlayer_mse: skip empty-input hook calls (Qwen3 MoE) - #2
Merged
Conversation
Qwen3 MoE routes each token to top-k experts; experts that get zero tokens in a given step are still called, with an input of shape (0, hidden). F.mse_loss handles numel()==0 cleanly, but (out - ref).abs().max() raises RuntimeError: max(): Expected reduction dim to be specified for input.numel() == 0. because reducing an empty tensor to a scalar without dim= is undefined. Dense Qwen3 never triggers this; the 30B-A3B Phase 2 run in the prior sweep crashed exactly here. Fix: early-return from the hook when x is empty — there is no SC error to record for an unused expert call. Verified on gl1810 at Qwen/Qwen3-30B-A3B-Instruct-2507, sc_prec=8, stoc_len=256: 3669 SC matmul calls captured across 48 layers / 128 experts. Top-10 worst single matmuls are all late-layer experts (layers 46-47 down_proj), matching the outlier-driven pattern observed on dense Qwen3.
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a crash in check_perlayer_mse.py for Qwen3 MoE models where experts that receive zero routed tokens produce empty-input hook calls, causing .abs().max() on a 0-element tensor to raise.
Changes:
- Early-return from the post-hook when
x.numel() == 0to skip empty expert calls.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
heroarmor
approved these changes
May 17, 2026
heroarmor
left a comment
Collaborator
There was a problem hiding this comment.
Clean, targeted fix for a real Qwen3-MoE-only crash. Confirmed:
- Empty-input case is genuine for MoE experts with 0 routed tokens; .abs().max()/.mean() on numel()==0 tensors raises (PyTorch refuses to guess a default for unreduced ops). F.mse_loss handles it but is unused on that path.
- Early-return is the right semantic (no SC error to record for an unrouted expert), and the printed 'Captured N' count becomes meaningful instead of being inflated by no-op calls.
- Disjoint from PR #3 (PR #3 touches root check_perlayer_mse.py; this touches model_qwen4b/check_perlayer_mse.py).
- Test evidence: 3669 calls captured on Qwen3-30B-A3B with late-layer down_proj dominating MSE — matches the established outlier pattern from dense Qwen3 and llama.
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
Follow-up to #1.
check_perlayer_mse.pycrashes on Qwen3 MoE checkpoints because the SC linears inside experts that receive zero routed tokens in a given step are still called, with an input of shape(0, hidden). The hook's(out - ref).abs().max()then raises:F.mse_losshandlesnumel()==0cleanly, but the unreduced.max()on an empty tensor is undefined and PyTorch refuses to guess. Dense Qwen3 never triggers this; the 30B-A3B Phase 2 run in the multi-model sweep was the only case that hit it.Fix is an early-return from the hook when
x.numel() == 0— there is no SC error to record for an unused expert call.Test plan
Qwen/Qwen3-30B-A3B-Instruct-2507,sc_prec=8 stoc_len=256on gl1810 (RTX PRO 6000 Blackwell) — completes without raising; 3669 SC matmul calls captured across 48 layers × 128 experts.down_projdominates (mean MSE 2.3e-3, max3.7e-1) as expected from the outlier-driven pattern.layers.46/47.mlp.experts.*.down_proj), the MoE analog of the late-layerdown_projstory already documented for dense Qwen3 / llama.Sample output (Qwen3-30B-A3B-Instruct-2507,
stoc_len=256)🤖 Generated with Claude Code