Repository navigation
[port] Skip auxiliary loss for hash MoE layers (upstream #7079) - #97
Merged
Zhichenzzz merged 1 commit intoSep 24, 2026
Merged
Conversation
HJSang
marked this pull request as ready for review
September 16, 2026 22:16
HJSang
force-pushed
the
port/7079-hash-moe-skip-aux-loss
branch
from
September 21, 2026 17:11
0dfb357 to
696b8df
Compare
HJSang
force-pushed
the
port/7079-hash-moe-skip-aux-loss
branch
from
September 23, 2026 16:32
696b8df to
e13741c
Compare
This was referenced Sep 23, 2026
Zhichenzzz
approved these changes
Sep 24, 2026
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.
Test results (2026-09-23) — ✅ passed
test_routers.py(4 ranks)--moe-aux-loss-coeff 1e-3: aux-lossgrad_norm, steps 0/1/2The 3 new
test_hash_routing_skips_aux_loss[*]cases pass. The 2 failures (test_router_gating_linear*[fp32], an fp32 router GEMM precision check) and the 14 errors (tests that need 8 ranks) are identical on the base. The E2E reproduces the grad-norm drop reported below. No regression.Environment: 2× new 4× B200 devboxes (
b200-verda-k8s),radixark/miles:devrebuilt after miles#3296 (cuDNN Frontend 1.28.0 with the compact wrapper, TE 2.17, torch 2.13), Miles @a6b72d31f, basemiles-main@96fe16ecb. Unit tests ran undertorchrun --nproc_per_node=4, and every failure was compared against the base run the same way. The Miles E2E recipe is DeepSeek-V4-Flash-FP8-4layer, GSM8K, deterministic mode, 3 rollouts,--dsv4-impl megatron --dsa-kernel-backend cudnn, with a per-token old-vs-train log-prob dump (~3.14M response tokens per arm). Rollouts were identical across arms. Full details: #99 (comment)Ports NVIDIA#7079 (
2b31f24598, merged to upstreamdev2026-09-07, author Hongxiao Bai) ontomiles-main. Cherry-picked with-x; applied cleanly, no conflicts.Why
Hash-routed MoE layers dispatch tokens by
tid2eid, not by the learned router logits. When an auxiliary load-balancing loss is enabled,TopKRouterstill recomputes a top-k routing map from the logits and applies the aux loss to it. That loss then optimizes routing decisions that were never executed. DeepSeek V4 uses hash routing on its firstmoe_n_hash_layersMoE layers (3 of the 4 layers in the Flash 4-layer prune, and the first 3 MoE layers of the full model), so every DSv4 run with a nonzero aux-loss coefficient trains against a spurious objective on those layers.What changes
router.py: the aux-loss block inTopKRouter.forwardgains anot self.is_hash_layerguard. Non-hash layers sharing the same config keep their aux loss. No behavior change whenmoe_aux_loss_coeff == 0.test_routers.py: newTestHashRouting::test_hash_routing_skips_aux_loss, parametrized overaux_loss,seq_aux_loss,global_aux_loss, asserting no aux-loss autograd function is attached on a hash layer.Applicability to Miles
Miles'
scripts/run_deepseek_v4.pycurrently converts and trains with--moe-aux-loss-coeff 0, so existing recipes are unaffected. The fix matters as soon as anyone turns the aux loss on for DSv4, and it keepsmiles-mainaligned with upstream for the pendingdevbump.Validation
radixark/miles:devimage, Megatronmiles-main@73b54618f+ this commit.tests/unit_tests/transformer/moe/test_routers.py -k test_hash_routing_skips_aux_loss: 3 passed.TestTop2Router::test_aux_loss: passed.TestAuxLossFreeTop2Router::test_router_forward_aux_freeerrors at setup on this devbox both with and without the patch (missing/opt/data/datasets.zipfixtures,torch.distributednot initialized in a single-process run). Pre-existing environment issue, unrelated to this change.Miles end-to-end A/B (4x B200,
radixark/miles:dev, model scriptscripts/models/deepseek-v4-flash-4layer.pyviascripts/run_deepseek_v4.py train)Same recipe both arms: DeepSeek-V4-Flash-FP8-4layer, GSM8K,
--dsv4-impl megatron --dsa-kernel-backend cudnn, TP1/PP1/EP1/CP1, deterministic mode, 3 rollouts, 256-token responses, and--moe-aux-loss-coeff 1e-3in--extra-argsto override the script's0so the aux loss is actually live (moe_aux_loss_coeff 0.001,moe_n_hash_layers 3confirmed in both logs). The pruned model earns zero reward, sotrain/lossandtrain/ppo_klare exactly 0 in both arms andtrain/grad_normis entirely aux-loss gradient.train/grad_normsteps 0 / 1 / 2miles-main73b5461port/7079The fix arm's aux-loss gradient is ~15% lower on every step (within-arm spread ~0.0002, between-arm gap ~0.0009): the three hash-routed layers no longer contribute an aux-loss gradient. The drop is not 4x because the router gate is frozen in this recipe (
--moe-router-freeze-gate), so aux-loss gradient only reaches parameters through the hidden states of earlier layers, and the surviving learned-routing layer is the last one. Direction and consistency are the point; the unit test proves the mechanism exactly. No behavior change when the coefficient is 0, as in current Miles recipes.Series
First of two ports of DeepSeek V4 commits from upstream
devthatmiles-main(snapshot ofdevat 2026-08-19) lacks. Companion: #98 (upstream NVIDIA#6343, fused RoPE packing). Further DSv4 commits (NVIDIA#7064, NVIDIA#5992) are left for the fulldevbump.🤖 Generated with Claude Code