Files
vLLM-4x-RTX-3090/patches/0085-recoverssm-use-replayssm-without-MTP-falls-back-to-t.patch
MOVZX 777e910dd0 Initial commit
Signed-off-by: MOVZX <movzx@yahoo.com>
2026-10-15 01:01:52 +07:00

82 lines
3.8 KiB
Diff

From a42c2e52b5765a7bcd896e97cecdb18a0f3a2764 Mon Sep 17 00:00:00 2001
From: halt95 <halt95@users.noreply.github.com>
Date: Sun, 4 Oct 2026 07:33:26 -0400
Subject: [PATCH 085/103] recoverssm: --use-replayssm without MTP falls back to
the stock GDN path
On Qwen4Exp the flag selects RecoverSSM, which needs speculative decoding. With num_speculative_tokens=0 the
validator refused to start; it now logs a warning, clears use_replayssm (the no-flag path) and continues, so one
launch line serves with and without MTP. Other architectures keep the error. Config tests cover both.
---
tests/config/test_recoverssm_config.py | 27 +++++++++++++++++++++++---
vllm/config/vllm.py | 14 +++++++++----
2 files changed, 34 insertions(+), 7 deletions(-)
diff --git a/tests/config/test_recoverssm_config.py b/tests/config/test_recoverssm_config.py
index 2fba7eb..352b8bf 100644
--- a/tests/config/test_recoverssm_config.py
+++ b/tests/config/test_recoverssm_config.py
@@ -122,9 +122,30 @@ def test_flag_unset_keeps_the_stock_path():
assert not uses_recoverssm(cfg.cache_config, 3)
-def test_qwen4exp_replayssm_requires_speculative_decoding():
- with pytest.raises(ValueError, match="requires speculative decoding"):
- _validator()(_config(TARGET, num_spec=0))
+@pytest.mark.parametrize(
+ "arch", ["Qwen4ExpForConditionalGeneration", "Qwen4ExpForCausalLM"]
+)
+def test_qwen4exp_replayssm_without_spec_falls_back_to_stock(arch):
+ # Fork (v2.5): no speculative decoding -> the flag is dropped, not refused.
+ cfg = _config(arch, num_spec=0)
+ _validator()(cfg)
+ assert cfg.cache_config.use_replayssm is False
+ assert cfg.cache_config.use_recoverssm is False
+ assert not uses_recoverssm(cfg.cache_config, 0)
+ # The fallback is the stock path: the RecoverSSM runtime checks no longer apply.
+ pp2 = _config(
+ arch, num_spec=0, mamba_config__backend="flashinfer", use_v2_model_runner=False
+ )
+ _validator()(pp2)
+ assert pp2.cache_config.use_replayssm is False
+
+
+def test_fallback_is_qwen4exp_only():
+ # Other ReplaySSM architectures keep their plain ReplaySSM path without drafts.
+ cfg = _config("NemotronHForCausalLM", num_spec=0, use_v2_model_runner=False)
+ _validator()(cfg)
+ assert cfg.cache_config.use_replayssm is True
+ assert cfg.cache_config.use_recoverssm is False
def test_architecture_without_replayssm_support_is_rejected():
diff --git a/vllm/config/vllm.py b/vllm/config/vllm.py
index d07579e..2538e80 100644
--- a/vllm/config/vllm.py
+++ b/vllm/config/vllm.py
@@ -3240,11 +3240,17 @@ class VllmConfig:
and not self.cache_config.use_recoverssm
):
# Qwen4Exp's GDN and PLE layers have no plain ReplaySSM path; with them the
- # flag selects RecoverSSM, which needs speculative decoding.
- raise ValueError(
- "--use-replayssm on Qwen4Exp selects GDN RecoverSSM and requires "
- "speculative decoding (num_speculative_tokens > 0)"
+ # flag selects RecoverSSM, which needs speculative decoding. Fork (v2.5):
+ # without speculative decoding there are no drafts to recover from, so the
+ # flag falls back to the stock path (as if it were not passed) instead of
+ # refusing to start; one launch line then serves with and without MTP.
+ logger.warning(
+ "--use-replayssm on Qwen4Exp selects GDN RecoverSSM, which needs "
+ "speculative decoding; num_speculative_tokens=0, so the stock GDN "
+ "path is used (as without --use-replayssm)"
)
+ self.cache_config.use_replayssm = False
+ return self
if self.cache_config.use_recoverssm:
if self.model_config is not None and self.model_config.architecture not in (
"KimiLinearForCausalLM",
--
2.43.0