Skip to content

Fix DFlash sliding attention causality defaults - #34524

Merged
hnyls2002 merged 2 commits into
mainfrom
mmangkad/fix-dflash-sliding-causality
Aug 12, 2026
Merged

Fix DFlash sliding attention causality defaults#34524
hnyls2002 merged 2 commits into
mainfrom
mmangkad/fix-dflash-sliding-causality

Conversation

@mmangkad

@mmangkad mmangkad commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Motivation

PR #34262 changed DFlash sliding-attention layers from the legacy causal behavior to bidirectional attention when a checkpoint does not declare is_causal. The z-lab/gemma-4-31B-it-DFlash config has four sliding-attention layers and no is_causal field, so its average speculative accept length regressed from approximately 5.62 to 5.27 and failed test_gemma4_dflash_31b_extra.py's 5.4 threshold.

This change restores compatibility for existing DFlash checkpoints while retaining Muse Glimmer's intended bidirectional draft attention.

Modifications

  • Preserve the historical layer-specific defaults when a DFlash checkpoint does not declare is_causal:
    • sliding-attention layers use causal (AttentionType.DECODER) attention;
    • full-attention layers use bidirectional (AttentionType.ENCODER_ONLY) attention.
  • Continue honoring explicit is_causal=True and is_causal=False checkpoint declarations for every DFlash attention layer.
  • Declare MuseGlimmerAssistantConfig.is_causal = False so Muse Glimmer explicitly retains bidirectional full and sliding draft attention.
  • Use config.get_text_config() for canonical text-config resolution.

Accuracy Tests

The regression boundary was confirmed from scheduled CI runs:

Scheduled run Commit Gemma-4 DFlash result
#134351 ceeaec2078 PASS, accept length 5.61731
#134738 546965fc72 PASS, accept length 5.62095
#134970 857910bd35 FAIL, accept length 5.30446; retry 5.27089

Local configuration-path validation loaded the cached checkpoints through SGLang's actual config parser and evaluated every draft layer:

  • Gemma-4 DFlash: four sliding layers resolved to DECODER; the full layer resolved to ENCODER_ONLY.
  • Muse Glimmer: all sliding layers resolved to ENCODER_ONLY.
  • Explicit is_causal=False and is_causal=True both override the legacy defaults consistently.

The Gemma-4 DFlash acceptance test passed locally on 2x NVIDIA H100 80GB GPUs with TP=2 and the Extra CI runtime environment:

CUDA_VISIBLE_DEVICES=0,1 \
NCCL_NVLS_ENABLE=0 \
SGLANG_ENABLE_ASYNC_ASSERT=true \
SGLANG_CUDA_COREDUMP=1 \
SGLANG_IS_IN_CI=true \
python -u test/registered/spec/test_gemma4_dflash_31b_extra.py -f
Total latency: 19.885 s
Score: 0.790
Output throughput: 1246.108 token/s
[METRIC] gsm8k_score=0.79 labels={"model": "google/gemma-4-31B-it", "eval": "gsm8k"}
[METRIC] gsm8k_latency=19.885110595991137 labels={"model": "google/gemma-4-31B-it", "eval": "gsm8k"}
====================
Speculative decoding: no per-request spec_accept_length in responses (non-speculative server, or --api completion which lacks return_meta_info).
====================
Writing report to /tmp/gsm8k_google_gemma-4-31B-it.html
{'score:std': np.float64(0.4073082370883261), 'score': np.float64(0.79), 'latency': 19.885110595991137, 'output_throughput': 1246.1082316029701}
Writing results to /tmp/gsm8k_google_gemma-4-31B-it.json
[2026-08-12 04:44:17] INFO:     127.0.0.1:58074 - "GET /server_info HTTP/1.1" 200 OK
[Gemma4 31B DFlash] score=0.7900 threshold=0.7500 avg_spec_accept_length=5.633289124668435
WARNING:root:GITHUB_STEP_SUMMARY environment variable not set
.
----------------------------------------------------------------------
Ran 1 test in 71.033s

OK

This restores the accept length from the regressed 5.27-5.30 range to the historical 5.61-5.62 range. CI should also run the Muse-specific acceptance test to confirm its explicit bidirectional behavior end to end:

  • test/registered/spec/dflash/test_muse_glimmer_dflash_assistant_gsm8k.py

Additional checks:

  • git diff --check
  • python -m compileall -q on both modified files
  • scoped pre-commit hooks on both modified files

Speed Tests and Profiling

No standalone speed benchmark or profile was run. The local Gemma-4 DFlash acceptance test completed its 200-example GSM8K evaluation in 19.885 seconds at 1246.108 output tokens/s. This change restores the acceptance behavior guarded by the existing test and does not add work to the inference path.

Checklist

Review and Merge Process

  1. Ping Merge Oncalls to start the process. See the PR Merge Process.
  2. Get approvals from CODEOWNERS and other reviewers.
  3. Trigger CI tests with comments or contact authorized users to do so.
    • Common commands include /tag-and-rerun-ci, /tag-run-ci-label, /rerun-failed-ci
  4. After green CI and required approvals, ask Merge Oncalls or people with Write permission to merge the PR.

CI States

Latest PR Test (Base): ❌ Run #31564810857
Latest PR Test (Extra): ❌ Run #31564810558

@mmangkad

Copy link
Copy Markdown
Collaborator Author

/rerun-test test/registered/spec/test_gemma4_dflash_31b_extra.py test/registered/spec/dflash/test_muse_glimmer_dflash_assistant_gsm8k.py

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Results for /rerun-test test/registered/spec/test_gemma4_dflash_31b_extra.py test/registered/spec/dflash/test_muse_glimmer_dflash_assistant_gsm8k.py:

🚀 2-gpu-h100 (1 test): ✅ View workflow run

cd test/ && python3 registered/spec/test_gemma4_dflash_31b_extra.py

🚀 1-gpu-h100 (1 test): ✅ View workflow run

cd test/ && python3 registered/spec/dflash/test_muse_glimmer_dflash_assistant_gsm8k.py

@hnyls2002
hnyls2002 merged commit 0dab252 into main Aug 12, 2026
112 of 128 checks passed
@hnyls2002
hnyls2002 deleted the mmangkad/fix-dflash-sliding-causality branch August 12, 2026 06:05
zixi-qi added a commit to zixi-qi/vllm that referenced this pull request Aug 13, 2026
Muse-Glimmer-30B-assistant has five sliding_attention layers and declares
no causality, so it resolves causal under the layer-type default. vllm-project#51655
handled that by treating any uniform layer_types as non-causal, which
changes the default for every DFlash and DSpark drafter and breaks
test_dflash_causality.py::test_dflash_has_any_non_causal[config3-False] --
the only failure in the amd-v1-spec-decode-mi300-1 job of build 83669.

Drop that change, leaving _dflash_layer_causal byte-identical to main, and
declare the head's causality on MuseGlimmerAssistantConfig instead. The
head is bidirectional over the draft block: transformers'
modeling_muse_glimmer_assistant sets is_causal = False and builds
bidirectional masks for both layer types, and SGLang declares the same on
its config class. SGLang widened the default first and reverted it in
sgl-project/sglang#34524 after gemma-4-31B-it-DFlash acceptance fell from
5.62 to 5.27.

Checkpoints that declare their own causality are unaffected either way:
poolside/Laguna-S-2.1-DFlash, poolside/Laguna-XS-2.1-DFlash and the
nvidia Nemotron DSpark head all ship dflash_config.causal, and a
checkpoint-supplied value still overrides the default added here.

Test: pytest v1/spec_decode/test_dflash_causality.py -> 10 passed, with
the test file byte-identical to upstream.

Signed-off-by: zixi-qi <zixi@inferact.ai>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
saturn-acc pushed a commit to saturn-acc/sglang that referenced this pull request Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants