Repository navigation
exp - feat(moe): Qwen3.8-27B DSpark MoE drafter with 16 x 1024 top-2 experts, 3-epoch GB300 recipe + serving-speed gate (stacked on kan/moe-3-qwen38) - #943
Draft
yushengsu-thu wants to merge 8 commits into
Conversation
…gl-project#941 package) + fused-MoE configs and equivalence gate Qwen3MoeDSparkModel / DFlashMoEDraftModel / DFlash2MoEDraftModel on SGLang's own TopK + FusedMoE modules (SGLANG_EXTERNAL_MODEL_PACKAGE=specforge.serving.sglang_models), so exports of the MoE drafter configs on this branch serve on stock SGLang >= 0.5.19. Tuned E=512,N=512 fused-MoE configs (H200, GB300) and the served-vs-reference gate come along unchanged from sgl-project#941.
…t length, with GB300 numbers make_moe_draft_from_dense.py builds a random-expert MoE export from the official dense DSpark drafter; speed_test_moe_draft.sh serves each drafter with SGLANG_SIMULATE_ACC_LEN so tok/s differences are step-time differences. README: GB300 tables for the bf16 and the FP8 target (dense / 16 x 1024 / 16 x 2048 / Kan's 512 x 512): 16 x 1024 top-2 costs 1-2%, Kan's shape 9-10% at c >= 8.
…s + 3-epoch GB300 recipe configs/qwen3.8-27b-dspark-moe-16x1024.json is Kan's v2 config with n_routed_experts 512 -> 16, moe_intermediate_size 512 -> 1024 and num_experts_per_tok 10 -> 2 (shared expert 2048, aux 0.001, per-sample router centering, grouped_mm unchanged): 283M FFN parameters per layer (1.06x dense), 63M active per token, ~1.94B in all. The recipe trains it from scratch for 3 epochs (14,874 steps at global batch 256) on one 4x GB300 node: 2 TP1 NVFP4 capture servers + 2 FSDP ranks, batch 4 x 32 x 2, AdamW on the GPUs, host-memory budget sized for the 924 GB container limit.
yushengsu-thu
requested review from
FlamingoPg,
FrankLeeeee,
shuaills and
sleepcoo
as code owners
October 8, 2026 11:42
yushengsu-thu
marked this pull request as draft
October 8, 2026 22:55
…ture node + trainer node, Mooncake RDMA) Weights-only warm start from the GB300 epoch-1 checkpoint (step 4958), bf16 target on Hopper, 8 capture servers on one node and an 8-rank FSDP trainer on the other, features over Mooncake RDMA. Measured between two h200-sci-k8s-1 devboxes: a trainer-side client reads 26 GB/s over RDMA (8 clients ~97 GB/s) against 2.2 GB/s over TCP, where the two-node layout is fetch-bound at ~5 samples/s; with RDMA it is capture-bound at ~17 samples/s (~20 h per epoch).
…ervers on the epoch-1 box + 4-rank trainer node)
… (smoke aborted at projected 551 GB > 512 GiB with 768 in flight)
…h-3 checkpoint, five epochs, per-epoch exports)
…point (the path had been rewritten to the new run's own directory)
3 of 4 tasks
This branch has not been deployed
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.
Stacked on
kan/moe-3-qwen38(the base of this PR), so the diff is only this branch's three commits: the drafter config + GB300 recipe, the serving-speed gate with its GB300 numbers, and the SGLang serving package of #941 (needed to serve the exports).Conclusion
RadixArk/qwen38-dspark-moe-16x1024/1epand benchmarked withspecforge benchmark(bf16 target, DSPARK block 7, triton, mamba 160, 32 max running requests, 100 / 200 prompts, 512 new tokens) on the GB300 box next to a running capture server, so only the accept lengths are valid: gsm8k c=1/8/32 4.87 / 4.89 / 4.90 (dense v1 5.16 / 5.15 / 5.17), mt-bench 3.38 / 3.65 / 3.73 (dense v1 3.63 / 3.89 / 4.02). Kan's 512 x 512 drafter gained 9-11% from epoch 1 to epoch 3; break-even here is +3.5% over dense (5.33 / 4.03 at c=8), worthwhile +6% (5.45 / 4.12). Epochs 2-3 continue from the epoch-1 checkpoint on two 8x H200 nodes (capture node + trainer node over Mooncake RDMA, recipeqwen3.8-27b-dspark-moe-16x1024-cont2ep-2node-h200.yaml); results per epoch will be added here.Motivation
Kan's MoE drafter (#811 / #812,
kan/moe-3-qwen38, 512 experts x 512 wide, top-10) gains ~1% accept length over dense v1 but loses 9-13% of throughput at c >= 8: a 7-token block x top-10 touches ~67 of the 512 experts, so every draft step streams ~1 GB of expert weights per layer against 0.53 GB for the dense FFN (#941 tables,qwen3.8-27b-dspark-moe-vs-dense-serving-results.md). With 16 experts a block touches at most 14, so the expert bytes stay at one dense FFN no matter how the router behaves, and the question becomes whether a few-wide-experts drafter keeps the MoE's accept-length gain. The speed gate below settles the throughput side before any GPU-hours are spent on training; the training run settles the accept-length side.Modifications
configs/qwen3.8-27b-dspark-moe-16x1024.json: Kan'sqwen3.8-27b-dspark-moe-v2.jsonwith only three keys changed:n_routed_experts512 -> 16,moe_intermediate_size512 -> 1024,num_experts_per_tok10 -> 2. Shared expert (2048, sigmoid-gated),qwen3_5_moepreset (softmax, renormalised top-k), aux loss 0.001, per-sample router centering (momentum 0.99) andgrouped_mmdispatch are unchanged.examples/configs/online/disaggregated/managed-local/qwen3.8-27b-dspark-moe-16x1024-3ep-gb300.yaml: 3 epochs from scratch (only the target embedding is loaded, as in Kan's runs) on one 4x GB300 node: 2 TP1 NVFP4 capture servers (GPUs 0-1) + 2 FSDP ranks (GPUs 2-3), batch 4 x accumulation 32 x 2 = 256 (4,958 steps per epoch, 14,874 in all), AdamW on the GPUs, lr 5e-4 constant after 4% warm-up, grad clip 1.0, FULL_SHARD, DSpark CE 0.1 / L1 0.9 / confidence 1.0, 512 anchors, decay gamma 4, flex attention, checkpoints every 2,479 steps (epoch ends included). Mooncake / feature-store watermarks are sized for the devbox's 924 GB container limit (comments in the file).scripts/moe_speed/:make_moe_draft_from_dense.pybuilds a random-expert MoE export from the official dense drafter (attention / projector / heads copied, experts random, so routing is uniform = worst case for expert bytes);speed_test_moe_draft.shserves each drafter withSGLANG_SIMULATE_ACC_LENand runssglang.bench_servingat c = 1 / 8 / 32, so tok/s differences are step-time differences. README has the tables below.specforge/serving/sglang_models/,patches/sglang/moe_configs/,scripts/gates/check_dspark_moe_sglang_equivalence.py,tests/test_serving/: the serving package of feat(serving): SGLang draft classes for the Qwen3.8-27B DSpark MoE drafter (SGLang FusedMoE path) + tuned fused-MoE configs #941 (SGLangTopK+FusedMoEdraft classes loaded viaSGLANG_EXTERNAL_MODEL_PACKAGE), unchanged, so the exports of this config serve on stock SGLang >= 0.5.19.End-to-end serving speed (GB300, accept length pinned to 5.0)
One GB300 (284 GB) per server, servers one after another on the same GPU with identical flags: DSPARK block 7, triton attention and MoE runner (default kernel config), mem-fraction 0.85, mamba cache 160, 32 max running requests, drafts bf16, 8 prompts per concurrency level x 512 in / 512 out, SGLang 0.5.20. Output tok/s, delta vs dense at the same concurrency. The 16-expert rows are random-expert exports; Kan's row is the trained
RadixArk/qwen38-dspark-moe-3ep-cont-step9916.bf16 target
Qwen/Qwen3.8-27B:FP8 target
Qwen/Qwen3.8-27B-FP8:Per step (c=1, bf16 target, TPOT): dense 2.92 ms, 16 x 1024 2.97 ms (+0.05 ms), 16 x 2048 2.98 ms, Kan 3.00 ms; at c=32: 7.39 / 7.51 / 7.61 / 8.16 ms. Doubling the expert width or the top-k buys nothing at a pinned accept length and costs another 1-2%, hence 16 x 1024 top-2 for the training run.
Training run
RadixArk/Qwen3.8-27B-NVFP4-BF16-LMHead) + 2 FSDP ranks, recipeqwen3.8-27b-dspark-moe-16x1024-3ep-gb300.yaml, 36.3 s/step (capture-bound, 7.0 samples/s), 50.7 h; train/acc 0.577 at step 4958.moe-16exp-1024dim, rank 0 = capture, rank 1 = trainer), recipeqwen3.8-27b-dspark-moe-16x1024-cont2ep-2node-h200.yaml: 8 capture servers on one node, 8 FSDP ranks on the other, features over Mooncake RDMA (26 GB/s per client measured, 277 GB/s raw); 17 s/step, 15 samples/s (still capture-bound), trainer peak 58 GB per rank, ~24 h per epoch. train/acc resumes at 0.575 at step 10 (0.585 at the end of epoch 1). The teacher changes from the NVFP4 target to the bf16Qwen/Qwen3.8-27Bbecause the NVFP4 checkpoint cannot run on Hopper; the draft stays bf16 and the data, order (seed 42), optimizer and loss settings are unchanged. The two sibling H200 runs (256-expert 5-layer, 512-expert 2-layer) use the bf16 teacher throughout. The GB300 run was stopped at step 5,780 of its epoch 2 once the two-node run had passed step 100 with sane metrics.2ep/and3ep/);qwen3.8-27b-dspark-moe-16x1024-cont5ep-from-3ep-2node-h200.yamlwarm-starts from its step-9916 checkpoint for five more epochs (24,790 steps) on the same two nodes; every epoch end is exported and uploaded toRadixArk/qwen38-dspark-moe-16x1024/{4..8}ep/(private). Target: 8 epochs in all....-cont2ep-2node-h200, was stopped at step 940 to merge the nodes into one devbox and is tagged superseded; same checkpoint, same settings)RadixArk/Qwen3.8-27B-Regen-Mixture-v1(1,269,290 conversations, max_length 8192, qwen3.5 chat template); bf16 training, bf16 serving, no fp8.1ep/uploaded 2026-10-10;2ep/…8ep/follow as each epoch ends)