Support piecewise cuda graph for fused marlin moe (#15100)
This commit is contained in:
@@ -2,7 +2,7 @@ from typing import Optional
|
|||||||
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from sglang.srt.utils import is_cuda
|
from sglang.srt.utils import direct_register_custom_op, is_cuda
|
||||||
|
|
||||||
_is_cuda = is_cuda()
|
_is_cuda = is_cuda()
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ def fused_marlin_moe(
|
|||||||
num_bits: int = 8,
|
num_bits: int = 8,
|
||||||
is_k_full: bool = True,
|
is_k_full: bool = True,
|
||||||
inplace: bool = False,
|
inplace: bool = False,
|
||||||
routed_scaling_factor: float = None,
|
routed_scaling_factor: Optional[float] = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
"""
|
"""
|
||||||
This function computes a Mixture of Experts (MoE) layer using two sets of
|
This function computes a Mixture of Experts (MoE) layer using two sets of
|
||||||
@@ -225,15 +225,26 @@ def fused_marlin_moe_fake(
|
|||||||
gating_output: torch.Tensor,
|
gating_output: torch.Tensor,
|
||||||
topk_weights: torch.Tensor,
|
topk_weights: torch.Tensor,
|
||||||
topk_ids: torch.Tensor,
|
topk_ids: torch.Tensor,
|
||||||
|
global_num_experts: int = -1,
|
||||||
|
expert_map: Optional[torch.Tensor] = None,
|
||||||
g_idx1: Optional[torch.Tensor] = None,
|
g_idx1: Optional[torch.Tensor] = None,
|
||||||
g_idx2: Optional[torch.Tensor] = None,
|
g_idx2: Optional[torch.Tensor] = None,
|
||||||
sort_indices1: Optional[torch.Tensor] = None,
|
sort_indices1: Optional[torch.Tensor] = None,
|
||||||
sort_indices2: Optional[torch.Tensor] = None,
|
sort_indices2: Optional[torch.Tensor] = None,
|
||||||
w1_zeros: Optional[torch.Tensor] = None,
|
w1_zeros: Optional[torch.Tensor] = None,
|
||||||
w2_zeros: Optional[torch.Tensor] = None,
|
w2_zeros: Optional[torch.Tensor] = None,
|
||||||
|
workspace: Optional[torch.Tensor] = None,
|
||||||
num_bits: int = 8,
|
num_bits: int = 8,
|
||||||
is_k_full: bool = True,
|
is_k_full: bool = True,
|
||||||
inplace: bool = False,
|
inplace: bool = False,
|
||||||
routed_scaling_factor: float = None,
|
routed_scaling_factor: Optional[float] = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
return torch.empty_like(hidden_states)
|
return torch.empty_like(hidden_states)
|
||||||
|
|
||||||
|
|
||||||
|
direct_register_custom_op(
|
||||||
|
op_name="fused_marlin_moe",
|
||||||
|
op_func=fused_marlin_moe,
|
||||||
|
mutates_args=[],
|
||||||
|
fake_impl=fused_marlin_moe_fake,
|
||||||
|
)
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ def fused_experts_none_to_marlin(
|
|||||||
runner_config: MoeRunnerConfig,
|
runner_config: MoeRunnerConfig,
|
||||||
) -> StandardCombineInput:
|
) -> StandardCombineInput:
|
||||||
global MARLIN_MOE_WORKSPACE
|
global MARLIN_MOE_WORKSPACE
|
||||||
from sglang.srt.layers.moe.fused_moe_triton.fused_marlin_moe import fused_marlin_moe
|
from sglang.srt.layers.moe.fused_moe_triton.fused_marlin_moe import ( # noqa
|
||||||
|
fused_marlin_moe,
|
||||||
|
)
|
||||||
from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput
|
from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput
|
||||||
from sglang.srt.layers.quantization.marlin_utils import marlin_make_workspace
|
from sglang.srt.layers.quantization.marlin_utils import marlin_make_workspace
|
||||||
|
|
||||||
@@ -97,7 +99,7 @@ def fused_experts_none_to_marlin(
|
|||||||
hidden_states.device, max_blocks_per_sm=4
|
hidden_states.device, max_blocks_per_sm=4
|
||||||
)
|
)
|
||||||
|
|
||||||
output = fused_marlin_moe(
|
output = torch.ops.sglang.fused_marlin_moe(
|
||||||
hidden_states=hidden_states,
|
hidden_states=hidden_states,
|
||||||
w1=quant_info.w13_qweight,
|
w1=quant_info.w13_qweight,
|
||||||
w2=quant_info.w2_qweight,
|
w2=quant_info.w2_qweight,
|
||||||
|
|||||||
@@ -943,7 +943,7 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
|
|||||||
layer: torch.nn.Module,
|
layer: torch.nn.Module,
|
||||||
dispatch_output: StandardDispatchOutput,
|
dispatch_output: StandardDispatchOutput,
|
||||||
) -> CombineInput:
|
) -> CombineInput:
|
||||||
from sglang.srt.layers.moe.fused_moe_triton.fused_marlin_moe import (
|
from sglang.srt.layers.moe.fused_moe_triton.fused_marlin_moe import ( # noqa
|
||||||
fused_marlin_moe,
|
fused_marlin_moe,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.moe.token_dispatcher import StandardCombineInput
|
from sglang.srt.layers.moe.token_dispatcher import StandardCombineInput
|
||||||
@@ -967,7 +967,7 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
|
|||||||
if expert_map is not None:
|
if expert_map is not None:
|
||||||
global_num_experts = self.moe_runner_config.num_experts
|
global_num_experts = self.moe_runner_config.num_experts
|
||||||
|
|
||||||
output = fused_marlin_moe(
|
output = torch.ops.sglang.fused_marlin_moe(
|
||||||
x,
|
x,
|
||||||
layer.w13_weight_packed,
|
layer.w13_weight_packed,
|
||||||
layer.w2_weight_packed,
|
layer.w2_weight_packed,
|
||||||
|
|||||||
@@ -1099,32 +1099,3 @@ if _is_cuda:
|
|||||||
@register_fake_if_exists("sgl_kernel::gptq_shuffle")
|
@register_fake_if_exists("sgl_kernel::gptq_shuffle")
|
||||||
def _(q_weight, q_perm, bit):
|
def _(q_weight, q_perm, bit):
|
||||||
return
|
return
|
||||||
|
|
||||||
@register_fake_if_exists("sgl_kernel::moe_wna16_marlin_gemm")
|
|
||||||
def _(
|
|
||||||
a,
|
|
||||||
c,
|
|
||||||
b_q_weight,
|
|
||||||
b_scales,
|
|
||||||
b_zeros,
|
|
||||||
g_idx,
|
|
||||||
perm,
|
|
||||||
workspace,
|
|
||||||
sorted_token_ids,
|
|
||||||
expert_ids,
|
|
||||||
num_tokens_post_padded,
|
|
||||||
topk_weights,
|
|
||||||
moe_block_size,
|
|
||||||
top_k,
|
|
||||||
mul_topk_weights,
|
|
||||||
is_ep,
|
|
||||||
b_q_type_id,
|
|
||||||
size_m,
|
|
||||||
size_n,
|
|
||||||
size_k,
|
|
||||||
is_k_full,
|
|
||||||
use_atomic_add,
|
|
||||||
use_fp32_reduce,
|
|
||||||
is_zp_float,
|
|
||||||
):
|
|
||||||
return c
|
|
||||||
|
|||||||
@@ -214,6 +214,41 @@ class TestPiecewiseCudaGraphAWQ(CustomTestCase):
|
|||||||
self.assertGreaterEqual(metrics["score"], 0.65)
|
self.assertGreaterEqual(metrics["score"], 0.65)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPiecewiseCudaGraphGPTQ(CustomTestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.model = "Qwen/Qwen3-30B-A3B-GPTQ-Int4"
|
||||||
|
cls.base_url = DEFAULT_URL_FOR_TEST
|
||||||
|
cls.process = popen_launch_server(
|
||||||
|
cls.model,
|
||||||
|
cls.base_url,
|
||||||
|
timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
|
||||||
|
other_args=["--enable-piecewise-cuda-graph"],
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
kill_process_tree(cls.process.pid)
|
||||||
|
|
||||||
|
def test_mgsm_accuracy(self):
|
||||||
|
num_examples = 1319
|
||||||
|
|
||||||
|
args = SimpleNamespace(
|
||||||
|
base_url=self.base_url,
|
||||||
|
model=self.model,
|
||||||
|
eval_name="mgsm_en",
|
||||||
|
num_examples=num_examples,
|
||||||
|
num_threads=min(num_examples, 1024),
|
||||||
|
)
|
||||||
|
|
||||||
|
metrics = run_eval(args)
|
||||||
|
print(f"MGSM Accuracy: {metrics['score']:.3f}")
|
||||||
|
|
||||||
|
# Expected accuracy: 0.948, allow some variance
|
||||||
|
self.assertGreaterEqual(metrics["score"], 0.92)
|
||||||
|
|
||||||
|
|
||||||
class TestPiecewiseCudaGraphFP8(CustomTestCase):
|
class TestPiecewiseCudaGraphFP8(CustomTestCase):
|
||||||
"""Test piecewise CUDA graph with FP8 quantized model"""
|
"""Test piecewise CUDA graph with FP8 quantized model"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user