Skip to content

vLLM: opt-in ReplaySSM decode for Gated DeltaNet (Qwen3.5 / Qwen3.6 / Qwen3-Next) - #1761

Merged
danielhanchen merged 12 commits into
mainfrom
vllm-replayssm-gdn
Oct 15, 2026
Merged

danielhanchen merged 12 commits into
mainfrom
vllm-replayssm-gdn

Conversation

@danielhanchen

Copy link
Copy Markdown
Member

Stacked on #1759. Adds vLLM ReplaySSM decode for Gated DeltaNet models (Qwen3.5, Qwen3.6, Qwen3-Next) to fast_inference / GRPO rollouts, opt-in:

import os
os.environ["UNSLOTH_VLLM_REPLAYSSM"] = "1"  # before loading a Qwen3.5 / Qwen3.6 / Qwen3-Next model

Why a backport

Released vLLM has ReplaySSM for Mamba2 only. The Gated DeltaNet half, vllm-project/vllm#48792 ("ReplaySSM: cache SSM inputs for faster Gated DeltaNet standard decode"), was reviewed and then closed unmerged when its fork was deleted. This PR carries it onto released vLLM (0.31) at runtime:

  • unsloth_zoo/_vendored/vllm/gdn_replayssm_decode.py: the PR's Triton decode kernel, verbatim except for its launch-config lookup (inlined; released vLLM has no GDN entry). Apache-2.0 LICENSE, MANIFEST and NOTICE entry added the same way as the vendored fla tree, and mirrored in _licenses.py.
  • unsloth_zoo/vllm_gdn_replayssm.py: the integration, ported from the same PR.
    • The GDN state page grows by the three ring tensors (corrected write d, key k, log-decay g), both in the layer spec and in the model-class hooks that size the hybrid page.
    • GDNAttentionMetadataBuilder derives the per-row ring cursor and flush flag from replayssm_decode_base_cpu, with persistent buffers for CUDA graphs. The metadata is a dataclass subclass, so update_block_table's dataclasses.replace keeps the fields.
    • QwenGatedDeltaNetAttention decodes through the ring both in decode-only batches and for the decode rows of mixed prefill + decode batches. The second matters: the conventional update would otherwise advance a state the ring then replays.
    • Every vLLM method it edits is matched against the installed source first (exact fragments). Any mismatch leaves vLLM untouched and the model loads without ReplaySSM.
  • Capability: ModelConfig.supports_replayssm is widened for the five Qwen GDN architectures (same mechanism as vLLM: ReplaySSM on by default for Mamba2 hybrids #1759).

Why opt-in

Unsloth fast_generate, vLLM 0.31.0, GSM8K first 250 (greedy), forced 256-token decode, fresh process per arm, ReplaySSM against today's default (V2 runner):

Model GPU B=8 B=64 GSM8K default -> ReplaySSM (paired 95% CI) top-5 KL
Qwen3.5-2B RTX PRO 6000 0.975x 1.018x 79.6% -> 78.0% ([-4.4, +0.8]) 2.8e-4
Qwen3.5-2B A100 40GB 0.804x 0.682x 79.6% -> 81.2% ([-0.8, +4.0]) 2.8e-4
Qwen3.6-35B-A3B RTX PRO 6000 1.007x 1.062x 94.8% -> 95.2% ([-1.6, +2.4]) 1.0e-3

Accuracy holds and peak memory is unchanged. Speed does not justify a default: vLLM 0.31 runs Triton ReplaySSM only on Model Runner V1, and for Qwen3.5 that switch alone costs 23% at 64 sequences on A100 (V1 without ReplaySSM: 0.766x) against about 3% for Nemotron-H. The GDN ring kernel is also slower than the packed decode kernel on A100 below about 100 sequences (isolated kernel, A100: 0.67x at 32, 1.63x at 128; RTX PRO 6000: 1.02x to 1.80x at every size; L4: 1.19x to 1.93x). The GDN recurrence is 5% to 24% of a Qwen3.5-2B decode step and 3% to 14% for Qwen3.6-35B-A3B, which bounds the end-to-end gain. So auto mode leaves GDN models alone; it can become a default once vLLM runs ReplaySSM on the V2 runner.

Tests

  • tests/test_vllm_replayssm.py: the GDN model types are gated, and auto mode does not request them.
  • tests/test_vendored_license_shipped.py: the vendored vLLM license and manifest are embedded verbatim.
  • tests/test_relative_imports_resolve.py: passes; the kernel import is spelled absolutely.
  • CPU smoke: the patch applies to vLLM 0.31.0, all three source edits match, and it is idempotent.

@danielhanchen danielhanchen self-assigned this Oct 15, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T07:28:49.917734Z 18725d1 Manual request
🔒 Security Review ✅ Completed 2026-10-15T06:15:52.458248Z bddac25 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

@danielhanchen

Copy link
Copy Markdown
Member Author

@codex security review

@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bddac253cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +220 to +222
decode_base_cpu = m.replayssm_decode_base_cpu
seq_lens_cpu = m.seq_lens_cpu_upper_bound
if decode_base_cpu is None or seq_lens_cpu is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject async speculative scheduling before deriving cursors

When the exported patch is used with both async scheduling and speculative decoding enabled, seq_lens_cpu_upper_bound is not an exact accepted sequence length, but this guard accepts it and derives write_pos and is_flush from it. The ring can consequently read unwritten entries or flush at the wrong token, silently changing logits; the upstream implementation explicitly rejects scheduler_config.async_scheduling and speculative_config is not None for this reason. Include that condition here so ReplaySSM is refused and the caller can fall back to the normal decode path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not reachable on the vLLM this targets: in vLLM 0.31 VllmConfig.validate_mamba_cached_kernel sets use_kda_recoverssm whenever num_speculative_tokens > 0 and raises "RecoverSSM is only supported for Kimi-K3 KDA" for every other architecture, so a speculative config with use_replayssm never reaches the GDN builder for Qwen. The patched builder also disables itself when use_kda_recoverssm is set, and load_vllm passes no speculative config.

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review

Security review completed. No security issues were found in this pull request.

Reviewed commit: bddac253cd

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: bddac253cd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@danielhanchen
danielhanchen changed the base branch from vllm-replayssm-default-on to main October 15, 2026 07:22
@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

1 similar comment
@danielhanchen

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 18725d17e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@danielhanchen

Copy link
Copy Markdown
Member Author

CI triage: Source lint fails on this PR's own new code, not on zoo main. The exec-literals gate reports a new call site at unsloth_zoo/vllm_gdn_replayssm.py:151, where compile(...) and exec(...) are handed a value that is not a written-out string (verdict: new-call-site). Either pass a literal, or, if the source really is trusted, record it with python scripts/lint_exec_literals.py --update and replace the generated "REVIEW ME" reason in scripts/exec_literals_baseline.json with why it is trusted (the gate stays red on "REVIEW ME").

@danielhanchen
danielhanchen merged commit d661e0b into main Oct 15, 2026
@danielhanchen
danielhanchen deleted the vllm-replayssm-gdn branch October 15, 2026 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant