Repository navigation
[Bugfix][GDN] Fix CuteDSL BF16 KKT inversion divergence - #53864
Conversation
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
|
@Zoe923 Thanks for the PR! I haven't checked but I think recent FlashInfer releases have a better GDN prefill kernel, hence I'm thinking about removing this kernel entirely. Have you checked it out? Otherwise, can you rebase the PR then I will be happy to start the CI. |
c1cbd42 to
3e4d1b8
Compare
|
/ci run |
|
❌ This PR is 15 commits behind upstream |
3e4d1b8 to
9eccc0d
Compare
|
/ci run |
|
❌ This PR is 3 commits behind upstream |
|
btw i reran microbenchmarks against FlashInfer GDN prefill and didn't see improvements from last time i checked it. so at least the vLLM CuteDSL kernel is still useful in some cases against the current FlashInfer release in vLLM |
Use a fourth Newton-Schulz correction round to prevent numerical divergence for correlated-key KKT blocks. Add a deterministic regression test
that reproduces the three-round failure.
Signed-off-by: Zoe923 <871844693@qq.com>
9eccc0d to
e95653b
Compare
|
/ci run |
|
✅ Triggered Buildkite CI #89639 for commit |
|
@gau-nernst Thank you for your continued help in triggering CI. I apologize for the delay; I was just rebasing and testing the new Flashinfer.Thanks for the pointer. You are right that my original evaluation did not cover the recent FlashInfer Blackwell GDN prefill path. The original tests used FlashInfer 0.6.8.post1 with PyTorch CUDA 12.9 on SM103. The newer SM100/SM103 FlashInfer GDN implementation landed later, so the previous results should only be interpreted as a comparison against the stack available at that time. I have now tested FlashInfer 0.6.18.post1 with CUTLASS DSL 4.7.1 and CUDA 13 on NVIDIA L20D / SM103, using the Qwen3.5-397B TP2 GDN shapes (Hq=8, Hv=32, K=V=128). Compared with the current in-tree CuteDSL kernel, FlashInfer was:
All outputs and final states were finite. Against the FLA reference, output cosine similarity was 0.9999849–0.9999862 and final-state cosine similarity was 0.9999904–0.9999909. Therefore, I agree that the recent FlashInfer kernel is preferable for most of the tested long-prompt shapes in a CUDA 13 environment. However, our current production Blackwell/B300 deployment still uses PyTorch CUDA 12.9. I also tested FlashInfer 0.6.18.post1 in that exact CUDA 12.9 environment:
Consequently, recent FlashInfer cannot currently replace the CuteDSL backend in our CUDA 12.9 production environment. Our production port of the in-tree CuteDSL implementation has been validated on CUDA 12.9 by using the CUTLASS DSL cu13 bindings, and this compatibility is the main reason it is still useful to us. I have not yet completed a full Qwen3.5-397B end-to-end/UDF validation with the CUDA 13 FlashInfer stack, so I would not claim complete replacement based only on the kernel benchmark. That said, if the project decides to remove the in-tree CuteDSL backend after validating the CUDA 13 FlashInfer path, I understand and am fine with this PR being superseded or closed. While the backend remains, this PR still fixes its correlated-key BF16 numerical stability issue. I have rebased the PR onto the latest upstream main. The new head is e95653b, and the focused CuteDSL GDN tests pass (7 passed on CUDA 12.9 / SM103). The branch is ready for CI. |
|
Oh glad to hear that this kernel is being used in production. It's fine, we can merge this PR, and keep the kernel probably at least until CUDA 12.9 is dropped in vLLM I was using cutedsl 4.6.2 in an old environment so it didn't run the new CP kernel i think lol. |
|
I just double-checked again. It seems like your timing doesn't include the extra processing required for FlashInfer done in vLLM currently? That includes |
|
You are right. I rechecked the benchmark (Compared with CuteDSL kernel, FlashInfer before): This does not affect the results in the PR body: the three-to-four-round CuteDSL overhead, CuteDSL-versus-FLA kernel results, end-to-end performance, and correctness validation remain valid. Thanks for catching this. |
|
Np, just want to confirm on the benchmark methodology of flashinfer. The PR is good as is |
…#53864) Signed-off-by: Zoe923 <871844693@qq.com>

Purpose
End-to-end impact
This is an end-to-end correctness bug, not only a synthetic numerical issue.
On Qwen3.5-397B-A17B-FP8, the current three-round CuteDSL GDN prefill kernel can cause deterministic greedy generation to diverge catastrophically from the FLA backend. In one affected real business request with a 9,991-token prompt, the three-round implementation returned an empty output under an otherwise identical serving configuration.
Changing only the Newton-Schulz correction count from three to four restored the affected request to the expected FLA output. After the fix:
Therefore, the fourth Newton-Schulz round fixes a model-level correctness failure while preserving the performance advantage of the CuteDSL backend.
Here, "exact" refers to generated response strings under deterministic greedy decoding. The intermediate GDN output and state tensors are numerically close to FLA, but are not bitwise identical.
Numerical root cause and fix
The CuteDSL GDN prefill kernel currently computes the inverse of each 16x16 lower-triangular KKT diagonal block using three Newton-Schulz correction rounds with BF16 intermediates.
Three rounds are sufficient for this block size in exact arithmetic. However, they are not always sufficient when the intermediate inverse is stored back in BF16 after every round. Highly correlated keys can produce non-normal KKT blocks with transient growth. In these cases, the third round may finish before the BF16 cancellation has converged, causing a large inverse error that propagates into the GDN state and output.
This was observed in both synthetic and real-model inputs:
752.116699with the three-round implementation.98.5014.This PR adds one Newton-Schulz correction round, changing the iteration count from three to four.
The fourth round does not change the GDN mathematical definition, tensor layout, metadata, or public API. It only improves convergence of the existing BF16 inverse approximation.
A deterministic regression test is also added. It constructs a 64-token case with highly correlated normalized keys,
beta=0.9,g=0, and a zero FP32 initial state. This input reliably exposes the three-round failure and verifies that the output and final state remain finite and within the expected error bounds.Four rounds were selected as the minimum sufficient fix:
98.50141.707e-30.0437011.139e-40.00781251.130e-4The fifth round further reduces the maximum error, but provides almost no improvement in the mean error. Four rounds therefore provide the best correctness/performance trade-off observed in the tested inputs.
Performance impact
The additional correction round adds approximately
0.38%average latency to the local CuteDSL GDN prefill kernel compared with the three-round implementation.Despite this small cost, the corrected four-round CuteDSL kernel remains
2.09xto3.20xfaster than the FLA reference across the tested Qwen3.5 GDN shapes.End-to-end Qwen3.5-397B-A17B-FP8 testing also retained a positive performance improvement over FLA:
+2.47%8.25%2.41%+2.69%7.60%2.63%+3.37%6.79%3.28%+7.32%6.19%7.04%The backend was also tested with 200 requests at each client concurrency from 16 to 200. Both sides used TP2, MTP disabled, a 10k-token scheduler budget,
max_num_seqs=220, unique cache salts, and zero prefix-cache hits.+9.16%-1.01%8.23%+8.72%8.38%8.05%+7.31%5.73%6.86%+8.68%8.14%8.00%+11.07%10.86%10.39%+7.39%6.25%6.80%+9.50%8.94%8.95%+6.36%7.02%6.65%+8.30%7.70%7.73%+8.36%10.10%9.35%Across these ten points, total throughput improved by
8.49%on average and mean latency improved by8.10%on average. C16 mean TTFT regressed by1.01%, which is within the observed run-to-run variance, while its mean latency still improved by8.23%. Every concurrency point completed 200/200 requests successfully, and all 2,000 CuteDSL responses matched their FLA counterparts character-for-character.The three-round implementation was not used as an end-to-end performance baseline because it produced incorrect model outputs. Its incremental cost was measured at the kernel level instead.
Test Plan
GPU regression tests
Run the existing parameterized CuteDSL/FLA comparisons together with the new correlated-key stability regression:
The tests cover:
num_seqs = 1, 5, 257Real hidden-state replay
Replay captured GDN inputs from all 45 GDN layers of Qwen3.5-397B-A17B-FP8 on both TP ranks:
End-to-end validation
Run 50 real prompts at concurrency 1, 2, 4, and 8 with:
Compare all generated responses character-for-character.
For high-concurrency validation, run 200 requests at client concurrency 16, 32, 64, 128, 136, 144, 160, 176, 192, and 200. Use unique cache salts and compare each CuteDSL response against the corresponding FLA response.
Test Result
GPU regression
With the original three-round implementation, the new regression test fails as expected:
With the fourth correction round:
Real hidden-state replay
All 90 layer/rank captures remained finite and passed the error gates.
Worst observed values:
2.662e-50.238%2.984e-40.497%End-to-end correctness
The four concurrency groups produced 200 responses in total:
All 200 CuteDSL responses matched their corresponding FLA responses character-for-character. No empty output, malformed text, Unicode replacement characters, or prefix-cache hits were observed.
The high-concurrency matrix completed 200/200 requests at every point from C16 through C200. All 2,000 CuteDSL responses matched FLA exactly. No HTTP 409 response, timeout, OOM, kernel error, malformed output, or prefix-cache hit was observed with the API concurrency limit set to 256.
Static checks
The applicable checks passed:
No documentation update is required because this PR only changes the finite-precision convergence of an existing internal kernel and adds a regression test.
AI assistance was used during failure analysis, regression-test development, and preparation of this PR description. The author reviewed the code changes and independently validated all reported test results.
Essential Elements of an Effective PR Description Checklist