Skip to content

fix(serving): pin cuBLAS/cuDNN to deterministic modes for batch-shape invariance - #44094

Closed
Asthenia0412 wants to merge 3 commits into
sgl-project:mainfrom
Asthenia0412:fix-qwen3-batch-shape-43956
Closed

Asthenia0412 wants to merge 3 commits into
sgl-project:mainfrom
Asthenia0412:fix-qwen3-batch-shape-43956

Conversation

@Asthenia0412

@Asthenia0412 Asthenia0412 commented Oct 13, 2026 •

Copy link
Copy Markdown

Summary

Fixes numerical drift across batch shapes reported in #43956: Qwen3.8-27B scores change enough to flip borderline decisions (FP8 / BF16) when the same token IDs are placed into different batch sizes.

Root cause

The reporter isolated the first projection drift to a pure-PyTorch torch.nn.functional.linear (BF16 x BF16 → BF16) in model.language_model.layers.0.linear_attn.in_proj_ba. A BF16 intermediate dot product was near the rounding boundary and cuBLAS chose a different reduction order for different M/N/K shapes — this crossed the boundary and the difference propagated through the network. With FP8 checkpoints and the default BF16 LM head the drift reached 12.2 percentage points on a 0.5 P(positive) tie.

torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = False alone does not help because the problem is reduction order, not reduced-precision reduction.

Fix

Wire cuBLAS and cuDNN determinism into the existing --enable-deterministic-inference code path in the argument-resolution pipeline:

  1. CUBLAS_WORKSPACE_CONFIG=:4096:8 — forces cuBLAS to pick the deterministic algorithm variant for every GEMM call, regardless of M/N/K shape. This is the primary fix and is set before any cuBLAS lazy initialisation.
  2. CUDNN_DETERMINISTIC=1 / CUDNN_BENCHMARK=0 plus the equivalent torch.backends.cudnn attributes.
  3. torch.use_deterministic_algorithms(True, warn_only=True) with flash-/mem-efficient-SDP disabled and allow_bf16_reduced_precision_reduction=False so remaining PyTorch ops with shape-dependent behaviour are pinned to deterministic code paths.

All three env vars are applied:

  • First in handle_deterministic_inference (pipeline step 228 of 351) — the earliest deterministic hook, well before model load or any GEMM.
  • Then again via setdefault in handle_environment_variables (step 318) as a belt-and-braces guard for code paths that might initialise cuBLAS between the two steps. setdefault preserves the earlier hook’s values.

Testing

I don’t have access to the reported H20 environment, so verification will need to come from the reporter’s existing reproduction script. The fix is additive to the existing --enable-deterministic-inference flag and a no-op when that flag is not set.

Related

Closes #43956.


CI States

Latest PR Test (Base): ❌ Run #38444677950
Latest PR Test (Extra): ❌ Run #38444677764
Latest PR Test (AMD ROCm 10): ❌ Run #38444677940

yancy added 3 commits October 13, 2026 15:48
…nd for fp4 on SM100 (Blackwell)

FP4 Marlin is weight-only (W4A16) and does not support W4A4 GEMM.
FlashInfer's mm_fp4 rejects backend='marlin' on SM100+ with:
    BackendSupportedError: mm_fp4 does not support backend 'marlin' with capability 100

When the user explicitly passes --fp4-gemm-backend marlin on Blackwell GPUs,
or auto-selection unexpectedly chooses marlin, fall back to flashinfer_cutedsl
(SM100) or flashinfer_cutlass (other SM12x) with a clear warning.

Fixes: #43988

Signed-off-by: yancy <yancy@users.noreply.github.com>
…eterministic-inference

Issue #43956 reports that Qwen3.8-27B scores change with batch shape under
BF16 and FP8 checkpoints, enough to flip borderline decisions. The root
cause is cuBLAS picking a different GEMM reduction order for different
M/N/K shapes, which crosses a BF16 rounding boundary on identical inputs.

The fix does three things whenever --enable-deterministic-inference is set:

1. Sets CUBLAS_WORKSPACE_CONFIG=:4096:8 so cuBLAS resolves every GEMM call
   to its deterministic algorithm variant. This is the primary fix and must
   be applied before cuBLAS is lazily initialised, so the env var is set at
   the very top of the pipeline's deterministic hook (step 228 of 351).

2. Sets CUDNN_DETERMINISTIC=1 and CUDNN_BENCHMARK=0, plus the equivalent
   torch.backends.cudnn attributes, to keep cuDNN convolutions consistent
   across shapes.

3. Calls torch.use_deterministic_algorithms(True, warn_only=True) and pins
   flash- / mem-efficient-SDP and allow_bf16_reduced_precision_reduction so
   any remaining PyTorch ops that have shape-dependent behaviour are forced
   onto deterministic paths.

All three env vars are also set in handle_environment_variables (step 318)
as a belt-and-braces guard — setdefault means the earlier hook still wins
when both run, but any code path that initialises cuBLAS between steps 228
and 318 is still covered.

Signed-off-by: yancy <yancy@users.noreply.github.com>
…fp4_utils.py

Signed-off-by: yancy <yancy@users.noreply.github.com>
@Asthenia0412

Copy link
Copy Markdown
Author

🤖 CI gating notice: This PR's checks (call-gate/pr-gate, pr-test-*-finish) fail because this repo requires a run-ci label to trigger the actual test matrix. The failed jobs are just CI gating placeholders — real tests haven't run yet.

@Asthenia0412

Copy link
Copy Markdown
Author

Hi! The CI currently shows skipped jobs because this repo requires the run-ci label to trigger the full test suite. The failing jobs you see are just the CI gating placeholders (call-gate/pr-gate, pr-test-*-finish) — real tests haven't run yet.

Could someone please add the run-ci label to kick off the actual test matrix? Thanks so much! 🙏

@lm-sys @zhyncs @hnyls2002 @ispobock @BBuf @Fridge003 @kevin-mii

@hnyls2002

Copy link
Copy Markdown
Collaborator

Thanks for your interest in SGLang. This account opened 16 PRs in about eight hours, across unrelated subsystems (attention backends, speculative decoding, diffusion loading, scheduler IPC, KV-cache compression, docs), including two PRs for the same change (#44073 and #44117, both for #28808) and a fix for #43929 that is already on main. We can't review contributions at this volume, so we are closing the ones still open. If you want to pursue one, please pick a single change, verify it on a real run (a repro, a test, or numbers), and open a fresh PR.

@hnyls2002 hnyls2002 closed this Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Qwen3.8-27B scores depend on batch shape and can change borderline decisions (FP8 and BF16)

3 participants