Skip to content

qwen4exp: multi-seq split replay corrupts recurrent state when rs rollback is enabled (why the arch is excluded from llm_arch_supports_rs_rollback?) #28019

Description

@netmana808

Summary

LLM_ARCH_QWEN4EXP is excluded from llm_arch_supports_rs_rollback(), so n_rs_seq clamps to 0 for Qwen3.8-Flash-Next and hybrid-recurrent batched rollback never engages. Force-enabling it shows why: test-recurrent-state-rollback fails test_multi_seq_split_replay with a logits max diff of 9.25 — single-seq checkpoint restore passes, multi-seq split replay corrupts state. If the exclusion is deliberate, this issue documents the concrete gap (and asks what state is missing snapshot coverage); if it's an oversight, the repro below should make it easy to chase.

Repro (~2 min on top of loading the model)

On master @ cc231cb0d:

  1. Add the arch to the rollback allowlist:
--- a/src/llama-arch.cpp
+++ b/src/llama-arch.cpp
@@ bool llm_arch_supports_rs_rollback(const llm_arch & arch) {
         case LLM_ARCH_QWEN35:
         case LLM_ARCH_QWEN35MOE:
+        case LLM_ARCH_QWEN4EXP:
         case LLM_ARCH_DEEPSEEK4:
  1. Run the existing test against a Qwen3.8-Flash-Next GGUF (tested with an IQ4_XS quant, CPU backend):
CUDA_VISIBLE_DEVICES="" ./bin/test-recurrent-state-rollback \
  --model Qwen3.8-Flash-Next-IQ4_XS-00001-of-00003.gguf -ngl 0
  1. Output:
main : recurrent rollback checkpoint restored successfully
test_multi_seq_split_replay : multi-seq split replay logits mismatch (max diff 9.25491, first at seq 0 pos 16)

A diff of 9.25 in the logits is state corruption, not numerical noise.

Suspected cause

qwen4exp carries extra per-row recurrent state beyond the gated-delta-net state that the snapshot planes cover for the allowlisted archs:

  • the PLE conv history (ple_layer_ids: [2] — the PLE module sits on a layer that is also a delta-net layer, so both keep conv state in the same recurrent row), and
  • possibly QSA indexer state.

If those aren't widened into the (1 + n_rs_seq) snapshot groups, an equal-split replay would restore the GDN state but replay over stale conv/indexer state — consistent with the mismatch appearing early (pos 16) on seq 0.

Why it matters

On hybrid-recurrent archs, server spec decode with --parallel N currently pays a large serialization cost without rollback snapshots. Measured on a GB10 (Grace-Blackwell, 128 GB unified, CUDA sm_121) with Qwen3.8-Flash-Next IQ4_XS + --spec-type ngram-map-k4v --parallel 3: three concurrent streams reach only ~50 tok/s aggregate on rewrite-style workloads vs ~66–70 with speculation disabled — speculation inverts under concurrency. Batched rollback is the structural fix, and it's blocked on this arch by the missing snapshot coverage.

Secondary observation while in this code: common_params_speculative::need_n_rs_seq() only arms n_rs_seq for the draft-model spec types (MTP/EAGLE3/DFLASH/DSPARK). Is there a reason the ngram-* types are excluded? They hit the same partial-acceptance rollback path.

Offer

Happy to test patches on GB10 hardware — the repro takes ~2 minutes here and I can also run before/after server throughput numbers (--parallel 3, ngram spec) on the same box.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions