| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
| from typing import TYPE_CHECKING, cast |
|
|
| import torch |
| from torch.nn import Module |
| from torch.nn.parameter import Parameter |
|
|
| |
| from sglang.srt.distributed import get_tp_group |
| from sglang.srt.distributed.device_communicators.pynccl_allocator import ( |
| is_symmetric_memory_enabled, |
| is_tensor_in_symmetric_mempool, |
| use_symmetric_memory, |
| ) |
| from sglang.srt.environ import envs |
| from sglang.srt.layers.dp_attention import is_allocation_symmetric |
| from sglang.srt.layers.moe.flashinfer_trtllm_moe import ( |
| trtllm_fp8_block_scale_moe_wrapper, |
| trtllm_fp8_block_scale_routed_moe_wrapper, |
| trtllm_fp8_per_tensor_scale_moe_wrapper, |
| ) |
| from sglang.srt.layers.moe.moe_runner.base import ( |
| MoeQuantInfo, |
| MoeRunnerConfig, |
| _moe_output_buf, |
| register_fused_func, |
| ) |
| from sglang.srt.layers.quantization.fp8_kernel import ( |
| per_token_group_quant_fp8, |
| scaled_fp8_quant, |
| ) |
| from sglang.srt.layers.utils import copy_or_rebind_param |
| from sglang.srt.utils.common import ( |
| is_cuda_alike, |
| is_flashinfer_available, |
| next_power_of_2, |
| ) |
|
|
| _SGLANG_EXPERIMENTAL_LORA_OPTI = envs.SGLANG_EXPERIMENTAL_LORA_OPTI.get() |
|
|
| logger = __import__("logging").getLogger(__name__) |
|
|
|
|
| def round_up_to_multiple(x: int, m: int) -> int: |
| """Round up *x* to the nearest multiple of *m*.""" |
| return (x + m - 1) // m * m |
|
|
|
|
| if TYPE_CHECKING: |
| from sglang.srt.layers.moe.token_dispatcher import ( |
| StandardCombineInput, |
| StandardDispatchOutput, |
| ) |
|
|
| if is_flashinfer_available(): |
| from sglang.srt.layers.quantization.fp4_utils import fp4_quantize |
| elif is_cuda_alike(): |
| from sglang.jit_kernel.nvfp4 import scaled_fp4_quant as fp4_quantize |
| else: |
| fp4_quantize = None |
|
|
| _flashinfer_trtllm_shuffle_row_indices_cache_mxfp8: dict[ |
| tuple, dict[str, torch.Tensor] |
| ] = {} |
|
|
|
|
| def _is_gated(layer: Module) -> bool: |
| """Return whether the MoE layer uses a gated activation (default True).""" |
| is_gated = ( |
| getattr(layer, "moe_runner_config", None) and layer.moe_runner_config.is_gated |
| ) |
| return True if is_gated is None else is_gated |
|
|
|
|
| def _align_fp8_moe_weights( |
| w13: torch.Tensor, |
| w2: torch.Tensor, |
| is_gated: bool, |
| min_alignment: int = 16, |
| ) -> tuple[torch.Tensor, torch.Tensor, int]: |
| """Pad intermediate size so FlashInfer TRTLLM FP8 kernels' alignment holds. |
| |
| Returns (w13, w2, padded_intermediate). |
| """ |
| num_experts, hidden_size, intermediate = w2.shape |
|
|
| padded_intermediate = round_up_to_multiple(intermediate, min_alignment) |
| if padded_intermediate == intermediate: |
| return w13, w2, intermediate |
|
|
| logger.info( |
| "FP8 MoE: padding intermediate size from %d to %d (alignment=%d)", |
| intermediate, |
| padded_intermediate, |
| min_alignment, |
| ) |
|
|
| up_mult = 2 if is_gated else 1 |
| padded_gate_up = up_mult * padded_intermediate |
|
|
| padded_w13 = w13.new_zeros((num_experts, padded_gate_up, w13.shape[2])) |
| padded_w13[:, : w13.shape[1], :] = w13 |
|
|
| padded_w2 = w2.new_zeros((num_experts, hidden_size, padded_intermediate)) |
| padded_w2[:, :, :intermediate] = w2 |
|
|
| return padded_w13, padded_w2, padded_intermediate |
|
|
|
|
| def align_fp8_moe_weights_for_flashinfer_trtllm( |
| layer: Module, swap_w13_halves: bool = False |
| ) -> None: |
| """Prepare FP8 MoE weights/scales for FlashInfer TRT-LLM kernels. |
| |
| Args: |
| layer: The MoE layer to process. |
| swap_w13_halves: If True, swap W13 halves from [Up, Gate] to [Gate, Up]. |
| This is needed for ModelOpt FP8 checkpoints which store weights in |
| [Up, Gate] order, while regular FP8 checkpoints store them in [Gate, Up]. |
| """ |
| from flashinfer import shuffle_matrix_a |
|
|
| is_gated = _is_gated(layer) |
|
|
| w13_weight = cast(torch.Tensor, layer.w13_weight) |
| w2_weight = cast(torch.Tensor, layer.w2_weight) |
| num_experts, gate_up_dim, hidden = w13_weight.shape |
|
|
| |
| if swap_w13_halves and is_gated: |
| inter = gate_up_dim // 2 |
| w13_weight = ( |
| w13_weight.reshape(num_experts, 2, inter, hidden) |
| .flip(dims=[1]) |
| .reshape(num_experts, gate_up_dim, hidden) |
| ) |
|
|
| |
| min_alignment = 16 if is_gated else 128 |
| w13_weight, w2_weight, _ = _align_fp8_moe_weights( |
| w13_weight, w2_weight, is_gated, min_alignment |
| ) |
| num_experts, gate_up_dim, hidden = w13_weight.shape |
|
|
| epilogue_tile_m = 128 |
|
|
| if is_gated: |
| from flashinfer import reorder_rows_for_gated_act_gemm |
|
|
| w13_interleaved_list = [ |
| reorder_rows_for_gated_act_gemm(w13_weight[i]) for i in range(num_experts) |
| ] |
| w13_processed: torch.Tensor = torch.stack(w13_interleaved_list).reshape( |
| num_experts, gate_up_dim, hidden |
| ) |
| else: |
| w13_processed = w13_weight |
|
|
| |
| w13_shuffled = [ |
| shuffle_matrix_a(w13_processed[i].view(torch.uint8), epilogue_tile_m) |
| for i in range(num_experts) |
| ] |
| w2_shuffled = [ |
| shuffle_matrix_a(w2_weight[i].view(torch.uint8), epilogue_tile_m) |
| for i in range(num_experts) |
| ] |
|
|
| layer.w13_weight = Parameter( |
| torch.stack(w13_shuffled).view(torch.float8_e4m3fn), |
| requires_grad=False, |
| ) |
| layer.w2_weight = Parameter( |
| torch.stack(w2_shuffled).view(torch.float8_e4m3fn), |
| requires_grad=False, |
| ) |
|
|
| |
| |
| assert hasattr(layer, "w13_input_scale") and layer.w13_input_scale is not None |
| assert hasattr(layer, "w2_input_scale") and layer.w2_input_scale is not None |
| assert hasattr(layer, "w13_weight_scale") and layer.w13_weight_scale is not None |
| assert hasattr(layer, "w2_weight_scale") and layer.w2_weight_scale is not None |
|
|
| input_scale = cast(torch.Tensor, layer.w13_input_scale).to(torch.float32) |
| activation_scale = cast(torch.Tensor, layer.w2_input_scale).to(torch.float32) |
| w13_weight_scale = cast(torch.Tensor, layer.w13_weight_scale).to(torch.float32) |
| w2_weight_scale = cast(torch.Tensor, layer.w2_weight_scale).to(torch.float32) |
|
|
| |
| |
| if is_gated: |
| output1_scales_scalar = ( |
| w13_weight_scale * input_scale * (1.0 / activation_scale) |
| ) |
| else: |
| output1_scales_scalar = torch.ones_like(w13_weight_scale) * ( |
| 1.0 / activation_scale |
| ) |
| output1_scales_gate_scalar = w13_weight_scale * input_scale |
| output2_scales_scalar = activation_scale * w2_weight_scale |
|
|
| layer.output1_scales_scalar = Parameter(output1_scales_scalar, requires_grad=False) |
| layer.output1_scales_gate_scalar = Parameter( |
| output1_scales_gate_scalar, requires_grad=False |
| ) |
| layer.output2_scales_scalar = Parameter(output2_scales_scalar, requires_grad=False) |
|
|
|
|
| def _align_mxfp8_moe_weights( |
| w13: torch.Tensor, |
| w13_scale: torch.Tensor, |
| w2: torch.Tensor, |
| w2_scale: torch.Tensor, |
| is_gated: bool, |
| min_alignment: int = 16, |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, int]: |
| """Pad intermediate size so FlashInfer TRTLLM MXFP8 kernels' alignment holds. |
| |
| Returns (w13, w13_scale, w2, w2_scale, padded_intermediate). |
| """ |
| num_experts, hidden_size, intermediate = w2.shape |
|
|
| padded_intermediate = round_up_to_multiple(intermediate, min_alignment) |
| if padded_intermediate == intermediate: |
| return w13, w13_scale, w2, w2_scale, intermediate |
|
|
| logger.info( |
| "MXFP8 MoE: padding intermediate size from %d to %d (alignment=%d)", |
| intermediate, |
| padded_intermediate, |
| min_alignment, |
| ) |
|
|
| up_mult = 2 if is_gated else 1 |
| padded_gate_up = up_mult * padded_intermediate |
|
|
| padded_w13 = w13.new_zeros((num_experts, padded_gate_up, w13.shape[2])) |
| padded_w13[:, : w13.shape[1], :] = w13 |
|
|
| padded_w2 = w2.new_zeros((num_experts, hidden_size, padded_intermediate)) |
| padded_w2[:, :, :intermediate] = w2 |
|
|
| padded_w13_scale = w13_scale.new_zeros( |
| (num_experts, padded_gate_up, w13_scale.shape[2]) |
| ) |
| padded_w13_scale[:, : w13_scale.shape[1], :] = w13_scale |
|
|
| |
| scale_block_k = intermediate // w2_scale.shape[2] if w2_scale.shape[2] > 0 else 32 |
| padded_w2_scale = w2_scale.new_zeros( |
| (num_experts, hidden_size, padded_intermediate // scale_block_k) |
| ) |
| padded_w2_scale[:, :, : w2_scale.shape[2]] = w2_scale |
|
|
| return padded_w13, padded_w13_scale, padded_w2, padded_w2_scale, padded_intermediate |
|
|
|
|
| def align_mxfp8_moe_weights_for_flashinfer_trtllm(layer: Module) -> None: |
| """Prepare MXFP8 MoE weights/scales for FlashInfer TRT-LLM kernels.""" |
| from flashinfer import block_scale_interleave |
| from flashinfer.fused_moe.core import ( |
| get_reorder_rows_for_gated_act_gemm_row_indices, |
| ) |
| from flashinfer.utils import ( |
| get_shuffle_matrix_a_row_indices, |
| get_shuffle_matrix_sf_a_row_indices, |
| ) |
|
|
| is_gated = _is_gated(layer) |
|
|
| w13_weight = cast(torch.Tensor, layer.w13_weight).contiguous() |
| w2_weight = cast(torch.Tensor, layer.w2_weight).contiguous() |
| w13_scale = cast(torch.Tensor, layer.w13_weight_scale_inv).contiguous() |
| w2_scale = cast(torch.Tensor, layer.w2_weight_scale_inv).contiguous() |
|
|
| assert w13_scale.dtype == torch.uint8 |
| assert w2_scale.dtype == torch.uint8 |
|
|
| |
| min_alignment = 16 if is_gated else 128 |
| w13_weight, w13_scale, w2_weight, w2_scale, _ = _align_mxfp8_moe_weights( |
| w13_weight, w13_scale, w2_weight, w2_scale, is_gated, min_alignment |
| ) |
|
|
| num_experts, gate_up_dim, _ = w13_weight.shape |
| _, hidden_size, _ = w2_weight.shape |
| epilogue_tile_m = 128 |
|
|
| |
| w13_weight_u8 = w13_weight.view(torch.uint8) |
| w2_weight_u8 = w2_weight.view(torch.uint8) |
| cache_key = ( |
| gate_up_dim, |
| hidden_size, |
| w2_weight.shape[-1], |
| w13_scale.shape[-1], |
| w2_scale.shape[-1], |
| epilogue_tile_m, |
| (w13_weight.device.type, w13_weight.device.index), |
| (w2_weight.device.type, w2_weight.device.index), |
| (w13_scale.device.type, w13_scale.device.index), |
| (w2_scale.device.type, w2_scale.device.index), |
| ) |
| cache = _flashinfer_trtllm_shuffle_row_indices_cache_mxfp8.get(cache_key) |
| if cache is None: |
| if is_gated: |
| reorder_row_indices = get_reorder_rows_for_gated_act_gemm_row_indices( |
| w13_weight_u8[0] |
| ).to(w13_weight.device) |
| else: |
| reorder_row_indices = torch.arange( |
| gate_up_dim, device=w13_weight.device, dtype=torch.long |
| ) |
| w13_shuffle_row_indices = get_shuffle_matrix_a_row_indices( |
| w13_weight_u8[0], epilogue_tile_m |
| ).to(w13_weight.device) |
| w2_shuffle_row_indices = get_shuffle_matrix_a_row_indices( |
| w2_weight_u8[0], epilogue_tile_m |
| ).to(w2_weight.device) |
| w13_scale_shuffle_row_indices = get_shuffle_matrix_sf_a_row_indices( |
| w13_scale[0].reshape(gate_up_dim, -1), epilogue_tile_m |
| ).to(w13_scale.device) |
| w2_scale_shuffle_row_indices = get_shuffle_matrix_sf_a_row_indices( |
| w2_scale[0].reshape(hidden_size, -1), epilogue_tile_m |
| ).to(w2_scale.device) |
| cache = { |
| "reorder_row_indices": reorder_row_indices, |
| "w13_shuffle_row_indices": w13_shuffle_row_indices, |
| "w2_shuffle_row_indices": w2_shuffle_row_indices, |
| "w13_scale_shuffle_row_indices": w13_scale_shuffle_row_indices, |
| "w2_scale_shuffle_row_indices": w2_scale_shuffle_row_indices, |
| } |
| _flashinfer_trtllm_shuffle_row_indices_cache_mxfp8[cache_key] = cache |
|
|
| reorder_row_indices = cache["reorder_row_indices"] |
| w13_shuffle_row_indices = cache["w13_shuffle_row_indices"] |
| w2_shuffle_row_indices = cache["w2_shuffle_row_indices"] |
| w13_scale_shuffle_row_indices = cache["w13_scale_shuffle_row_indices"] |
| w2_scale_shuffle_row_indices = cache["w2_scale_shuffle_row_indices"] |
|
|
| w13_shuffled_u8 = torch.empty_like(w13_weight_u8) |
| w2_shuffled_u8 = torch.empty_like(w2_weight_u8) |
| w13_scale_shuffled = torch.empty_like(w13_scale) |
| w2_scale_shuffled = torch.empty_like(w2_scale) |
|
|
| for i in range(num_experts): |
| w13_interleaved_u8 = w13_weight_u8[i].index_select(0, reorder_row_indices) |
| w13_scale_interleaved = w13_scale[i].index_select(0, reorder_row_indices) |
|
|
| w13_shuffled_u8[i].copy_( |
| w13_interleaved_u8.index_select(0, w13_shuffle_row_indices) |
| ) |
| w2_shuffled_u8[i].copy_(w2_weight_u8[i].index_select(0, w2_shuffle_row_indices)) |
|
|
| w13_scale_linear = w13_scale_interleaved.reshape(gate_up_dim, -1) |
| w13_scale_shuffled[i].copy_( |
| block_scale_interleave( |
| w13_scale_linear.index_select(0, w13_scale_shuffle_row_indices) |
| ).reshape_as(w13_scale_shuffled[i]) |
| ) |
|
|
| w2_scale_linear = w2_scale[i].reshape(hidden_size, -1) |
| w2_scale_shuffled[i].copy_( |
| block_scale_interleave( |
| w2_scale_linear.index_select(0, w2_scale_shuffle_row_indices) |
| ).reshape_as(w2_scale_shuffled[i]) |
| ) |
|
|
| |
| copy_or_rebind_param(layer, "w13_weight", w13_shuffled_u8.view(torch.float8_e4m3fn)) |
| copy_or_rebind_param(layer, "w2_weight", w2_shuffled_u8.view(torch.float8_e4m3fn)) |
| copy_or_rebind_param( |
| layer, |
| "w13_weight_scale_inv", |
| w13_scale_shuffled.contiguous(), |
| ) |
| copy_or_rebind_param( |
| layer, |
| "w2_weight_scale_inv", |
| w2_scale_shuffled.contiguous(), |
| ) |
| layer.w13_weight_scale_inv.format_ue8m0 = True |
| layer.w2_weight_scale_inv.format_ue8m0 = True |
|
|
|
|
| def _align_fp4_moe_weights( |
| w13: torch.Tensor, |
| w13_scale: torch.Tensor, |
| w2: torch.Tensor, |
| w2_scale: torch.Tensor, |
| is_gated: bool, |
| min_alignment: int = 16, |
| ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, int]: |
| """Pad intermediate size so FlashInfer TRTLLM FP4 kernels' alignment holds. |
| |
| Returns (w13, w13_scale, w2, w2_scale, padded_intermediate). |
| """ |
| num_experts, hidden_size, intermediate_packed = w2.shape |
| intermediate = intermediate_packed * 2 |
|
|
| padded_intermediate = round_up_to_multiple(intermediate, min_alignment) |
| if padded_intermediate == intermediate: |
| return w13, w13_scale, w2, w2_scale, intermediate |
|
|
| logger.info( |
| "FP4 MoE: padding intermediate size from %d to %d (alignment=%d)", |
| intermediate, |
| padded_intermediate, |
| min_alignment, |
| ) |
|
|
| up_mult = 2 if is_gated else 1 |
| padded_gate_up = up_mult * padded_intermediate |
|
|
| padded_w13 = w13.new_zeros((num_experts, padded_gate_up, w13.shape[2])) |
| padded_w13[:, : w13.shape[1], :] = w13 |
|
|
| padded_w2 = w2.new_zeros((num_experts, hidden_size, padded_intermediate // 2)) |
| padded_w2[:, :, : w2.shape[2]] = w2 |
|
|
| padded_w13_scale = w13_scale.new_zeros( |
| (num_experts, padded_gate_up, w13_scale.shape[2]) |
| ) |
| padded_w13_scale[:, : w13_scale.shape[1], :] = w13_scale |
|
|
| padded_w2_scale = w2_scale.new_zeros( |
| (num_experts, hidden_size, padded_intermediate // 16) |
| ) |
| padded_w2_scale[:, :, : w2_scale.shape[2]] = w2_scale |
|
|
| return padded_w13, padded_w13_scale, padded_w2, padded_w2_scale, padded_intermediate |
|
|
|
|
| def align_fp4_moe_weights_for_flashinfer_trtllm(layer: Module) -> None: |
| """Prepare FP4 MoE weights/scales for FlashInfer TRT-LLM kernels. |
| |
| This function handles the weight transformation needed for FP4 TRTLLM MoE: |
| - Pads intermediate dimension for kernel alignment constraints |
| - Reorders weights for gated activation GEMM |
| - Shuffles weights and scales for transposed MMA output |
| - Computes the output scale factors |
| """ |
| from sglang.srt.layers.quantization.utils import ( |
| prepare_static_weights_for_trtllm_fp4_moe, |
| ) |
|
|
| w13_weight = cast(torch.Tensor, layer.w13_weight) |
| w2_weight = cast(torch.Tensor, layer.w2_weight) |
| w13_weight_scale = cast(torch.Tensor, layer.w13_weight_scale) |
| w2_weight_scale = cast(torch.Tensor, layer.w2_weight_scale) |
|
|
| is_gated = layer.moe_runner_config.is_gated |
| min_alignment = 16 if is_gated else 128 |
|
|
| |
| w13_weight, w13_weight_scale, w2_weight, w2_weight_scale, intermediate_size = ( |
| _align_fp4_moe_weights( |
| w13_weight, |
| w13_weight_scale, |
| w2_weight, |
| w2_weight_scale, |
| is_gated, |
| min_alignment, |
| ) |
| ) |
|
|
| ( |
| gemm1_weights_fp4_shuffled, |
| gemm1_scales_fp4_shuffled, |
| gemm2_weights_fp4_shuffled, |
| gemm2_scales_fp4_shuffled, |
| ) = prepare_static_weights_for_trtllm_fp4_moe( |
| w13_weight, |
| w2_weight, |
| w13_weight_scale, |
| w2_weight_scale, |
| w2_weight.size(-2), |
| intermediate_size, |
| w13_weight.size(0), |
| is_gated=is_gated, |
| ) |
|
|
| |
| copy_or_rebind_param(layer, "w13_weight", gemm1_weights_fp4_shuffled.contiguous()) |
| copy_or_rebind_param(layer, "w2_weight", gemm2_weights_fp4_shuffled.contiguous()) |
| copy_or_rebind_param( |
| layer, "w13_weight_scale", gemm1_scales_fp4_shuffled.contiguous() |
| ) |
| copy_or_rebind_param( |
| layer, "w2_weight_scale", gemm2_scales_fp4_shuffled.contiguous() |
| ) |
|
|
| |
| |
| |
| w2_input_scale_quant = cast(torch.Tensor, layer.w2_input_scale_quant) |
| g1_alphas = cast(torch.Tensor, layer.g1_alphas) |
| if layer.moe_runner_config.is_gated: |
| g1_scale_c = (w2_input_scale_quant * g1_alphas).to(torch.float32) |
| else: |
| num_experts = g1_alphas.shape[0] |
| g1_scale_c = ( |
| w2_input_scale_quant.to(torch.float32).expand(num_experts).contiguous() |
| ) |
| copy_or_rebind_param(layer, "g1_scale_c", g1_scale_c) |
|
|
| |
| layer.intermediate_size_per_partition = intermediate_size |
|
|
|
|
| def get_activation_type(activation: str, is_gated: bool = True) -> int: |
| """Map SGLang activation string to FlashInfer ActivationType int value.""" |
| from flashinfer.fused_moe.core import ActivationType |
|
|
| if is_gated: |
| _ACTIVATION_STR_TO_TYPE = { |
| "silu": ActivationType.Swiglu, |
| "gelu": ActivationType.Geglu, |
| } |
| else: |
| _ACTIVATION_STR_TO_TYPE = { |
| "silu": ActivationType.Silu, |
| "gelu": ActivationType.Gelu, |
| "relu2": ActivationType.Relu2, |
| } |
| act = _ACTIVATION_STR_TO_TYPE.get(activation) |
| if act is None: |
| raise ValueError( |
| f"Unsupported activation '{activation}' for TRTLLM MoE " |
| f"(is_gated={is_gated}). " |
| f"Expected one of {list(_ACTIVATION_STR_TO_TYPE.keys())}." |
| ) |
| return act.value |
|
|
|
|
| @dataclass |
| class FlashInferTrtllmFp8MoeQuantInfo(MoeQuantInfo): |
| """Quantization payload consumed by FlashInfer TRT-LLM FP8 MoE kernels.""" |
|
|
| |
| w13_weight: torch.Tensor |
| w2_weight: torch.Tensor |
|
|
| |
| global_num_experts: int |
| local_expert_offset: int |
| local_num_experts: int |
| intermediate_size: int |
|
|
| routing_method_type: int |
|
|
| |
| block_quant: bool |
| use_mxfp8: bool = False |
| weight_block_k: int | None = None |
| w13_weight_scale_inv: torch.Tensor | None = None |
| w2_weight_scale_inv: torch.Tensor | None = None |
|
|
| |
| w13_input_scale: torch.Tensor | None = None |
| output1_scales_scalar: torch.Tensor | None = None |
| output1_scales_gate_scalar: torch.Tensor | None = None |
| output2_scales_scalar: torch.Tensor | None = None |
| use_routing_scales_on_input: bool = False |
|
|
| |
| activation_type: int | None = None |
|
|
|
|
| def _pack_topk_for_flashinfer_routed( |
| topk_ids: torch.Tensor, topk_weights: torch.Tensor |
| ) -> torch.Tensor: |
| """Pack routed top-k tensors into FlashInfer's int32 format.""" |
| packed_ids = topk_ids.to(torch.int32) |
| packed_weights = topk_weights.to(torch.bfloat16) |
| packed = (packed_ids << 16) | packed_weights.view(torch.int16).to(torch.int32) |
| return packed |
|
|
|
|
| def fused_experts_none_to_flashinfer_trtllm_fp8( |
| dispatch_output: StandardDispatchOutput, |
| quant_info: FlashInferTrtllmFp8MoeQuantInfo, |
| runner_config: MoeRunnerConfig, |
| use_routed_topk: bool = False, |
| ) -> StandardCombineInput: |
| from flashinfer.fused_moe import Fp8QuantizationType |
|
|
| from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput |
| from sglang.srt.layers.moe.topk import TopKOutputChecker |
| from sglang.srt.layers.moe.utils import RoutingMethodType |
|
|
| _SUPPORTED_FP8_ACTIVATIONS = {"silu", "relu2"} |
| assert runner_config.activation in _SUPPORTED_FP8_ACTIVATIONS, ( |
| f"Only {_SUPPORTED_FP8_ACTIVATIONS} are supported for FP8 MoE, " |
| f"got '{runner_config.activation}'." |
| ) |
| assert not runner_config.no_combine, "no_combine is not supported for flashinfer." |
|
|
| hidden_states = dispatch_output.hidden_states |
| topk_output = dispatch_output.topk_output |
| if TopKOutputChecker.format_is_bypassed(topk_output): |
| router_logits = topk_output.router_logits |
| topk_config = topk_output.topk_config |
| correction_bias = ( |
| None |
| if topk_config.correction_bias is None |
| else topk_config.correction_bias.to(hidden_states.dtype) |
| ) |
| else: |
| router_logits = None |
| topk_config = None |
| correction_bias = None |
|
|
| routing_method_type = quant_info.routing_method_type |
| fp8_quantization_type = ( |
| Fp8QuantizationType.MxFp8 |
| if quant_info.use_mxfp8 |
| else Fp8QuantizationType.DeepSeekFp8 |
| ) |
| use_shuffled_weight = quant_info.use_mxfp8 |
|
|
| if quant_info.block_quant: |
| assert quant_info.weight_block_k is not None |
| assert quant_info.w13_weight_scale_inv is not None |
| assert quant_info.w2_weight_scale_inv is not None |
|
|
| if quant_info.use_mxfp8: |
| assert quant_info.weight_block_k == 32 |
| from flashinfer import mxfp8_quantize |
|
|
| a_q, a_sf = mxfp8_quantize(hidden_states, False) |
| |
| |
| a_sf_t = a_sf.view(torch.uint8).reshape(hidden_states.shape[0], -1) |
| else: |
| a_q, a_sf = per_token_group_quant_fp8( |
| hidden_states, quant_info.weight_block_k |
| ) |
| a_sf_t = a_sf.t().contiguous() |
|
|
| |
| with use_symmetric_memory( |
| get_tp_group(), disabled=not is_allocation_symmetric() |
| ): |
| symm_output = torch.empty( |
| hidden_states.shape[0], |
| hidden_states.shape[1], |
| dtype=hidden_states.dtype, |
| device=hidden_states.device, |
| ) |
|
|
| |
| |
| |
| if use_routed_topk: |
| assert ( |
| runner_config.top_k is not None |
| ), "runner_config.top_k is required for flashinfer_trtllm_routed." |
| assert TopKOutputChecker.format_is_standard(topk_output) |
| packed_topk_ids = _pack_topk_for_flashinfer_routed( |
| topk_ids=topk_output.topk_ids, |
| topk_weights=topk_output.topk_weights, |
| ) |
|
|
| output = trtllm_fp8_block_scale_routed_moe_wrapper( |
| topk_ids=packed_topk_ids, |
| routing_bias=None, |
| hidden_states=a_q, |
| hidden_states_scale=a_sf_t, |
| gemm1_weights=quant_info.w13_weight, |
| gemm1_weights_scale=quant_info.w13_weight_scale_inv, |
| gemm2_weights=quant_info.w2_weight, |
| gemm2_weights_scale=quant_info.w2_weight_scale_inv, |
| num_experts=quant_info.global_num_experts, |
| top_k=runner_config.top_k, |
| n_group=None, |
| topk_group=None, |
| intermediate_size=quant_info.intermediate_size, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=quant_info.local_num_experts, |
| routed_scaling_factor=( |
| runner_config.routed_scaling_factor |
| if runner_config.routed_scaling_factor is not None |
| else 1.0 |
| ), |
| routing_method_type=( |
| RoutingMethodType.TopK |
| if routing_method_type == RoutingMethodType.DeepSeekV3 |
| else routing_method_type |
| ), |
| use_shuffled_weight=use_shuffled_weight, |
| tune_max_num_tokens=next_power_of_2(a_q.shape[0]), |
| fp8_quantization_type=int(fp8_quantization_type), |
| activation_type=quant_info.activation_type, |
| ) |
| else: |
| assert TopKOutputChecker.format_is_bypassed(topk_output) |
|
|
| output = trtllm_fp8_block_scale_moe_wrapper( |
| routing_logits=router_logits, |
| routing_bias=correction_bias, |
| hidden_states=a_q, |
| hidden_states_scale=a_sf_t, |
| gemm1_weights=quant_info.w13_weight, |
| gemm1_weights_scale=quant_info.w13_weight_scale_inv, |
| gemm2_weights=quant_info.w2_weight, |
| gemm2_weights_scale=quant_info.w2_weight_scale_inv, |
| num_experts=quant_info.global_num_experts, |
| top_k=topk_config.top_k, |
| n_group=topk_config.num_expert_group, |
| topk_group=topk_config.topk_group, |
| intermediate_size=quant_info.intermediate_size, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=quant_info.local_num_experts, |
| routed_scaling_factor=( |
| runner_config.routed_scaling_factor |
| if runner_config.routed_scaling_factor is not None |
| else 1.0 |
| ), |
| routing_method_type=routing_method_type, |
| use_shuffled_weight=use_shuffled_weight, |
| tune_max_num_tokens=next_power_of_2(a_q.shape[0]), |
| fp8_quantization_type=int(fp8_quantization_type), |
| activation_type=quant_info.activation_type, |
| ) |
| |
| symm_output.copy_(output) |
| output = symm_output |
| else: |
| assert TopKOutputChecker.format_is_bypassed(topk_output) |
| assert quant_info.w13_input_scale is not None |
| assert quant_info.output1_scales_scalar is not None |
| assert quant_info.output1_scales_gate_scalar is not None |
| assert quant_info.output2_scales_scalar is not None |
|
|
| a_q, _ = scaled_fp8_quant(hidden_states, quant_info.w13_input_scale) |
| routing_bias_cast = ( |
| None if correction_bias is None else correction_bias.to(torch.bfloat16) |
| ) |
|
|
| |
| with use_symmetric_memory( |
| get_tp_group(), disabled=not is_allocation_symmetric() |
| ): |
| symm_output = torch.empty( |
| hidden_states.shape[0], |
| hidden_states.shape[1], |
| dtype=torch.bfloat16, |
| device=hidden_states.device, |
| ) |
|
|
| |
| |
| |
|
|
| router_logits = router_logits.to(torch.bfloat16) |
|
|
| output = trtllm_fp8_per_tensor_scale_moe_wrapper( |
| routing_logits=router_logits, |
| routing_bias=routing_bias_cast, |
| hidden_states=a_q, |
| gemm1_weights=quant_info.w13_weight, |
| output1_scales_scalar=quant_info.output1_scales_scalar, |
| output1_scales_gate_scalar=quant_info.output1_scales_gate_scalar, |
| gemm2_weights=quant_info.w2_weight, |
| output2_scales_scalar=quant_info.output2_scales_scalar, |
| num_experts=quant_info.global_num_experts, |
| top_k=topk_config.top_k, |
| n_group=topk_config.num_expert_group, |
| topk_group=topk_config.topk_group, |
| intermediate_size=int(quant_info.w2_weight.shape[2]), |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=quant_info.local_num_experts, |
| routed_scaling_factor=( |
| runner_config.routed_scaling_factor |
| if runner_config.routed_scaling_factor is not None |
| else 1.0 |
| ), |
| use_routing_scales_on_input=False, |
| routing_method_type=routing_method_type, |
| tune_max_num_tokens=next_power_of_2(a_q.shape[0]), |
| activation_type=quant_info.activation_type, |
| ) |
| symm_output.copy_(output) |
| output = symm_output |
|
|
| return StandardCombineInput(hidden_states=output) |
|
|
|
|
| @dataclass |
| class FlashInferTrtllmFp4MoeQuantInfo(MoeQuantInfo): |
| """Quantization payload consumed by FlashInfer TRT-LLM FP4 MoE kernels.""" |
|
|
| w13_weight: torch.Tensor |
| w2_weight: torch.Tensor |
| w13_weight_scale: torch.Tensor |
| w2_weight_scale: torch.Tensor |
|
|
| |
| g1_scale_c: torch.Tensor |
| g1_alphas: torch.Tensor |
| g2_alphas: torch.Tensor |
| w13_input_scale_quant: torch.Tensor |
|
|
| |
| global_num_experts: int |
| local_expert_offset: int |
| local_num_experts: int |
| intermediate_size_per_partition: int |
|
|
| routing_method_type: int |
| use_per_token_activation: bool = False |
|
|
|
|
| def quantize_hidden_states_fp4( |
| hidden_states: torch.Tensor, |
| input_scale_quant: torch.Tensor, |
| ) -> tuple[torch.Tensor, torch.Tensor]: |
| """ |
| Quantize hidden states to FP4 for TRTLLM MoE. |
| |
| Global scale factor is set by ModelOptNvFp4FusedMoEMethod during weight loading. |
| Only block scales are computed at runtime for efficiency. |
| |
| Returns (packed_fp4_uint8, scale_float8_e4m3fn_runtime) |
| """ |
|
|
| |
| |
| hs_fp4_bytes, hs_sf_bytes = fp4_quantize( |
| hidden_states, |
| input_scale_quant, |
| 16, |
| False, |
| False, |
| ) |
|
|
| seq_len, hidden_size = hidden_states.shape |
| hs_fp4 = hs_fp4_bytes.reshape(seq_len, hidden_size // 2) |
| |
| hs_sf = hs_sf_bytes.view(torch.float8_e4m3fn).reshape(seq_len, hidden_size // 16) |
|
|
| return hs_fp4, hs_sf |
|
|
|
|
| def fused_experts_none_to_flashinfer_trtllm_fp4( |
| dispatch_output: StandardDispatchOutput, |
| quant_info: FlashInferTrtllmFp4MoeQuantInfo, |
| runner_config: MoeRunnerConfig, |
| use_routed_topk: bool = False, |
| ) -> StandardCombineInput: |
| """FlashInfer TRTLLM FP4 MoE forward pass. |
| |
| This function handles the FP4 TRTLLM MoE path that was previously in |
| ModelOptNvFp4FusedMoEMethod.apply. |
| """ |
| from flashinfer.fused_moe import ( |
| trtllm_fp4_block_scale_moe, |
| trtllm_fp4_block_scale_routed_moe, |
| ) |
|
|
| from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput |
| from sglang.srt.layers.moe.topk import TopKOutputChecker |
| from sglang.srt.layers.moe.utils import RoutingMethodType |
|
|
| _SUPPORTED_FP4_ACTIVATIONS = {"silu", "relu2", "gelu"} |
| assert runner_config.activation in _SUPPORTED_FP4_ACTIVATIONS, ( |
| f"Only {_SUPPORTED_FP4_ACTIVATIONS} are supported for FP4 MoE, " |
| f"got '{runner_config.activation}'." |
| ) |
|
|
| hidden_states = dispatch_output.hidden_states |
| topk_output = dispatch_output.topk_output |
|
|
| |
| if quant_info.use_per_token_activation: |
| from flashinfer import SfLayout, nvfp4_quantize |
|
|
| e4m3_max = 448.0 |
| if ( |
| envs.FLASHINFER_NVFP4_4OVER6.get() |
| and envs.FLASHINFER_NVFP4_4OVER6_E4M3_USE_256.get() |
| ): |
| e4m3_max = 256.0 |
|
|
| hs_fp4_bytes, hs_sf_bytes, per_token_scale = nvfp4_quantize( |
| hidden_states, |
| 1.0 / (e4m3_max * 6.0), |
| sfLayout=SfLayout.layout_linear, |
| per_token_activation=True, |
| ) |
|
|
| seq_len, hidden_size = hidden_states.shape |
| hs_fp4 = hs_fp4_bytes.reshape(seq_len, hidden_size // 2) |
| hs_scale_linear = hs_sf_bytes.view(torch.float8_e4m3fn).reshape( |
| seq_len, hidden_size // 16 |
| ) |
| else: |
| per_token_scale = None |
| hs_fp4, hs_scale_linear = quantize_hidden_states_fp4( |
| hidden_states, quant_info.w13_input_scale_quant |
| ) |
| hs_scale = hs_scale_linear.view(torch.float8_e4m3fn).reshape( |
| *hs_scale_linear.shape[:-1], -1 |
| ) |
| activation_type = get_activation_type( |
| runner_config.activation, is_gated=runner_config.is_gated |
| ) |
|
|
| |
| _clamp_val = runner_config.gemm1_clamp_limit |
| if _clamp_val is not None: |
| gemm1_clamp_limit = torch.full( |
| (quant_info.local_num_experts,), |
| _clamp_val, |
| dtype=torch.float32, |
| device=hs_fp4.device, |
| ) |
| else: |
| gemm1_clamp_limit = None |
|
|
| |
| |
| |
| |
| |
| if runner_config.gemm1_alpha is not None: |
| raise NotImplementedError( |
| "flashinfer_trtllm FP4 MoE does not support parameterized " |
| "(GPT-OSS-style) SwiGLU (gemm1_alpha is set); use " |
| "--moe-runner-backend flashinfer_cutlass instead." |
| ) |
|
|
| num_tokens = hs_fp4.shape[0] |
| hidden_size = ( |
| hs_fp4.shape[-1] * 2 if hs_fp4.dtype == torch.uint8 else hs_fp4.shape[-1] |
| ) |
| _provided = _moe_output_buf.get() |
| _symm_required = is_allocation_symmetric() |
| if ( |
| _provided is not None |
| and _provided.shape == (num_tokens, hidden_size) |
| and _provided.dtype == hidden_states.dtype |
| and _provided.device == hs_fp4.device |
| and ( |
| not _symm_required |
| or not is_symmetric_memory_enabled() |
| or is_tensor_in_symmetric_mempool(_provided) |
| ) |
| ): |
| symm_output = _provided |
| else: |
| with use_symmetric_memory(get_tp_group(), disabled=not _symm_required): |
| symm_output = torch.empty( |
| num_tokens, hidden_size, dtype=hidden_states.dtype, device=hs_fp4.device |
| ) |
|
|
| |
| if not use_routed_topk and TopKOutputChecker.format_is_standard(topk_output): |
| use_routed_topk = True |
|
|
| if use_routed_topk: |
| assert TopKOutputChecker.format_is_standard(topk_output) |
|
|
| packed_topk_ids = _pack_topk_for_flashinfer_routed( |
| topk_output.topk_ids, topk_output.topk_weights |
| ) |
| result = trtllm_fp4_block_scale_routed_moe( |
| topk_ids=packed_topk_ids, |
| routing_bias=None, |
| hidden_states=hs_fp4, |
| hidden_states_scale=hs_scale, |
| gemm1_weights=quant_info.w13_weight, |
| gemm1_weights_scale=quant_info.w13_weight_scale.view(torch.float8_e4m3fn), |
| gemm1_bias=None, |
| gemm1_alpha=None, |
| gemm1_beta=None, |
| gemm1_clamp_limit=gemm1_clamp_limit, |
| gemm2_weights=quant_info.w2_weight, |
| gemm2_weights_scale=quant_info.w2_weight_scale.view(torch.float8_e4m3fn), |
| gemm2_bias=None, |
| output1_scale_scalar=quant_info.g1_scale_c, |
| output1_scale_gate_scalar=quant_info.g1_alphas, |
| output2_scale_scalar=quant_info.g2_alphas, |
| per_token_scale=per_token_scale, |
| num_experts=quant_info.global_num_experts, |
| top_k=topk_output.topk_ids.shape[1], |
| n_group=0, |
| topk_group=0, |
| intermediate_size=quant_info.intermediate_size_per_partition, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=quant_info.local_num_experts, |
| routed_scaling_factor=None, |
| routing_method_type=1, |
| do_finalize=True, |
| activation_type=activation_type, |
| tune_max_num_tokens=next_power_of_2(hs_fp4.shape[0]), |
| output=symm_output, |
| )[0] |
| else: |
| assert TopKOutputChecker.format_is_bypassed(topk_output) |
|
|
| router_logits = topk_output.router_logits |
| topk_config = topk_output.topk_config |
| routing_method_type = quant_info.routing_method_type |
|
|
| correction_bias = ( |
| None |
| if topk_config.correction_bias is None |
| else topk_config.correction_bias.to(hidden_states.dtype) |
| ) |
| result = trtllm_fp4_block_scale_moe( |
| routing_logits=router_logits, |
| routing_bias=correction_bias, |
| hidden_states=hs_fp4, |
| hidden_states_scale=hs_scale, |
| gemm1_weights=quant_info.w13_weight, |
| gemm1_weights_scale=quant_info.w13_weight_scale.view(torch.float8_e4m3fn), |
| gemm1_bias=None, |
| gemm1_alpha=None, |
| gemm1_beta=None, |
| gemm1_clamp_limit=gemm1_clamp_limit, |
| gemm2_weights=quant_info.w2_weight, |
| gemm2_weights_scale=quant_info.w2_weight_scale.view(torch.float8_e4m3fn), |
| gemm2_bias=None, |
| output1_scale_scalar=quant_info.g1_scale_c, |
| output1_scale_gate_scalar=quant_info.g1_alphas, |
| output2_scale_scalar=quant_info.g2_alphas, |
| per_token_scale=per_token_scale, |
| num_experts=quant_info.global_num_experts, |
| top_k=topk_config.top_k, |
| n_group=topk_config.num_expert_group, |
| topk_group=topk_config.topk_group, |
| intermediate_size=quant_info.intermediate_size_per_partition, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=quant_info.local_num_experts, |
| routed_scaling_factor=runner_config.routed_scaling_factor, |
| routing_method_type=( |
| routing_method_type |
| if routing_method_type is not None |
| else RoutingMethodType.Default |
| ), |
| do_finalize=True, |
| activation_type=activation_type, |
| tune_max_num_tokens=next_power_of_2(hs_fp4.shape[0]), |
| output=symm_output, |
| )[0] |
|
|
| return StandardCombineInput(hidden_states=result) |
|
|
|
|
| @dataclass |
| class FlashInferTrtllmBf16MoeQuantInfo(MoeQuantInfo): |
| """Quantization payload consumed by FlashInfer TRT-LLM BF16 MoE kernels.""" |
|
|
| gemm1_weights: torch.Tensor |
| gemm2_weights: torch.Tensor |
|
|
| |
| global_num_experts: int |
| local_expert_offset: int |
|
|
|
|
| def fused_experts_none_to_flashinfer_trtllm_bf16( |
| dispatch_output: StandardDispatchOutput, |
| quant_info: FlashInferTrtllmBf16MoeQuantInfo, |
| runner_config: MoeRunnerConfig, |
| use_routed_topk: bool = False, |
| ) -> StandardCombineInput: |
| |
| from sglang.srt.layers.moe.token_dispatcher.standard import StandardCombineInput |
| from sglang.srt.layers.moe.topk import TopKOutputChecker |
| from sglang.srt.layers.moe.utils import RoutingMethodType |
|
|
| trtllm_bf16_routed_moe = None |
| trtllm_bf16_moe = None |
| if use_routed_topk: |
| try: |
| from flashinfer.fused_moe import trtllm_bf16_routed_moe |
| except ImportError as e: |
| raise ImportError( |
| "Can't import trtllm_bf16_routed_moe from flashinfer. " |
| "Please check flashinfer version to use bf16 with flashinfer_trtllm_routed backend." |
| ) from e |
| else: |
| try: |
| from flashinfer.fused_moe import trtllm_bf16_moe |
| except ImportError as e: |
| raise ImportError( |
| "Can't import trtllm_bf16_moe from flashinfer. " |
| "Please check flashinfer version to use bf16 with flashinfer_trtllm backend." |
| ) from e |
|
|
| _SUPPORTED_BF16_ACTIVATIONS = {"silu", "relu2"} |
| assert runner_config.activation in _SUPPORTED_BF16_ACTIVATIONS, ( |
| f"Only {_SUPPORTED_BF16_ACTIVATIONS} are supported for flashinfer trtllm bf16 moe, " |
| f"got '{runner_config.activation}'." |
| ) |
| if not use_routed_topk: |
| assert ( |
| dispatch_output.topk_output.topk_config.renormalize |
| ), "Renormalize is required for flashinfer trtllm moe" |
| assert ( |
| runner_config.num_fused_shared_experts == 0 |
| ), "Fused shared experts are not supported for flashinfer trtllm moe" |
| activation_type = get_activation_type( |
| runner_config.activation, is_gated=runner_config.is_gated |
| ) |
|
|
| hidden_states = dispatch_output.hidden_states |
| topk_output = dispatch_output.topk_output |
|
|
| with use_symmetric_memory(get_tp_group(), disabled=not is_allocation_symmetric()): |
| if use_routed_topk: |
| assert ( |
| runner_config.top_k is not None |
| ), "runner_config.top_k is required for flashinfer_trtllm_routed." |
| assert TopKOutputChecker.format_is_standard(topk_output) |
| routing_method_type = runner_config.routing_method_type |
| if routing_method_type is None: |
| routing_method_type = RoutingMethodType.Default |
| elif routing_method_type == RoutingMethodType.DeepSeekV3: |
| routing_method_type = RoutingMethodType.TopK |
|
|
| packed_topk_ids = _pack_topk_for_flashinfer_routed( |
| topk_ids=topk_output.topk_ids, |
| topk_weights=topk_output.topk_weights, |
| ) |
| final_hidden_states = trtllm_bf16_routed_moe( |
| topk_ids=packed_topk_ids, |
| hidden_states=hidden_states, |
| gemm1_weights=quant_info.gemm1_weights, |
| gemm2_weights=quant_info.gemm2_weights, |
| num_experts=quant_info.global_num_experts, |
| top_k=runner_config.top_k, |
| n_group=None, |
| topk_group=None, |
| intermediate_size=runner_config.intermediate_size_per_partition, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=runner_config.num_local_experts, |
| routing_method_type=routing_method_type, |
| routed_scaling_factor=( |
| runner_config.routed_scaling_factor |
| if runner_config.routed_scaling_factor is not None |
| else 1.0 |
| ), |
| tune_max_num_tokens=next_power_of_2(hidden_states.shape[0]), |
| activation_type=activation_type, |
| ) |
| else: |
| assert TopKOutputChecker.format_is_bypassed(topk_output) |
| topk_config = topk_output.topk_config |
|
|
| |
| final_hidden_states = trtllm_bf16_moe( |
| routing_logits=topk_output.router_logits, |
| routing_bias=topk_config.correction_bias, |
| hidden_states=hidden_states, |
| gemm1_weights=quant_info.gemm1_weights, |
| gemm2_weights=quant_info.gemm2_weights, |
| num_experts=quant_info.global_num_experts, |
| top_k=topk_config.top_k, |
| n_group=topk_config.num_expert_group, |
| topk_group=topk_config.topk_group, |
| intermediate_size=runner_config.intermediate_size_per_partition, |
| local_expert_offset=quant_info.local_expert_offset, |
| local_num_experts=runner_config.num_local_experts, |
| routing_method_type=runner_config.routing_method_type, |
| routed_scaling_factor=runner_config.routed_scaling_factor, |
| tune_max_num_tokens=next_power_of_2(hidden_states.shape[0]), |
| activation_type=activation_type, |
| ) |
|
|
| return StandardCombineInput(hidden_states=final_hidden_states) |
|
|
|
|
| @register_fused_func("none", "flashinfer_trtllm") |
| def fused_experts_none_to_flashinfer_trtllm( |
| dispatch_output: StandardDispatchOutput, |
| quant_info: MoeQuantInfo, |
| runner_config: MoeRunnerConfig, |
| ) -> StandardCombineInput: |
| """Dispatch to FP8 or FP4 FlashInfer TRT-LLM MoE based on quant_info type.""" |
| if isinstance(quant_info, FlashInferTrtllmFp4MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_fp4( |
| dispatch_output, quant_info, runner_config |
| ) |
| if isinstance(quant_info, FlashInferTrtllmFp8MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_fp8( |
| dispatch_output, quant_info, runner_config |
| ) |
| if isinstance(quant_info, FlashInferTrtllmBf16MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_bf16( |
| dispatch_output, quant_info, runner_config |
| ) |
| raise TypeError( |
| f"Unexpected quant_info type for flashinfer_trtllm: {type(quant_info)}" |
| ) |
|
|
|
|
| @register_fused_func("none", "flashinfer_trtllm_routed") |
| def fused_experts_none_to_flashinfer_trtllm_routed( |
| dispatch_output: StandardDispatchOutput, |
| quant_info: MoeQuantInfo, |
| runner_config: MoeRunnerConfig, |
| ) -> StandardCombineInput: |
| if isinstance(quant_info, FlashInferTrtllmFp4MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_fp4( |
| dispatch_output, |
| quant_info, |
| runner_config, |
| use_routed_topk=True, |
| ) |
| if isinstance(quant_info, FlashInferTrtllmFp8MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_fp8( |
| dispatch_output, |
| quant_info, |
| runner_config, |
| use_routed_topk=True, |
| ) |
| if isinstance(quant_info, FlashInferTrtllmBf16MoeQuantInfo): |
| return fused_experts_none_to_flashinfer_trtllm_bf16( |
| dispatch_output, |
| quant_info, |
| runner_config, |
| use_routed_topk=True, |
| ) |
| raise TypeError( |
| f"Unexpected quant_info type for flashinfer_trtllm_routed: {type(quant_info)}" |
| ) |
|
|
|
|
| |
| |
| if _SGLANG_EXPERIMENTAL_LORA_OPTI: |
| from sglang.srt.lora.trtllm_lora_temp import sgl_backend |
|
|