@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 42d440c22b
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 15, 02:15 UTC

[Perf] Use Triton instead of Torch for DeepGEMM Per Token Group Quant (#20841)

Signed-off-by: yewentao256 <zhyanwentao@126.com>

Wentao Ye committed Jul 12, 2025 at 22:38 UTC 42d440c22bc85a95dc457d4a0970507f8e66f0da
6 files changed +26 -42
tests/kernels/moe/test_deepgemm.py
+4 -3
@@ -13,9 +13,10 @@ import torch
13
14 # vLLM fused-expert reference (Triton fallback + DeepGEMM option)
15 from vllm.model_executor.layers.fused_moe.fused_moe import fused_experts
16 +from vllm.model_executor.layers.quantization.utils.fp8_utils import (
17 + per_token_group_quant_fp8)
18 from vllm.utils import has_deep_gemm
17 -from vllm.utils.deep_gemm import (calc_diff, per_block_cast_to_fp8,
18 - per_token_group_cast_to_fp8)
19 +from vllm.utils.deep_gemm import calc_diff, per_block_cast_to_fp8
20
21 BLOCK_SIZE = [128, 128]
22
@@ -81,7 +82,7 @@ def run_single_case(m, n, k, topk, num_experts, block_size):
82 """
83 tokens_bf16 = torch.randn(
84 m, k, device="cuda", dtype=torch.bfloat16).clamp_min_(-1).clamp_max_(1)
84 - _, a1_scale = per_token_group_cast_to_fp8(tokens_bf16, block_size[1])
85 + _, a1_scale = per_token_group_quant_fp8(tokens_bf16, block_size[1])
86
87 # expert weight tensors
88 w1, w2, w1_s, w2_s = make_block_quant_fp8_weights(num_experts, n, k,
tests/kernels/quantization/test_block_fp8.py
+2 -3
@@ -15,8 +15,7 @@ from vllm.model_executor.layers.quantization.utils.fp8_utils import (
15 w8a8_block_fp8_matmul)
16 from vllm.platforms import current_platform
17 from vllm.utils import has_deep_gemm
18 -from vllm.utils.deep_gemm import (fp8_gemm_nt, per_block_cast_to_fp8,
19 - per_token_group_cast_to_fp8)
18 +from vllm.utils.deep_gemm import fp8_gemm_nt, per_block_cast_to_fp8
19
20 if current_platform.get_device_capability() < (9, 0):
21 pytest.skip("FP8 Triton requires CUDA 9.0 or higher",
@@ -117,7 +116,7 @@ def test_w8a8_block_fp8_deep_gemm_matmul(M, N, K, block_size, out_dtype, seed):
116 A_fp32 = (torch.rand(M, K, dtype=torch.float32) - 0.5) * 2 * fp8_max
117 B_fp32 = (torch.rand(N, K, dtype=torch.float32) - 0.5) * 2 * fp8_max
118
120 - A_fp8, As_fp8 = per_token_group_cast_to_fp8(A_fp32, block_size[1])
119 + A_fp8, As_fp8 = per_token_group_quant_fp8(A_fp32, block_size[1])
120 B_fp8, Bs_fp8 = per_block_cast_to_fp8(B_fp32)
121
122 As = As_fp8.to(torch.float32)
vllm/model_executor/layers/fused_moe/deep_gemm_moe.py
+7 -6
@@ -15,9 +15,10 @@ from vllm.model_executor.layers.fused_moe.prepare_finalize import (
15 from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
16 TopKWeightAndReduceDelegate)
17 from vllm.model_executor.layers.fused_moe.utils import _resize_cache
18 +from vllm.model_executor.layers.quantization.utils.fp8_utils import (
19 + per_token_group_quant_fp8)
20 from vllm.utils import has_deep_gemm, round_up
19 -from vllm.utils.deep_gemm import (m_grouped_fp8_gemm_nt_contiguous,
20 - per_token_group_cast_to_fp8)
21 +from vllm.utils.deep_gemm import m_grouped_fp8_gemm_nt_contiguous
22
23 logger = init_logger(__name__)
24
@@ -170,10 +171,10 @@ class DeepGemmExperts(mk.FusedMoEPermuteExpertsUnpermute):
171 self.activation(activation, act_out, mm1_out.view(-1, N))
172
173 a2q_scale: Optional[torch.Tensor] = None
173 - a2q, a2q_scale = per_token_group_cast_to_fp8(act_out,
174 - self.block_shape[1],
175 - column_major_scales=True,
176 - out_q=quant_out)
174 + a2q, a2q_scale = per_token_group_quant_fp8(act_out,
175 + self.block_shape[1],
176 + column_major_scales=True,
177 + out_q=quant_out)
178
179 m_grouped_fp8_gemm_nt_contiguous((a2q, a2q_scale), (w2, w2_scale),
180 mm2_out, expert_ids)
vllm/model_executor/layers/fused_moe/utils.py
+1 -6
@@ -15,8 +15,6 @@ from vllm.model_executor.layers.quantization.utils.mxfp4_utils import (
15 from vllm.platforms import current_platform
16 from vllm.triton_utils import tl, triton
17 from vllm.utils import cdiv
18 -from vllm.utils.deep_gemm import (is_blackwell_deep_gemm_used,
19 - per_token_group_cast_to_fp8)
18
19
20 @triton.jit
@@ -119,10 +117,7 @@ def _fp8_quantize(
117 assert not per_act_token
118 assert len(block_shape) == 2
119 _, block_k = block_shape[0], block_shape[1]
122 - if is_blackwell_deep_gemm_used():
123 - A, A_scale = per_token_group_cast_to_fp8(A, block_k)
124 - else:
125 - A, A_scale = per_token_group_quant_fp8(A, block_k)
120 + A, A_scale = per_token_group_quant_fp8(A, block_k)
121 assert cdiv(A.size(-1), block_k) == A_scale.size(-1)
122
123 return A, A_scale
vllm/model_executor/layers/quantization/utils/fp8_utils.py
+12 -3
@@ -20,6 +20,7 @@ from vllm.model_executor.layers.quantization.utils.w8a8_utils import (
20 from vllm.platforms import current_platform
21 from vllm.triton_utils import tl, triton
22 from vllm.utils import cdiv, direct_register_custom_op, has_deep_gemm
23 +from vllm.utils.deep_gemm import is_blackwell_deep_gemm_used
24
25 logger = init_logger(__name__)
26
@@ -256,6 +257,7 @@ def _per_token_group_quant_fp8(
257 # Information for float8
258 fp8_min,
259 fp8_max,
260 + use_ue8m0: tl.constexpr,
261 # Meta-parameters
262 BLOCK: tl.constexpr,
263 ):
@@ -285,7 +287,8 @@ def _per_token_group_quant_fp8(
287 y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32)
288 # Quant
289 _absmax = tl.maximum(tl.max(tl.abs(y)), eps)
288 - y_s = _absmax / fp8_max
290 + scale_raw = _absmax / fp8_max
291 + y_s = tl.math.exp2(tl.ceil(tl.log2(scale_raw))) if use_ue8m0 else scale_raw
292 y_q = tl.clamp(y / y_s, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty)
293
294 tl.store(y_q_ptr + cols, y_q, mask=mask)
@@ -309,6 +312,7 @@ def _per_token_group_quant_fp8_colmajor(
312 # Information for float8
313 fp8_min,
314 fp8_max,
315 + use_ue8m0: tl.constexpr,
316 # Meta-parameters
317 BLOCK: tl.constexpr,
318 ):
@@ -347,7 +351,8 @@ def _per_token_group_quant_fp8_colmajor(
351 y = tl.load(y_ptr + cols, mask=mask, other=0.0).to(tl.float32)
352 # Quant
353 _absmax = tl.maximum(tl.max(tl.abs(y)), eps)
350 - y_s = _absmax / fp8_max
354 + scale_raw = _absmax / fp8_max
355 + y_s = tl.math.exp2(tl.ceil(tl.log2(scale_raw))) if use_ue8m0 else scale_raw
356 y_q = tl.clamp(y / y_s, fp8_min, fp8_max).to(y_q_ptr.dtype.element_ty)
357
358 tl.store(y_q_ptr + cols, y_q, mask=mask)
@@ -373,9 +378,11 @@ def per_token_group_quant_fp8(
378 is supported for now.
379 column_major_scales: Outputs scales in column major.
380 out_q: Optional output tensor. If not provided, function will create.
376 - Returns:
381 tuple[torch.Tensor, torch.Tensor]: The quantized tensor and the
382 scaling factor for quantization.
383 + Returns:
384 + tuple[torch.Tensor, torch.Tensor]: The quantized tensor and the
385 + scaling factor.
386 """
387 dtype = current_platform.fp8_dtype() if dtype is None else dtype
388 assert (x.shape[-1] % group_size == 0), (
@@ -418,6 +425,7 @@ def per_token_group_quant_fp8(
425 eps,
426 fp8_min=fp8_min,
427 fp8_max=fp8_max,
428 + use_ue8m0=is_blackwell_deep_gemm_used(),
429 BLOCK=BLOCK,
430 num_warps=num_warps,
431 num_stages=num_stages,
@@ -433,6 +441,7 @@ def per_token_group_quant_fp8(
441 eps,
442 fp8_min=fp8_min,
443 fp8_max=fp8_max,
444 + use_ue8m0=is_blackwell_deep_gemm_used(),
445 BLOCK=BLOCK,
446 num_warps=num_warps,
447 num_stages=num_stages,
vllm/utils/deep_gemm.py
-21
@@ -49,7 +49,6 @@ if not has_deep_gemm():
49 _fp8_gemm_nt_impl: Callable[..., Any] | None = None
50 _grouped_impl: Callable[..., Any] | None = None
51 _grouped_masked_impl: Callable[..., Any] | None = None
52 - _per_token_cast_impl: Callable[..., Any] | None = None
52 _per_block_cast_impl: Callable[..., Any] | None = None
53 else:
54 _dg = importlib.import_module("deep_gemm") # type: ignore
@@ -74,12 +73,9 @@ else:
73 try:
74 _math_mod = importlib.import_module(
75 "deep_gemm.utils.math") # type: ignore
77 - _per_token_cast_impl = getattr(_math_mod, "per_token_cast_to_fp8",
78 - None)
76 _per_block_cast_impl = getattr(_math_mod, "per_block_cast_to_fp8",
77 None)
78 except ModuleNotFoundError:
82 - _per_token_cast_impl = None
79 _per_block_cast_impl = None
80
81
@@ -101,22 +97,6 @@ def fp8_m_grouped_gemm_nt_masked(*args, **kwargs):
97 return _grouped_masked_impl(*args, **kwargs)
98
99
104 -def per_token_group_cast_to_fp8(x, group_size, *args, **kwargs):
105 - """Wrapper for token-wise FP8 quantisation.
106 -
107 - • If DeepGEMM provides ``per_token_cast_to_fp8`` (new API), use it.
108 - • Otherwise, fall back to vLLM's ``per_token_group_quant_fp8``
109 - """
110 -
111 - if _per_token_cast_impl is not None and is_blackwell_deep_gemm_used():
112 - assert group_size == 128, "group_size must be 128 for deepgemm"
113 - return _per_token_cast_impl(x)
114 -
115 - from vllm.model_executor.layers.quantization.utils.fp8_utils import (
116 - per_token_group_quant_fp8 as _ptg)
117 - return _ptg(x, group_size, *args, **kwargs)
118 -
119 -
100 def per_block_cast_to_fp8(x, *args, **kwargs):
101 if _per_block_cast_impl is not None and is_blackwell_deep_gemm_used():
102 return _per_block_cast_impl(x)
@@ -146,7 +126,6 @@ __all__ = [
126 "fp8_gemm_nt",
127 "m_grouped_fp8_gemm_nt_contiguous",
128 "fp8_m_grouped_gemm_nt_masked",
149 - "per_token_group_cast_to_fp8",
129 "per_block_cast_to_fp8",
130 "is_blackwell_deep_gemm_used",
131 ]