[ROCm] triton+triton_kernels 3.8 mxfp4 MoE support (gpt-oss + DeepSeek-V4) (#55934)

Signed-off-by: Rohan Potdar <rohan.potdar@amd.com>
Signed-off-by: Rohan138 <rohanpotdar138@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Matt <156021403+mawong-amd@users.noreply.github.com>
This commit is contained in:
Rohan Potdar
2026-09-16 20:03:34 -05:00
committed by GitHub
co-authored by Claude Opus 4.8 Matt
parent 95f4925c3a
commit 3e267bae70
9 changed files with 270 additions and 147 deletions
+5 -3
View File
@@ -5,7 +5,7 @@ ARG VLLM_BRANCH="main"
ARG COMMON_WORKDIR=/app
ARG BASE_IMAGE=rocm/vllm-dev:base
ARG CI_BASE_IMAGE=rocm/vllm-dev:ci_base
ARG ROCM_TRITON_KERNELS_COMMIT=0f380657dbf3ee86eb57558ff71df24f03b5d4e7
ARG ROCM_TRITON_KERNELS_COMMIT=669b31acc1dd1b3fd93286afd5db67f65d9f7557
ARG INSTALL_LMCACHE=false
# NIC backend for MoRI RDMA support.
# By default (all), drivers and userspace libraries for all supported NIC types
@@ -322,8 +322,9 @@ ENV SETUPTOOLS_SCM_PRETEND_VERSION="0.0.0+rocm.csrc.build"
RUN --mount=type=bind,source=pyproject.toml,target=${COMMON_WORKDIR}/vllm/pyproject.toml \
--mount=type=cache,id=vllm-rocm-ccache,target=/root/.cache/ccache \
grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
{ grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
cmake/external_projects/triton_kernels.cmake \
|| echo "WARNING: Dockerfile.rock ROCM_TRITON_KERNELS_COMMIT (${ROCM_TRITON_KERNELS_COMMIT}) does not match cmake TRITON_KERNELS_TAG; the Docker build uses the Dockerfile pin, cmake governs only non-Docker builds"; } \
&& export CCACHE_BASEDIR="$PWD" \
&& echo "=== ccache stats before ROCm native build ===" \
&& (ccache --show-stats || true) \
@@ -669,8 +670,9 @@ RUN if [ "$GIT_REPO_CHECK" != "0" ]; then \
# Install the packaging helpers before modifying requirements/rocm.txt.
RUN --mount=type=cache,target=/root/.cache/uv \
grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
{ grep -Fq "set(TRITON_KERNELS_TAG \"${ROCM_TRITON_KERNELS_COMMIT}\")" \
vllm/cmake/external_projects/triton_kernels.cmake \
|| echo "WARNING: Dockerfile.rock ROCM_TRITON_KERNELS_COMMIT (${ROCM_TRITON_KERNELS_COMMIT}) does not match cmake TRITON_KERNELS_TAG; the Docker build uses the Dockerfile pin, cmake governs only non-Docker builds"; } \
&& cd vllm \
&& uv pip install --system setuptools_scm regex
@@ -384,9 +384,8 @@ def test_routing_data_from_sparse_topk_parity(n_tokens, n_experts, topk):
make_routing_data = gptoss_moe.make_routing_data
routing_data_from_sparse_topk = gptoss_moe.routing_data_from_sparse_topk
use_legacy_triton_kernels = gptoss_moe.use_legacy_triton_kernels
if use_legacy_triton_kernels:
if gptoss_moe.triton_kernels_version == "3.5.1":
pytest.skip("SparseMatrix path requires triton_kernels v3.6.0+")
from triton_kernels.topk import topk as topk_fn
@@ -17,14 +17,19 @@ from vllm.model_executor.layers.quantization.utils.ocp_mx_utils import (
)
from vllm.model_executor.layers.quantization.utils.quant_utils import GroupShape
from vllm.platforms import current_platform
from vllm.utils.import_utils import has_triton_kernels
from vllm.utils.import_utils import get_triton_kernels_version
from vllm.utils.math_utils import cdiv
logger = init_logger(__name__)
if has_triton_kernels():
_triton_kernels_version = get_triton_kernels_version()
if _triton_kernels_version is not None:
try:
from triton_kernels.matmul_ogs import PrecisionConfig
if _triton_kernels_version == "3.8":
from triton_kernels.matmul import PrecisionConfig
else:
from triton_kernels.matmul_ogs import PrecisionConfig
except (ImportError, AttributeError) as e:
logger.error(
"Failed to import Triton kernels. Please make sure your triton "
@@ -12,9 +12,6 @@ from vllm.model_executor.layers.fused_moe.config import (
FusedMoEQuantConfig,
RoutingMethodType,
)
from vllm.model_executor.layers.fused_moe.experts.aiter_mxfp4_w4a8_moe import (
patch_gating_output,
)
from vllm.model_executor.layers.quantization.utils.quant_utils import (
QuantKey,
kMxfp4Static,
@@ -26,17 +23,6 @@ __all__ = [
]
def _aiter_raw(t):
"""Unwrap the `triton_kernels.tensor.Tensor` that `_swizzle_mxfp4` returns."""
if t is None or isinstance(t, torch.Tensor):
return t
assert hasattr(t, "storage"), (
f"expected a triton_kernels wrapped tensor with a .storage attribute, "
f"got {type(t)}"
)
return t.storage.data
def _aiter_w4a16_silu_via_a8w4(
hidden_states: torch.Tensor,
w1_data,
@@ -168,11 +154,6 @@ def aiter_triton_kernel_w4a16_moe_forward(
_routing_mod.is_tdm_avail = lambda: False
aiter_routing = _routing_mod.routing
# See context in #50859.
# TODO: Remove once https://github.com/ROCm/aiter/pull/4530 is merged,
# AITER released, and AITER pin in vLLM increased from 0.1.19.
gating_output = patch_gating_output(gating_output, global_num_experts)
if score_mode is not None:
use_grouped_topk = num_expert_group is not None and num_expert_group > 1
routing_data, gather_idx, scatter_idx = aiter_routing(
@@ -201,10 +182,14 @@ def aiter_triton_kernel_w4a16_moe_forward(
assert quant_config.w1_precision is not None
assert quant_config.w2_precision is not None
w1_data = _aiter_raw(w1)
w2_data = _aiter_raw(w2)
w1_wscale = _aiter_raw(quant_config.w1_precision.weight_scale)
w2_wscale = _aiter_raw(quant_config.w2_precision.weight_scale)
w1_data = w1.storage.data
w2_data = w2.storage.data
from vllm.model_executor.layers.quantization.utils.mxfp4_utils import (
weight_mx_scale,
)
w1_wscale = weight_mx_scale(quant_config.w1_precision).storage.data
w2_wscale = weight_mx_scale(quant_config.w2_precision).storage.data
gammas = routing_data.gate_scal if routing_data else None
@@ -5,7 +5,6 @@ import torch
import vllm.model_executor.layers.fused_moe.modular_kernel as mk
from vllm._aiter_ops import rocm_aiter_ops
from vllm.forward_context import get_forward_context, is_forward_context_available
from vllm.model_executor.layers.fused_moe.activation import MoEActivation
from vllm.model_executor.layers.fused_moe.config import (
FusedMoEConfig,
@@ -25,60 +24,6 @@ __all__ = [
]
# TODO(akaratza): Remove
# _get_padding_mask and patch_gating_output after
# https://github.com/ROCm/aiter/pull/4530 is released and consumed by vLLM.
def _get_padding_mask() -> torch.Tensor | None:
"""Retrieves a boolean mask with non-padding (0) and padding (1) tokens.
`slot_mapping < 0` comes from:
slot_mapping[num_tokens_unpadded:num_tokens_padded].fill_(-1)
in gpu_model_runner.py.
Direct kernel callers do not have model-runner padding metadata, so no
mask is needed when there is no forward context.
"""
if not is_forward_context_available():
return None
forward_context = get_forward_context()
# model runner v2.
if forward_context.is_padding is not None:
return forward_context.is_padding
# model runner v1.
slot_mapping = forward_context.slot_mapping
if isinstance(slot_mapping, list):
slot_mapping_dict = slot_mapping[0]
else:
slot_mapping_dict = slot_mapping
if isinstance(slot_mapping_dict, dict):
slot_mapping_sample = next(iter(slot_mapping_dict.values()), None)
if isinstance(slot_mapping_sample, torch.Tensor):
return slot_mapping_sample < 0
else:
return None
def patch_gating_output(
gating_output: torch.Tensor, global_num_experts: int
) -> torch.Tensor:
if global_num_experts != 128:
is_padding = _get_padding_mask()
if is_padding is not None:
assert is_padding.shape[0] == gating_output.shape[0]
gating_output = gating_output.masked_fill(is_padding[:, None], 0.0)
return gating_output
def aiter_triton_kernel_w4a8_moe_forward(
hidden_states: torch.Tensor,
w1, # Tensor or triton_kernels.Tensor
@@ -112,11 +57,6 @@ def aiter_triton_kernel_w4a8_moe_forward(
_routing_mod.is_tdm_avail = lambda: False
aiter_routing = _routing_mod.routing
# See context in #50859.
# TODO: Remove once https://github.com/ROCm/aiter/pull/4530 is merged,
# AITER released, and AITER pin in vLLM increased from 0.1.19.
gating_output = patch_gating_output(gating_output, global_num_experts)
routing_data, gather_idx, scatter_idx = aiter_routing(
gating_output, topk, sm_first=not renormalize
)
@@ -191,6 +131,7 @@ def triton_kernel_fused_mxfp4_w4a8_experts(
from vllm.model_executor.layers.quantization.utils.mxfp4_utils import (
should_use_cdna4_mx_scale_swizzle,
weight_mx_scale,
)
_swizzle_mx_scale = "CDNA4_SCALE" if should_use_cdna4_mx_scale_swizzle() else None
@@ -210,7 +151,7 @@ def triton_kernel_fused_mxfp4_w4a8_experts(
hidden_states,
w1.storage.data,
None,
quant_config.w1_precision.weight_scale.storage.data,
weight_mx_scale(quant_config.w1_precision).storage.data,
quant_config.w1_precision.flex_ctx.lhs_data.scale,
quant_config.w2_precision.flex_ctx.lhs_data.scale,
quant_config.w1_bias,
@@ -230,7 +171,7 @@ def triton_kernel_fused_mxfp4_w4a8_experts(
intermediate_cache1,
w2.storage.data,
None,
quant_config.w2_precision.weight_scale.storage.data,
weight_mx_scale(quant_config.w2_precision).storage.data,
quant_config.w2_precision.flex_ctx.lhs_data.scale,
None,
quant_config.w2_bias,
@@ -26,7 +26,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
)
from vllm.platforms import current_platform
from vllm.triton_utils import tl, triton
from vllm.utils.import_utils import has_triton_kernels
from vllm.utils.import_utils import get_triton_kernels_version, has_triton_kernels
from ..utils import swiglu_limit_func
@@ -441,48 +441,59 @@ def _patch_legacy_routing_for_nonpow2_topk() -> None:
_routing.sort_tokens = _sort_tokens_pow2
# Two API generations of triton_kernels are supported:
# - v3.5.1 (the version bundled with vLLM): exposes `routing()` and
# `routing_from_bitmatrix()` in triton_kernels.routing; the `Bitmatrix`
# constructor takes a `scratchpad` argument.
# - v3.6.0+: removes the `routing` module in favor of a `SparseMatrix`
# based path, and adds a `dtype=BIT` kwarg to `Bitmatrix`. Used only
# when the user has triton_kernels installed system-wide at v3.6.0+.
#
# `use_legacy_triton_kernels` selects between them at import time based on
# whether `SparseMatrix` is importable.
use_legacy_triton_kernels = False
triton_kernels_version = get_triton_kernels_version()
if has_triton_kernels():
if triton_kernels_version is not None:
try:
import triton_kernels.swiglu
from triton_kernels.matmul_ogs import (
FnSpecs,
FusedActivation,
GatherIndx,
RoutingData,
ScatterIndx,
matmul_ogs,
)
from triton_kernels.tensor import (
BIT,
Bitmatrix,
)
if triton_kernels_version == "3.8":
from triton_kernels.matmul import FnSpecs, FusedActivation, matmul
from triton_kernels.matmul_details.opt_flags import (
update_opt_flags_constraints,
)
from triton_kernels.tensor import make_ragged_tensor_metadata
from vllm.platforms.rocm import on_gfx950
if on_gfx950():
# block_n=64/block_k=256 fit gfx950's 160KB LDS + the CDNA4
# scale swizzle; block_m=32 avoids an autotuner block_m=128
# padding cliff (~15x) at decode-sized ragged MoE shapes.
update_opt_flags_constraints(
{"block_m": 32, "block_n": 64, "block_k": 256}
)
else:
from triton_kernels.matmul_ogs import (
FnSpecs,
FusedActivation,
GatherIndx,
RoutingData,
ScatterIndx,
matmul_ogs,
)
if triton_kernels_version == "3.6":
from triton_kernels.tensor import (
SparseMatrix,
make_ragged_tensor_metadata,
)
# BIT/Bitmatrix exist in v3.5.1/v3.6, gone in v3.8.
try:
from triton_kernels.tensor import (
SparseMatrix,
make_ragged_tensor_metadata,
BIT,
Bitmatrix,
)
except ImportError:
# TODO(mgoin): drop the v3.5.1 pin and remove this fallback once
# the gpt-oss perf regression in v3.6.0+ is resolved upstream.
# Tracking: https://github.com/triton-lang/triton/issues/9969
use_legacy_triton_kernels = True
if not use_legacy_triton_kernels:
BIT = None
Bitmatrix = None
# Patch the routing kernels for non-pow2 top_k (DeepSeek-V4 top_k=6);
# v3.8 rebuilds routing from topk ids and needs no patch.
if triton_kernels_version == "3.6":
_patch_make_bitmatrix_metadata()
else:
# Legacy routing fails to compile for non-pow2 top_k (DeepSeek-V4).
elif triton_kernels_version == "3.5.1":
_patch_legacy_routing_for_nonpow2_topk()
except (AttributeError, ImportError) as e:
logger.error(
@@ -492,6 +503,21 @@ if has_triton_kernels():
)
if triton_kernels_version == "3.8":
# 3.8's matmul dropped matmul_ogs's in-kernel scatter+topk-reduce, so the
# forward combines externally via index_add; this is the ragged routing
# bundle the (inlined) 3.8 paths pass around, in place of matmul_ogs's.
class RoutingData: # type: ignore[no-redef]
__slots__ = ("ragged", "gate_scal", "gather_tok", "n_expts_act", "n_valid")
def __init__(self, ragged, gate_scal, gather_tok, n_expts_act, n_valid):
self.ragged = ragged
self.gate_scal = gate_scal
self.gather_tok = gather_tok
self.n_expts_act = n_expts_act
self.n_valid = n_valid
@triton.jit
def pack_bitmatrix(
bitmatrix,
@@ -562,7 +588,7 @@ def triton_kernel_moe_forward(
# three separate kernels used by the generic path below.
# Only available in the legacy (v3.5.1) API; the v3.6.0+ path inlines
# equivalent logic via SparseMatrix in `make_routing_data`.
if use_legacy_triton_kernels and expert_map is None:
if triton_kernels_version == "3.5.1" and expert_map is None:
from triton_kernels.routing import routing as fused_routing
routing_data, gather_idx, scatter_idx = fused_routing(
@@ -662,6 +688,52 @@ def triton_kernel_fused_experts(
assert activation == MoEActivation.SWIGLUOAI, (
"Only SWIGLUOAI activation is supported"
)
if triton_kernels_version == "3.8":
# 3.8 has no in-kernel scatter+topk-reduce, so the two matmuls are
# followed by an external index_add combine.
assert quant_config is not None
M, K = hidden_states.shape[-2:]
a_ragged = routing_data.ragged
gather_tok = routing_data.gather_tok
gammas = routing_data.gate_scal
act = FusedActivation(
FnSpecs(
"swiglu",
triton_kernels.swiglu.swiglu_fn,
("alpha", "limit"),
reduction_n=2,
),
(swiglu_alpha, swiglu_limit),
)
inter = matmul(
hidden_states,
w1,
quant_config.w1_bias,
a_ragged,
None,
gather_tok,
None,
quant_config.w1_precision,
gammas=gammas if apply_router_weight_on_input else None,
fused_activation=act,
)
y = matmul(
inter,
w2,
quant_config.w2_bias,
a_ragged,
None,
None,
None,
quant_config.w2_precision,
gammas=None if apply_router_weight_on_input else gammas,
)
acc = torch.zeros((M, K), dtype=torch.float32, device=hidden_states.device)
acc.index_add_(0, gather_tok.to(torch.int64), y.to(torch.float32))
out = output_tensor.view(M, K)
out.copy_(acc.to(out.dtype))
return out
assert quant_config is not None
# type check, uint8 means mxfp4
@@ -704,7 +776,7 @@ def triton_kernel_fused_experts(
),
(swiglu_alpha, swiglu_limit),
)
if not use_legacy_triton_kernels
if triton_kernels_version != "3.5.1"
else FusedActivation(
FnSpecs("swiglu", triton_kernels.swiglu.swiglu_fn, ("alpha", "limit")),
(swiglu_alpha, swiglu_limit),
@@ -744,6 +816,24 @@ def make_routing_data(
topk_weights: torch.Tensor,
num_local_experts: int,
) -> tuple["RoutingData", torch.Tensor, torch.Tensor]:
if triton_kernels_version == "3.8":
_, topk = topk_ids.shape
flat_e = topk_ids.reshape(-1)
valid = flat_e >= 0
flat_e = flat_e.to(torch.int64).clamp(min=0)
flat_w = topk_weights.reshape(-1).to(torch.float32) * valid.to(torch.float32)
nrows = flat_e.shape[0]
order = torch.argsort(flat_e, stable=True)
col_sum = torch.zeros(
num_local_experts, dtype=torch.int32, device=flat_e.device
)
col_sum.scatter_add_(0, flat_e, torch.ones_like(flat_e, dtype=torch.int32))
ragged = make_ragged_tensor_metadata(col_sum, nrows)
gather_tok = (order // topk).to(torch.int32)
gammas = flat_w[order]
routing = RoutingData(ragged, gammas, gather_tok, topk, nrows)
return routing, gather_tok, gather_tok
topk_ids = topk_ids.to(torch.int16)
topk_weights = topk_weights.to(torch.bfloat16)
@@ -774,7 +864,7 @@ def make_routing_data(
Bitmatrix(
bitmatrix, dtype=BIT, shape=bitmatrix_shape, shape_max=bitmatrix_shape_max
)
if not use_legacy_triton_kernels
if triton_kernels_version != "3.5.1"
else Bitmatrix(
bitmatrix,
shape=bitmatrix_shape,
@@ -786,7 +876,7 @@ def make_routing_data(
# matmul_ogs expects invalid topk_weights to be -1s
topk_weights = torch.where(topk_ids == -1, -1.0, topk_weights)
if use_legacy_triton_kernels:
if triton_kernels_version == "3.5.1":
from triton_kernels.routing import routing_from_bitmatrix
return routing_from_bitmatrix(
@@ -809,6 +899,10 @@ def routing_data_from_sparse_topk(
call already produced; when the topk ids are used as-is (no expert-map
remapping) that work is redundant.
"""
if triton_kernels_version == "3.8":
# 3.8 routing is rebuilt from raw ids; no SparseMatrix reuse.
return make_routing_data(sparse_topk.indx, sparse_topk.vals, n_expts)
dispatch_indx = sparse_topk.mask_metadata.row_sorted_indx
combine_indx = sparse_topk.mask_metadata.col_sorted_indx
ragged_batch_metadata = make_ragged_tensor_metadata(
@@ -1197,6 +1291,50 @@ class UnfusedOAITritonExperts(LoRAExpertsMixin, BaseOAITritonExperts):
topk = topk_ids.size(1)
if triton_kernels_version == "3.8":
# Activation and topk-reduce kept unfused from the matmuls (3.8 has
# no in-kernel scatter+reduce); combine via external index_add.
assert self._lora_context is None, (
"tk38 unfused MoE path does not support LoRA yet"
)
act_out_dim = self.adjust_N_for_activation(w1.shape[2], activation)
M, K = hidden_states.shape[-2:]
a_ragged = routing_data.ragged
gather_tok = routing_data.gather_tok
gammas = routing_data.gate_scal
inter = matmul(
hidden_states,
w1,
quant_config.w1_bias,
a_ragged,
None,
gather_tok,
None,
quant_config.w1_precision,
gammas=gammas if apply_router_weight_on_input else None,
)
act_out = torch.empty(
(routing_data.n_valid, act_out_dim),
dtype=hidden_states.dtype,
device=hidden_states.device,
)
self.activation(activation, act_out, inter)
down = matmul(
act_out,
w2,
quant_config.w2_bias,
a_ragged,
None,
None,
None,
quant_config.w2_precision,
gammas=None if apply_router_weight_on_input else gammas,
)
acc = torch.zeros((M, K), dtype=torch.float32, device=hidden_states.device)
acc.index_add_(0, gather_tok.to(torch.int64), down.to(torch.float32))
output.view(M, K).copy_(acc.to(output.dtype))
return
# type check, uint8 means mxfp4
assert hidden_states.dtype == torch.bfloat16
assert (
@@ -45,7 +45,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
)
from vllm.model_executor.layers.quantization.utils.w8a8_utils import all_close_1d
from vllm.platforms import current_platform
from vllm.utils.import_utils import has_triton_kernels
from vllm.utils.import_utils import get_triton_kernels_version
from vllm.utils.math_utils import round_up
if TYPE_CHECKING:
@@ -54,9 +54,14 @@ if TYPE_CHECKING:
logger = init_logger(__name__)
if has_triton_kernels():
triton_kernels_version = get_triton_kernels_version()
if triton_kernels_version is not None:
try:
from triton_kernels.matmul_ogs import PrecisionConfig
if triton_kernels_version == "3.8":
from triton_kernels.matmul import FlexCtx, PrecisionConfig
else:
from triton_kernels.matmul_ogs import FlexCtx, PrecisionConfig
except (ImportError, AttributeError) as e:
logger.error(
"Failed to import Triton kernels. Please make sure your triton "
@@ -65,6 +70,15 @@ if has_triton_kernels():
)
def _mx_scale_kwargs(scale):
"""PrecisionConfig weight-scale kwargs: 3.8 uses b_mx_scale/b_microblock_size,
3.5.1/3.6 use weight_scale.
"""
if triton_kernels_version == "3.8":
return {"b_mx_scale": scale, "b_microblock_size": 32}
return {"weight_scale": scale}
def _pack_deepgemm_mxfp4_scales(
w13_weight: torch.Tensor,
w2_weight: torch.Tensor,
@@ -1182,7 +1196,6 @@ def convert_gpt_oss_weight_to_mxfp4_moe_kernel_format(
elif mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_FP8:
# W4A8: MXFP4 weights + static FP8 activations (triton kernel)
from triton_kernels.matmul_ogs import FlexCtx, PrecisionConfig
from triton_kernels.numerics import InFlexData
if w13_bias is not None:
@@ -1217,11 +1230,11 @@ def convert_gpt_oss_weight_to_mxfp4_moe_kernel_format(
# Create PrecisionConfig with both weight and activation info
w13_precision_config = PrecisionConfig(
weight_scale=w13_scale,
**_mx_scale_kwargs(w13_scale),
flex_ctx=FlexCtx(rhs_data=w13_flex, lhs_data=lhs_data13),
)
w2_precision_config = PrecisionConfig(
weight_scale=w2_scale,
**_mx_scale_kwargs(w2_scale),
flex_ctx=FlexCtx(rhs_data=w2_flex, lhs_data=lhs_data2),
)
@@ -1238,8 +1251,6 @@ def convert_gpt_oss_weight_to_mxfp4_moe_kernel_format(
)
elif mxfp4_backend in TRITON_BACKENDS:
from triton_kernels.matmul_ogs import FlexCtx, PrecisionConfig
if w13_bias is not None:
w13_bias = w13_bias.to(torch.float32)
if w2_bias is not None:
@@ -1255,10 +1266,10 @@ def convert_gpt_oss_weight_to_mxfp4_moe_kernel_format(
)
w13_precision_config = PrecisionConfig(
weight_scale=w13_scale, flex_ctx=FlexCtx(rhs_data=w13_flex)
**_mx_scale_kwargs(w13_scale), flex_ctx=FlexCtx(rhs_data=w13_flex)
)
w2_precision_config = PrecisionConfig(
weight_scale=w2_scale, flex_ctx=FlexCtx(rhs_data=w2_flex)
**_mx_scale_kwargs(w2_scale), flex_ctx=FlexCtx(rhs_data=w2_flex)
)
# The original mxfp4 block scales have been swizzled into the
@@ -1653,8 +1664,6 @@ def convert_weight_to_mxfp4_moe_kernel_format(
elif mxfp4_backend in TRITON_BACKENDS or (
mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16 and is_gfx1250
):
from triton_kernels.matmul_ogs import FlexCtx, PrecisionConfig
if mxfp4_backend == Mxfp4MoeBackend.AITER_TRITON_MXFP4_BF16:
# AITER moe_gemm_a16w4 needs gate/up interleaved
def interleave_gate_up(w: torch.Tensor) -> torch.Tensor:
@@ -1698,10 +1707,10 @@ def convert_weight_to_mxfp4_moe_kernel_format(
)
w13_precision_config = PrecisionConfig(
weight_scale=w13_scale, flex_ctx=FlexCtx(rhs_data=w13_flex)
**_mx_scale_kwargs(w13_scale), flex_ctx=FlexCtx(rhs_data=w13_flex)
)
w2_precision_config = PrecisionConfig(
weight_scale=w2_scale, flex_ctx=FlexCtx(rhs_data=w2_flex)
**_mx_scale_kwargs(w2_scale), flex_ctx=FlexCtx(rhs_data=w2_flex)
)
# The original mxfp4 block scales have been swizzled into the
@@ -7,7 +7,7 @@ import torch
from vllm.logger import init_logger
from vllm.platforms import current_platform
from vllm.triton_utils import tl, triton
from vllm.utils.import_utils import has_triton_kernels
from vllm.utils.import_utils import get_triton_kernels_version, has_triton_kernels
from vllm.utils.torch_utils import direct_register_custom_op, is_torch_equal_or_newer
logger = init_logger(__name__)
@@ -27,10 +27,23 @@ def should_use_cdna4_mx_scale_swizzle() -> bool:
return on_gfx950() and get_tensor_model_parallel_world_size() <= 2
def weight_mx_scale(precision_config):
"""mxfp4 weight scale from a triton_kernels PrecisionConfig: 3.8 exposes it
as b_mx_scale, 3.5.1/3.6 as weight_scale.
"""
if get_triton_kernels_version() == "3.8":
return precision_config.b_mx_scale
return precision_config.weight_scale
def _swizzle_mxfp4(quant_tensor, scale, num_warps=8):
"""Weight swizzle for mxfp4 moe, used for OAI mxfp4 kernel."""
assert has_triton_kernels()
import triton_kernels.matmul_ogs_details.opt_flags as opt_flags
if get_triton_kernels_version() == "3.8":
# 3.8: matmul_ogs_details -> matmul_details
import triton_kernels.matmul_details.opt_flags as opt_flags
else:
import triton_kernels.matmul_ogs_details.opt_flags as opt_flags
from triton_kernels.numerics import InFlexData
from triton_kernels.tensor import FP4, convert_layout, wrap_torch_tensor
from triton_kernels.tensor_details import layout
@@ -51,6 +64,17 @@ def _swizzle_mxfp4(quant_tensor, scale, num_warps=8):
)
value_layout = StridedLayout
scale_layout = StridedLayout
elif current_platform.is_rocm() and get_triton_kernels_version() == "3.8":
# StridedLayout(-2) is triton_kernels' default CDNA mxfp4 weight layout
# (make_default_matmul_mxfp4_w_layout); 3.8 wants layout instances.
from triton_kernels.tensor_details.layout import CDNA4MXScaleLayout
value_layout = StridedLayout(-2)
scale_layout = (
CDNA4MXScaleLayout()
if should_use_cdna4_mx_scale_swizzle()
else StridedLayout()
)
elif current_platform.is_rocm():
value_layout = StridedLayout
if should_use_cdna4_mx_scale_swizzle():
+20
View File
@@ -527,6 +527,26 @@ def has_triton_kernels() -> bool:
return is_available
@cache
def get_triton_kernels_version() -> str | None:
"""The triton_kernels MoE-API generation ("3.5.1"/"3.6"/"3.8"), or None.
Inferred by capability since the package exposes no usable version: 3.8
replaced ``matmul_ogs`` with ``matmul``, and 3.5.1 predates ``SparseMatrix``.
"""
if not has_triton_kernels():
return None
try:
import triton_kernels.matmul_ogs # noqa: F401
except ImportError:
return "3.8"
try:
from triton_kernels.tensor import SparseMatrix # noqa: F401
except ImportError:
return "3.5.1"
return "3.6"
@cache
def has_tilelang() -> bool:
"""Whether the optional `tilelang` package is available.