-
Notifications
You must be signed in to change notification settings - Fork 7.8k
[NVIDIA] Enable TRTLLM BF16 MoE on Blackwell GPUs #13798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
4cb84be
3f790bf
d8e4e40
c4473ce
4dfadca
fd0b86a
b0f0611
366834d
7e3f2d4
ef306da
4bf405d
c154225
d8e7185
d3e92a4
0a926b9
fecbe3f
4f356fc
6081e51
9c4b0a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -415,27 +415,25 @@ def get_moe_impl_class(quant_config: Optional[QuantizationConfig]): | |
| if get_moe_a2a_backend().is_deepep() or get_moe_a2a_backend().is_mooncake(): | ||
| return DeepEPMoE | ||
|
|
||
| # NEW: Direct FP4 detection (bypasses EP requirements) | ||
| # Check for FP4 quantization with TRTLLM flag, regardless of EP | ||
| if get_moe_runner_backend().is_flashinfer_trtllm(): | ||
| # NEW: Direct FP4 detection (bypasses EP requirements) | ||
| # Check for FP4 quantization with TRTLLM flag, regardless of EP | ||
| # FlashInferFP4MoE must be paired with ModelOptNvFp4FusedMoEMethod. | ||
| # If UnquantizedFusedMoEMethod is detected, fall back to FusedMoE instead. | ||
| if quant_config is None: | ||
| return FusedMoE | ||
| try: | ||
| # Check the quantization argument directly | ||
| if quant_config is not None and quant_config.get_name() == "modelopt_fp4": | ||
| if quant_config is not None and quant_config.get_name() == "modelopt_fp4": | ||
| try: | ||
| from sglang.srt.layers.moe.fused_moe_triton.layer import ( | ||
| FlashInferFP4MoE, | ||
| ) | ||
|
|
||
| return FlashInferFP4MoE | ||
| except: | ||
| pass | ||
| except: | ||
| pass | ||
| elif (quant_config is None) or ( | ||
| quant_config is not None and quant_config.get_name() == "fp8" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should it be
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it should be. Fixed |
||
| ): | ||
|
b8zhong marked this conversation as resolved.
Outdated
|
||
| # FlashInferFusedMoE support bf16 and fp8 | ||
| return FlashInferFusedMoE | ||
|
|
||
| if get_moe_runner_backend().is_flashinfer_trtllm() and quant_config is not None: | ||
| # FIXME: FlashInferFusedMoE only supports fp8 quant now | ||
| return FlashInferFusedMoE | ||
| if get_moe_runner_backend().is_flashinfer_cutlass(): | ||
| return FusedMoE | ||
| return FusedMoE | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,10 +135,14 @@ def apply( | |
| class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp): | ||
| """MoE method without quantization.""" | ||
|
|
||
| def __init__(self, use_triton_kernels: bool = False): | ||
| def __init__( | ||
| self, use_triton_kernels: bool = False, use_flashinfer_trtllm_moe: bool = False | ||
| ): | ||
| super().__init__() | ||
| self.use_triton_kernels = use_triton_kernels | ||
| self.with_bias = False | ||
| self.use_flashinfer_trtllm_moe = use_flashinfer_trtllm_moe | ||
| self._cache_permute_indices = dict({}) | ||
|
|
||
| def create_weights( | ||
| self, | ||
|
|
@@ -215,6 +219,68 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None: | |
| if _is_cpu and _is_cpu_amx_available: | ||
| _amx_process_weight_after_loading(layer, ["w13_weight", "w2_weight"]) | ||
|
|
||
| # Reorder rows of W1 for fused gated activation | ||
| if self.use_flashinfer_trtllm_moe: | ||
| from flashinfer.fused_moe.core import ( | ||
| _maybe_get_cached_w3_w1_permute_indices, | ||
| convert_to_block_layout, | ||
| get_w2_permute_indices_with_cache, | ||
| ) | ||
|
|
||
| # w1 and w3 have been swapped, so we don't need do that here | ||
| epilogue_tile_m = 128 | ||
| block_k = 128 | ||
| w13_weights_bf16_shuffled = [] | ||
| w2_weights_bf16_shuffled = [] | ||
| for i in range(layer.num_local_experts): | ||
| permute_indices = _maybe_get_cached_w3_w1_permute_indices( | ||
| self._cache_permute_indices, | ||
| layer.w13_weight.data[i].view(torch.uint8), | ||
| epilogue_tile_m, | ||
| ) | ||
| tmp_weights1 = ( | ||
| layer.w13_weight.data[i] | ||
| .clone() | ||
| .view(torch.uint8)[permute_indices.to(layer.w13_weight.data.device)] | ||
| .contiguous() | ||
| ) | ||
|
|
||
| permute_indices = get_w2_permute_indices_with_cache( | ||
| self._cache_permute_indices, | ||
| layer.w2_weight.data[i].view(torch.uint8), | ||
| epilogue_tile_m, | ||
| ) | ||
| tmp_weights2 = ( | ||
| layer.w2_weight.data[i] | ||
| .clone() | ||
| .view(torch.uint8)[permute_indices.to(layer.w2_weight.data.device)] | ||
| .contiguous() | ||
| ) | ||
|
|
||
| tmp_weights1 = convert_to_block_layout( | ||
| tmp_weights1.view(torch.uint8), block_k | ||
| ) | ||
| tmp_weights2 = convert_to_block_layout( | ||
| tmp_weights2.view(torch.uint8), block_k | ||
| ) | ||
|
|
||
| w13_weights_bf16_shuffled.append(tmp_weights1.view(torch.bfloat16)) | ||
| w2_weights_bf16_shuffled.append(tmp_weights2.view(torch.bfloat16)) | ||
|
|
||
| # Stack weights for all experts | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Convert all experts layout and stack may double the memory usage, which may cause oom when loading weights.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This makes sense. Fixed by inplace convert. |
||
| w13_weights_bf16_shuffled = ( | ||
| torch.stack(w13_weights_bf16_shuffled).view(torch.bfloat16).contiguous() | ||
| ) | ||
| w2_weights_bf16_shuffled = ( | ||
| torch.stack(w2_weights_bf16_shuffled).view(torch.bfloat16).contiguous() | ||
| ) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The w13_weights_bf16_shuffled = torch.stack(w13_weights_bf16_shuffled).contiguous()
w2_weights_bf16_shuffled = torch.stack(w2_weights_bf16_shuffled).contiguous() |
||
| layer.w13_weight = torch.nn.Parameter( | ||
| w13_weights_bf16_shuffled, requires_grad=False | ||
| ) | ||
| layer.w2_weight = torch.nn.Parameter( | ||
| w2_weights_bf16_shuffled, requires_grad=False | ||
| ) | ||
|
|
||
| return | ||
|
|
||
| def create_moe_runner( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.