Skip to content

[Fix] [XPU] glm4_moe_lite: Skip model-side routed scaling on XPU (fix GLM-4.7-Flash accuracy) - #43891

Open
desmond-intel wants to merge 8 commits into
sgl-project:mainfrom
desmond-intel:model-serve/glm47-flash-xpu
Open

desmond-intel wants to merge 8 commits into
sgl-project:mainfrom
desmond-intel:model-serve/glm47-flash-xpu

Conversation

@desmond-intel

@desmond-intel desmond-intel commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

On Intel XPU, zai-org/GLM-4.7-Flash (Glm4MoeLiteForCausalLM) serves but gives wrong answers: gsm8k 5-shot drops to 0.25 (limit 20) with both --attention-backend intel_xpu and triton, against 84.2 on H200.

On XPU, the MoE layer already applies routed_scaling_factor on every path:

  • sgl_kernel.fused_experts for unquantized (UnquantizedFusedMoEMethod.forward_xpu), fp8 and mxfp4 weights;
  • the triton runner's moe_sum_reduce in the _is_xpu branch of fused_moe.py.

Glm4MoeLiteSparseMoeBlock.forward_normal multiplies the routed output by routed_scaling_factor again on every non-CUDA device, so XPU applies it twice (1.8^2 for GLM-4.7-Flash). DeepseekV2MoE.forward_normal already excludes XPU from this multiply. The unquantized path began passing the factor to the kernel in #39817, which aligned it with the fp8/mxfp4 paths and exposed the double scaling for the bf16 GLM-4.7-Flash checkpoint.

Modifications

  • Add _is_xpu to the model-side scaling condition in Glm4MoeLiteSparseMoeBlock.forward_normal (python/sglang/srt/models/glm4_moe_lite.py), matching DeepseekV2MoE.forward_normal.
  • CUDA, ROCm/aiter, NPU and CPU are unchanged: the condition is identical when _is_xpu is False.
  • forward_normal_dual_stream is unchanged: alt_stream is only created on CUDA, so XPU never takes that path.
  • Add test/registered/xpu/llm_models/test_xpu_glm_4_7_flash.py: GLM-4.7-Flash GSM8K on XPU at TP=4 in the nightly-xpu-kernel-main-4-gpu suite. Like the other tests in that folder it uses SimpleEvalGSM8KXPUMixin (sgl-eval gsm8k), with the cookbook settings: thinking on with --reasoning-parser glm45, temperature 0.7, top_p 0.95, max_tokens 2048.
  • The XPU nightly jobs and the XPU test extra already install sgl-eval==0.1.3 and antlr4-python3-runtime==4.9.3 on main ([CI] [Intel] xpu-eval: Add sgl-eval to XPU test deps and move all GSM8K tests to it #47056), so this PR no longer changes nightly-test-intel.yml or pyproject_xpu.toml.

Glm4MoeSparseMoeBlock.forward_normal in glm4_moe.py (GLM-4.5/4.6/4.7) has the same condition and likely the same XPU issue. It is left out of this PR because those checkpoints could not be validated on the available XPU hardware.

Accuracy Tests

Intel Arc Pro B60, tp-size 4, --attention-backend intel_xpu, lm_eval gsm8k 5-shot (local-completions, greedy, max_gen_toks=8192):

Run flexible-extract strict-match
Before, limit 20 0.25 0.20
After, limit 20 0.75 0.75
After, full 1319 0.8408 +/- 0.0101 0.8415 +/- 0.0101
H200 reference 0.842 -

The new nightly test on 4x Arc Pro B60, sgl-eval GSM8K at 20 questions, three runs: 0.85, 0.80, 0.90 (1-2 answers per run truncated at 2048 tokens), threshold 0.75. The eval takes 5.5-7 min; the whole test took 18-26 min, mostly server start with the weights read from a network model mirror. An earlier 50-question run scored 0.90.

Prompt logprobs against a CPU fp32 HF transformers reference (4 prompts): mean absolute difference was 0.77-1.46 nats before the fix and 0.07-0.16 after. Greedy continuations match HF token-for-token on 2 of the 4 prompts; the other 2 diverge at a bf16 near-tie.

Reproduce (the last three serve flags are B60 concurrency settings, unrelated to this change):

SGLANG_USE_SGL_XPU=1 sglang serve --model-path zai-org/GLM-4.7-Flash --device xpu --tp-size 4 \
  --mem-fraction-static 0.85 --trust-remote-code --attention-backend intel_xpu --reasoning-parser auto \
  --disable-overlap-schedule --disable-radix-cache --max-running-requests 4

python -m lm_eval --model local-completions \
  --model_args pretrained=zai-org/GLM-4.7-Flash,base_url=http://127.0.0.1:30000/v1/completions,num_concurrent=16,max_gen_toks=8192,max_length=12288,trust_remote_code=True \
  --tasks gsm8k --num_fewshot 5 --batch_size 16

Speed Tests and Profiling

No speed impact expected. On XPU the change removes one redundant elementwise multiply per MoE layer; other platforms are untouched.

Checklist


CI States

Latest PR Test (Base): ❌ Run #41987630259
Latest PR Test (Extra): ❌ Run #41987630128
Latest PR Test (AMD ROCm 10): ❌ Run #41987630040

Tip

Base CI only covers the core cases, and its workload may not exercise your change. Use /rerun-test to run the tests your change touches, or copy this prompt for an agent:

Find the registered tests this PR affects and run them with /rerun-test, following https://github.com/sgl-project/sglang/blob/main/.agents/skills/rerun-test/SKILL.md

@desmond-intel
desmond-intel force-pushed the model-serve/glm47-flash-xpu branch from c03b8fa to 0b570c3 Compare October 14, 2026 07:09
@desmond-intel desmond-intel changed the title glm4_moe_lite: skip model-side routed scaling on XPU (fix GLM-4.7-Flash accuracy) [Fix] [XPU] glm4_moe_lite: Skip model-side routed scaling on XPU (fix GLM-4.7-Flash accuracy) Oct 15, 2026

@airMeng airMeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please enable the related tests then I can include the PR in #45201

@desmond-intel

desmond-intel commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor Author

@airMeng Added test/registered/xpu/llm_models/test_xpu_glm_4_7_flash.py in 3b5b261: GLM-4.7-Flash GSM8K on XPU at TP=4, in the nightly-xpu-kernel-main-4-gpu suite with the same mixin as the Qwen3-30B-A3B test. No existing test covers this path; the other GLM-4.7-Flash tests are CUDA only or CPU unit tests of the gate.

On Arc Pro B60 (main 6e667c4 plus this fix) it scores 0.96 on its 50 questions against a threshold of 0.90, in 1431 s. With the factor applied twice the model scores about 0.25. --max-running-requests 4 is the B60 setting that keeps concurrent requests from losing the device.

Could you take it into the next weekly consolidation ?

airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 26, 2026
…43891)

