[Kernel] Add FlashInfer TRTLLM MXFP8 linear backend - #52204
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. 🚀 |
|
@claude review |
8f90950 to
d7c8714
Compare
|
Documentation preview: https://vllm--52204.org.readthedocs.build/en/52204/ |
Expose the TRTLLM MXFP8 dense GEMM path behind the existing flashinfer_trtllm linear backend selector. Prepare weights and scales once at load time, preserve the actual activation row count, and restore logical output dimensions after physical N padding. Assisted-by: OpenAI Codex Signed-off-by: seonjinn <sna@nvidia.com>
d7c8714 to
37d19a7
Compare
…m-linear-main Signed-off-by: seonjinn <sna@nvidia.com>
| `vllm serve --help=KernelConfig`. | ||
|
|
||
| !!! note | ||
| For MXFP8 checkpoints on SM100, SM103, and SM107 GPUs, BF16 models can |
There was a problem hiding this comment.
Updated to "models quantized to MXFP8 with BF16 activations" to distinguish the weight format from the activation dtype.
| possible = list(_POSSIBLE_MXFP8_KERNELS.get(platform, [])) | ||
| possible = [ | ||
| kernel | ||
| for kernel in _POSSIBLE_MXFP8_KERNELS.get(platform, []) | ||
| if kernel is not FlashInferTrtllmMxfp8LinearKernel | ||
| ] | ||
|
|
||
| if _get_linear_backend() == "flashinfer_trtllm": | ||
| possible.append(FlashInferTrtllmMxfp8LinearKernel) |
There was a problem hiding this comment.
Maybe you could add it to the bottom of _POSSIBLE_MXFP8_KERNELS if you don't want this chosen by default? I'd prefer to not have a special case
There was a problem hiding this comment.
Done. The kernel is now the last CUDA MXFP8 candidate, and the special-case selection logic is removed.
| if x.dtype != torch.bfloat16: | ||
| raise ValueError( | ||
| "FlashInfer TRTLLM MXFP8 requires bfloat16 output, " | ||
| f"got input dtype {x.dtype}." | ||
| ) |
There was a problem hiding this comment.
Done. Replaced the BF16 dtype ValueError with an assertion.
| weight = layer.weight # shuffled [padded N, K] | ||
| weight_scale = layer.weight_scale | ||
| _, K = weight.shape | ||
| output_size = layer._mxfp8_trtllm_output_size | ||
| input_shape = x.shape | ||
| input_2d = x.view(-1, K) | ||
|
|
||
| input_mxfp8, input_scale = vllm_flashinfer.flashinfer_mxfp8_quantize_8x4( | ||
| input_2d | ||
| ) | ||
| output = vllm_flashinfer.mm_mxfp8( | ||
| input_mxfp8, | ||
| weight.t(), | ||
| input_scale, | ||
| weight_scale, | ||
| out_dtype=x.dtype, | ||
| backend="trtllm", | ||
| use_8x4_sf_layout=True, | ||
| ) | ||
| if output.shape[-1] != output_size: | ||
| output = output[:, :output_size].contiguous() |
There was a problem hiding this comment.
Are we missing padding the input to match the weight?
There was a problem hiding this comment.
No input padding is needed. Only N is padded, so the operands remain A[M, K] and B[K, padded_N]; the result is sliced back to N. The 8x4 quantizer handles M-side scale-layout padding internally.
| if compute_capability is None: | ||
| supported_capability = any( | ||
| current_platform.is_device_capability(capability) | ||
| for capability in (100, 103, 107) | ||
| ) | ||
| else: | ||
| supported_capability = compute_capability in (100, 103, 107) | ||
| if not supported_capability: | ||
| return False, "requires sm_100/sm_103/sm_107 (Blackwell)" |
There was a problem hiding this comment.
nit: can just do current_platform.is_device_capability_family(100)
There was a problem hiding this comment.
Done. The kernel and its GPU test now use the SM100-family capability helper.
There was a problem hiding this comment.
I think a lot of these mocked tests are overkill
There was a problem hiding this comment.
I removed this part
There was a problem hiding this comment.
Reduced the mocked CPU suite from 252 lines to one backend-selection test. Numerics, padding, custom-op checks, and CUDA Graph coverage remain in the real GPU tests.
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: seonjinn <sna@nvidia.com>
Signed-off-by: Misha Goin <mgoin64@gmail.com>
|
/ci run |
|
✅ @seonjinn, CI is now available for this PR.
|
|
✅ Triggered Buildkite CI #84669 for commit |
|
Hi @seonjinn, the pre-commit checks have failed. Please run: uv pip install pre-commit>=4.5.1
pre-commit install
pre-commit run --all-filesThen, commit the changes and push to your branch. For future commits, |
Signed-off-by: seonjinn <sna@nvidia.com>
|
/ci run |
|
✅ Triggered Buildkite CI #84684 for commit |
|
@mgoin For amd-mi300-v1-spec-decode test case, does it take longer time usually? |
Signed-off-by: seonjinn <sna@nvidia.com> Signed-off-by: Misha Goin <mgoin64@gmail.com> Co-authored-by: Misha Goin <mgoin64@gmail.com> Signed-off-by: Zhu, Zufang <zufang.zhu@intel.com>
Signed-off-by: seonjinn <sna@nvidia.com> Signed-off-by: Misha Goin <mgoin64@gmail.com> Co-authored-by: Misha Goin <mgoin64@gmail.com>
Purpose
FlashInfer exposes a TensorRT-LLM backend for dense MXFP8 GEMM, but vLLM's
flashinfer_trtllmlinear selector currently covers NVFP4 only. This changeadds
FlashInferTrtllmMxfp8LinearKernel, which can be selected with:The kernel prepares TensorRT-LLM weight and scale layouts once after weight
loading. At runtime it quantizes BF16 activations with the 8x4 scale layout,
calls FlashInfer's TensorRT-LLM MXFP8 GEMM, and slices the physically padded
output back to its logical width before adding bias.
The kernel is the last CUDA entry in the MXFP8 priority list, so existing
kernels retain their normal priority. Explicit
flashinfer_trtllmselectionfilters the list to this kernel. This PR does not add tactic hints, MoE kernel
changes, or the high-M 128x4 activation-scale path.
No matching open PR was found with the searches
MXFP8 TRTLLM linearandmm_mxfp8 trtllm. The closest merged implementations are the NVFP4 TRTLLMlinear backend (#39129) and the MXFP8 CuTeDSL linear backend (#46393). Open PR
#52016 adds the independent B12X CuTeDSL package for SM120/SM121 and does not
expose FlashInfer's TensorRT-LLM MXFP8 runner.
Test Result
The GB200 test passed five real-GPU cases: three numerical shapes with M=1,
7, and 128, custom-op checks, and CUDA Graph capture and replay. The N=130
cases cover physical output padding and slicing. The run used commit
37d19a7edd7559c3f8da24703d53feea198f96b4and FlashInfer 0.6.16.post3,matching the vLLM dependency pin. Model-level accuracy and same-version
performance results are not yet available, so this PR makes no accuracy or
performance claim.