Hybrid linear-attention (Qwen3.5/Qwen3-Next) KV cache spec + prefix-caching guard#1
Open
Carlos-Marques wants to merge 11 commits into
Open
Hybrid linear-attention (Qwen3.5/Qwen3-Next) KV cache spec + prefix-caching guard#1Carlos-Marques wants to merge 11 commits into
Carlos-Marques wants to merge 11 commits into
Conversation
…efix-caching guard Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
…ror) Linear-attention (DeltaNet) layers have constant-size recurrent state managed by NxDI, not vLLM's block manager. Reporting MambaSpec for them triggered ValueError in unify_hybrid_kv_cache_specs when the Hybrid KV cache Manager (HMA) is disabled (always on the Neuron path). Fix: only report FullAttentionSpec for actual attention layers. Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
When the CTE bucket is smaller than the prompt (e.g., bucket=128 but prompt=7500 tokens), split the prompt into max_context_length-sized chunks and feed each through context_encoding_model directly. DeltaNet layers accumulate recurrent state correctly across passes. Also overrides max_prompt_length validation to allow prompts up to max_model_len through the scheduler when multi-pass CTE is active. Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
ModelWrapper.pad_inputs expects args[1] (attention_mask) to be a tensor with shape (batch, seq_len). Passing None would crash on .shape[1]. Create an all-ones mask for each chunk since all tokens are valid. Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
…missing The V1 engine's step_with_batch_queue dispatches execute_model and sample_tokens as sequential non-blocking tasks. If execute_model raises, sample_tokens still runs and must return None so the engine can surface the real error via exec_model_fut.result(). Previously we raised RuntimeError which masked the actual forward() error. Also add diagnostic logging around execute_model to capture the real exception details. Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
The compiled CTE model expects prev_hidden with shape [batch_size], not [0]. torch.empty(0) produced shape [0] which wasn't in the input_shape_map. This caused the forward pass to fail with: ValueError: Input shape ... not found in input_shape_map Change to torch.zeros(batch_size) to match the compiled shape. Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
… diagnostics - prev_hidden: use int32 (matches _process_args default tracing dtype) - position_ids: use chunk-relative [0, chunk_len) instead of absolute positions to avoid potential KV workspace buffer overflow on device - Add print/flush diagnostic logging for crash visibility in EngineCore subprocess Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
context_encoding_model() returns the raw output tensor — sampled token IDs when on_device_sampling is enabled. The previous code tried to access .hidden_states on this tensor, which only exists when going through NeuronBaseForCausalLM.forward() (wraps in CausalLMOutputWithPast). Fixes: AttributeError: 'Tensor' object has no attribute 'hidden_states' Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
…ill step On Neuron the compiled model processes a fixed batch dimension regardless of how many positions hold real data (unused = zero-padded). Admitting only 1 request per prefill step wasted (batch_size - 1) positions on padding, multiplying total prefill time by batch_size. Default max_prompt_batch_size is now max_num_running_reqs (= max_num_seqs). Configurable via NEURON_MAX_PROMPT_BATCH_SIZE env var for A/B testing. For the Qwen3.5-4B benchmark (batch16, 60 requests × 7500 in / 500 out): old scheduler did 60 sequential 2.1s prefills (15/16 padded) → 126s blocked. New scheduler batches all 16 into one 2.1s prefill → 4 batches × 2.1s = 8.4s. Expected throughput lift: ~57% (97.77 → ~154 tok/s). Co-Authored-By: carlos <carlosmarques.personal@gmail.com>
…ng logs Co-Authored-By: carlos <carlosmarques.personal@gmail.com> Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Companion to exa-labs/neuronx-distributed-inference#1 (NxDI Qwen3.5/Qwen3-Next port). Makes the plugin's cache accounting correct for hybrid linear-attention models, where ~3/4 of layers (Gated DeltaNet) keep a constant-size per-sequence state instead of a growing KV cache.
Two changes:
NeuronxDistributedModelRunner.get_kv_cache_spec()no longer declaresFullAttentionSpecfor every layer. For models whosehf_config.layer_typescontains"linear_attention", those layers now get aMambaSpec:so vLLM's KV-cache manager budgets the real (constant) HBM footprint instead of 4x-overcounting and refusing admissible requests. State shapes come from
linear_num_{key,value}_heads/linear_{key,value}_head_dim/linear_conv_kernel_dim: conv state(2*Hk*Dk + Hv*Dv, kernel-1), recurrent state(Hv, Dk, Dv).NeuronPlatform.check_and_update_config()force-disables--enable-prefix-cachingfor hybrid models, since DeltaNet's recurrent state is a running summary at one position — KV blocks can't be reused at branch points and prefix caching would silently produce garbage. Disabling also routes into the existingblock_size = max_model_lencontiguous path.Non-hybrid models are unaffected (
layer_typesabsent → all layersFullAttentionSpec, guard no-ops).Testing
get_kv_cache_spec(per-layer spec types + state shapes) intest/unit/worker/test_model_runner.py; prefix-caching guard on/off + non-hybrid passthrough intest/unit/test_platform.py.pytest test/unit/test_platform.py test/unit/worker/test_model_runner.py→ 295 passed (vLLM 0.16.0, CPU).Link to Devin session: https://app.devin.ai/sessions/853f8dae8e27497a9a8ed7a1a6d347b0
Requested by: @Carlos-Marques