Source: sgl-project#43891
Source-head: 3b5b261

Mechanically replay the latest source net patch, including the author-added XPU GSM8K nightly test. Kernel scaling behavior is present in pinned release v0.4.0 (028ac5a4e92a4addabeedac1a94374515f68e4a5). Source author retains responsibility for behavior and review feedback.
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 27, 2026
…43891)

Source: sgl-project#43891
Source-head: 3b5b261

Mechanically replay the latest source net patch, including the author-added XPU GSM8K nightly test. Kernel scaling behavior is present in pinned release v0.4.0 (028ac5a4e92a4addabeedac1a94374515f68e4a5). Source author retains responsibility for behavior and review feedback.
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 27, 2026
…43891)

Source: sgl-project#43891
Source-head: 3b5b261

Mechanically replayed source net patch onto origin/main cb55d77.
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 27, 2026
…43891)

Source: sgl-project#43891
Source-head: 3b5b261

Mechanically replayed source net patch onto origin/main cb55d77.
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 27, 2026
Source: sgl-project#43891
Source-head: 3b5b261

Mechanically replayed source net patch onto origin/main b74fd39.
@airMeng

airMeng commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

@desmond-intel — forwarding @mingfeima’s comment from #46623:
#46623 (comment)

This new test inherits a mixin that calls deprecated run_eval.

Now the BKM is to use the sgl-eval helper/mixin with explicit generation settings and recalibrate the accuracy threshold under that harness.

@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Oct 28, 2026
@desmond-intel

Copy link
Copy Markdown
Contributor Author

@mingfeima @airMeng Switched in 15d1c41. The test now uses the shared GSM8KMixin with gsm8k_backend = "sgl_eval" and explicit generation settings from the GLM-4.7-Flash cookbook: thinking on with --reasoning-parser glm45, temperature 0.7, top_p 0.95, max_tokens 2048. Recalibrated on Arc Pro B60 (tp 4, main 8301033 plus this PR): 0.92 on the 50 questions in 793 s, and the threshold is now 0.80.

The XPU nightly container does not ship sgl-eval, and the sgl-eval kits skip their test when it is missing. aa20bd2 installs sgl-eval==0.1.3 and antlr4-python3-runtime==4.9.3 (the pins of the main test extra) in the four XPU nightly jobs and adds them to the XPU test extra. The branch also merges current main (2e58c3c), since the nightly workflow was split after this PR's base.

airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 28, 2026
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 28, 2026
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 28, 2026
airMeng pushed a commit to airMeng/sglang that referenced this pull request Oct 28, 2026
@desmond-intel
desmond-intel force-pushed the model-serve/glm47-flash-xpu branch from b311ab7 to a8f23b9 Compare November 2, 2026 19:46
@arathi-hlab arathi-hlab added the run-ci CI: run the baseline test suite on this PR label Nov 3, 2026
…sh accuracy)

On XPU every MoE path applies routed_scaling_factor itself: sgl-kernel
fused_experts (unquant, fp8, mxfp4) and the triton runner's moe_sum_reduce.
Glm4MoeLiteSparseMoeBlock.forward_normal still multiplied on every non-CUDA
device, so XPU scaled the routed output by routed_scaling_factor squared (1.8^2
for GLM-4.7-Flash) and the model answered wrongly on any attention backend
(gsm8k 0.25 at limit 20). Exclude XPU like CUDA, matching
DeepseekV2MoE.forward_normal. Verified on intel_xpu tp4 (Arc Pro B60): gsm8k
5-shot, full 1319, flexible-extract 0.8408, strict-match 0.8415 (H200 84.2).
Covers the glm4_moe_lite routed scaling fix: with the factor applied twice
the model scores about 0.25 on gsm8k. --max-running-requests 4 is the B60
setting that keeps concurrent requests from losing the device.

Arc Pro B60, tp 4, on main 6e667c4 with the fix: 0.96 on the 50
questions, 1431 s.
Switch from SimpleEvalGSM8KXPUMixin, which calls the deprecated run_eval,
to the shared GSM8KMixin with the sgl_eval backend and explicit generation
settings from the GLM-4.7-Flash cookbook: thinking on (the chat template's
default) with --reasoning-parser glm45, temperature 0.7, top_p 0.95
(sgl-eval's default) and max_tokens 2048.

Arc Pro B60, tp 4, on main 8301033 with this PR: 0.92 on the 50
questions (2 truncated at 2048 tokens), 793 s. The threshold is 0.80; with
the routed scaling applied twice the model scores about 0.25.
The file lives under test/registered/xpu and is registered with
register_xpu_ci, so it only runs on XPU runners.
Main now scores every test in test/registered/xpu/llm_models/ with
SimpleEvalGSM8KXPUMixin (sgl-eval gsm8k, sgl-project#47056). Move this test onto it
instead of the generic GSM8KMixin with its own server launch. Same launch
flags, 50 examples, 4 threads, threshold 0.80 and cookbook sampling
(temperature 0.7, top_p 0.95, max_tokens 2048, thinking on by template
default).
@desmond-intel
desmond-intel force-pushed the model-serve/glm47-flash-xpu branch from 725edd7 to 0d5f866 Compare November 3, 2026 09:28

other_args = SimpleEvalGSM8KXPUMixin.other_args + [
"--reasoning-parser",
"glm45",

@arathi-hlab arathi-hlab Nov 4, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you confirm sgl-eval is used ? if yes so please collect the number based on that rest is LGTM

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it uses sgl-eval. SimpleEvalGSM8KXPUMixin calls run_sgl_eval(eval_name="gsm8k") (simple_eval_gsm8k_xpu_mixin.py:110), and each run logs sgl-eval gsm8k generation: {'max_tokens': 2048, 'temperature': 0.7, 'top_p': 0.95, ...}. The numbers in the description are from sgl-eval: three runs at 20 questions on 4x B60 scored 0.85, 0.80 and 0.90 (threshold 0.75), and an earlier 50-question run scored 0.90.

Three runs at 20 examples on 4x Arc Pro B60 scored 0.85, 0.80 and 0.90
(sampling at temperature 0.7, 1-2 answers per run cut off at 2048 tokens).
0.80 left no margin below the lowest run; 0.75 leaves one question.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file run-ci CI: run the baseline test suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants