| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- # SPDX-License-Identifier: Apache-2.0
- # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
- """b12x modular tensor-parallel fused MoE backend."""
- from collections.abc import Iterable
- from typing import Any
- import torch
- import vllm.model_executor.layers.fused_moe.modular_kernel as mk
- from vllm.logger import init_logger
- from vllm.model_executor.layers.fused_moe.activation import MoEActivation
- from vllm.model_executor.layers.fused_moe.config import (
- FusedMoEParallelConfig,
- FusedMoEQuantConfig,
- )
- from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
- TopKWeightAndReduceNoOP,
- )
- from vllm.model_executor.layers.quantization.utils.quant_utils import (
- QuantKey,
- kMxfp4Static,
- kMxfp8Dynamic,
- kNvfp4Dynamic,
- kNvfp4Static,
- )
- from vllm.model_executor.utils import replace_parameter
- from vllm.platforms import current_platform
- from vllm.utils.b12x import (
- B12xWarmupUnit,
- get_b12x_fused_moe,
- reuse_packed_weight_storage,
- )
- logger = init_logger(__name__)
- _B12X_MOE_MODES: dict[
- tuple[torch.dtype | str | None, torch.dtype | str | None],
- tuple[str, str, str],
- ] = {
- ("mxfp4", "mxfp8"): ("w4a8_mx", "fp4_e8m0_k32", "w31"),
- ("mxfp4", None): ("w4a16", "fp4_e8m0_k32", "w31"),
- ("nvfp4", "nvfp4"): ("nvfp4", "modelopt_nvfp4", "w31"),
- ("nvfp4", "mxfp8"): ("w4a8_nvfp4", "modelopt_nvfp4", "w31"),
- ("nvfp4", None): ("w4a16", "modelopt_nvfp4", "w13"),
- }
- def _require_b12x_fused_moe() -> Any:
- fused_moe = get_b12x_fused_moe()
- assert fused_moe is not None
- return fused_moe
- def _b12x_activation_name(activation: MoEActivation) -> str:
- if activation == MoEActivation.SILU:
- return "silu"
- if activation in (MoEActivation.RELU2, MoEActivation.RELU2_NO_MUL):
- return "relu2"
- return activation.value
- def _b12x_scratch_nbytes(plan: Any) -> int:
- specs = plan.scratch_specs()
- if len(specs) != 1:
- raise RuntimeError(f"expected one b12x MoE scratch buffer, got {len(specs)}")
- spec = specs[0]
- if spec.dtype != torch.uint8:
- raise TypeError(f"expected b12x MoE scratch dtype uint8, got {spec.dtype}")
- return int(spec.shape[0])
- def _b12x_moe_execution_plan(
- *,
- tokens: int,
- topk: int,
- prepared: Any,
- quant_mode: str,
- apply_router_weight_on_input: bool,
- swiglu_limit: float | None,
- swiglu_alpha: float | None,
- swiglu_beta: float | None,
- ) -> Any:
- fused_moe = _require_b12x_fused_moe()
- return fused_moe.plan_execution(
- num_tokens=max(int(tokens), 1),
- num_topk=int(topk),
- device=prepared.w1_fp4.device,
- weight_plan=prepared.plan,
- quant_mode=quant_mode,
- apply_router_weight_on_input=apply_router_weight_on_input,
- swiglu_limit=swiglu_limit,
- swiglu_alpha=swiglu_alpha,
- swiglu_beta=swiglu_beta,
- )
- def _run_b12x_moe_plan(
- *,
- plan: Any,
- scratch: torch.Tensor,
- hidden_states: torch.Tensor,
- prepared: Any,
- topk_weights: torch.Tensor,
- topk_ids: torch.Tensor,
- output: torch.Tensor,
- unit_scale_contract: bool,
- ) -> None:
- fused_moe = _require_b12x_fused_moe()
- binding = fused_moe.bind(
- plan,
- scratch=scratch,
- a=hidden_states,
- experts=prepared,
- topk_weights=topk_weights,
- topk_ids=topk_ids,
- output=output,
- input_scales_static=True,
- unit_scale_contract=unit_scale_contract,
- )
- fused_moe.run(binding=binding)
- def _is_current_stream_capturing() -> bool:
- is_capturing = getattr(torch.cuda, "is_current_stream_capturing", None)
- return bool(is_capturing is not None and is_capturing())
- def _normalize_topk_ids(topk_ids: torch.Tensor) -> torch.Tensor:
- if topk_ids.dtype == torch.int32 and topk_ids.is_contiguous():
- return topk_ids
- if _is_current_stream_capturing():
- raise RuntimeError(
- "b12x MoE topk_ids normalization would allocate during CUDA capture"
- )
- return topk_ids.to(dtype=torch.int32).contiguous()
- def _normalize_topk_weights(topk_weights: torch.Tensor) -> torch.Tensor:
- if topk_weights.dtype == torch.float32 and topk_weights.is_contiguous():
- return topk_weights
- if _is_current_stream_capturing():
- raise RuntimeError(
- "b12x MoE topk_weights normalization would allocate during CUDA capture"
- )
- return topk_weights.to(dtype=torch.float32).contiguous()
- def _workspace_as_b12x_scratch(
- workspace: torch.Tensor | None,
- plan: Any,
- ) -> torch.Tensor:
- if workspace is None:
- raise RuntimeError("b12x MoE requires workspace2 scratch")
- if not workspace.is_contiguous():
- raise ValueError("b12x MoE workspace2 must be contiguous")
- scratch = workspace.view(-1).view(torch.uint8)
- required_nbytes = _b12x_scratch_nbytes(plan)
- if scratch.numel() < required_nbytes:
- raise ValueError(
- "b12x MoE workspace2 is too small: "
- f"have={scratch.numel()} bytes, need={required_nbytes} bytes"
- )
- return scratch
- def _replace_parameter_with_empty(
- layer: torch.nn.Module,
- name: str,
- ) -> torch.Tensor | None:
- parameter = getattr(layer, name, None)
- if not isinstance(parameter, torch.Tensor):
- return None
- empty = torch.empty((0,), dtype=parameter.dtype, device=parameter.device)
- replace_parameter(layer, name, empty)
- return getattr(layer, name)
- def _normalize_expert_scale(scale: torch.Tensor) -> torch.Tensor:
- if scale.ndim == 2:
- if scale.shape[1] not in (1, 2):
- raise ValueError(
- "expected an expert scale with one or two columns, got "
- f"{tuple(scale.shape)}"
- )
- scale = scale[:, 0]
- return scale.to(dtype=torch.float32).contiguous()
- def _canonicalize_fp4_zero_signs_(packed: torch.Tensor) -> None:
- """Clear sign bits from packed FP4 zero values in place."""
- packed = packed.view(torch.uint8)
- magnitude = packed & 0x77
- nonzero = (magnitude | (magnitude >> 1) | (magnitude >> 2)) & 0x11
- packed.bitwise_and_(0x77 | (nonzero << 3))
- class B12xExperts(mk.FusedMoEExpertsModular):
- """FP4 MoE experts backed by the b12x SM12x planned API."""
- def __init__(
- self,
- moe_config: mk.FusedMoEConfig,
- quant_config: FusedMoEQuantConfig,
- ):
- super().__init__(moe_config, quant_config)
- if quant_config.weight_quant_dtype not in ("mxfp4", "nvfp4"):
- raise ValueError(
- "b12x MoE requires MXFP4 or NVFP4 weights, got "
- f"{quant_config.weight_quant_dtype}"
- )
- scheme = (
- quant_config.weight_quant_dtype,
- quant_config.quant_dtype,
- )
- try:
- self._quant_mode, self._source_format, self._w13_layout = _B12X_MOE_MODES[
- scheme
- ]
- except KeyError as exc:
- raise ValueError(
- f"unsupported b12x MoE quantization scheme {scheme}"
- ) from exc
- self._prepared_experts: Any | None = None
- self._source_parameters_released = False
- self._unit_scales: dict[torch.device, torch.Tensor] = {}
- self._plans: dict[tuple[int, int, MoEActivation, bool], Any] = {}
- self._apply_router_weight_on_input = False
- def _unit_scale(self, device: torch.device, num_experts: int) -> torch.Tensor:
- scale = self._unit_scales.get(device)
- if scale is None or scale.numel() != num_experts:
- scale = torch.ones(num_experts, dtype=torch.float32, device=device)
- self._unit_scales[device] = scale
- return scale
- def _weight_global_scale(
- self,
- device: torch.device,
- num_experts: int,
- scale: torch.Tensor | None,
- name: str,
- ) -> torch.Tensor:
- if self._source_format != "modelopt_nvfp4":
- return self._unit_scale(device, num_experts)
- if scale is None:
- raise ValueError(f"b12x NVFP4 MoE requires {name}")
- scale = _normalize_expert_scale(scale)
- if scale.numel() != num_experts:
- raise ValueError(
- f"b12x NVFP4 MoE expected {num_experts} {name} values, "
- f"got {scale.numel()}"
- )
- return scale.to(device=device)
- def _swiglu_params(
- self,
- activation: MoEActivation,
- ) -> tuple[float | None, float | None, float | None]:
- if activation in (
- MoEActivation.SITU,
- MoEActivation.RELU2,
- MoEActivation.RELU2_NO_MUL,
- ):
- return None, None, None
- limit = self.quant_config.gemm1_clamp_limit
- if limit is None:
- limit = self.moe_config.swiglu_limit
- if activation != MoEActivation.SWIGLUOAI_UNINTERLEAVE:
- return limit, None, None
- alpha = self.quant_config.gemm1_alpha
- if alpha is None:
- alpha = self.moe_config.swiglu_alpha
- beta = self.quant_config.gemm1_beta
- if beta is None:
- beta = self.moe_config.swiglu_beta
- return limit, alpha, beta
- def _prepare_experts(
- self,
- *,
- w1: torch.Tensor,
- w2: torch.Tensor,
- activation: MoEActivation,
- params_dtype: torch.dtype,
- ) -> Any:
- quant_mode = self._quant_mode
- if _is_current_stream_capturing():
- raise RuntimeError(
- "b12x MoE weights must be prepared before CUDA graph capture"
- )
- if self.w1_scale is None or self.w2_scale is None:
- raise ValueError("b12x MoE requires w1 and w2 block scales")
- _canonicalize_fp4_zero_signs_(w1)
- _canonicalize_fp4_zero_signs_(w2)
- fused_moe = _require_b12x_fused_moe()
- num_experts = int(w1.shape[0])
- hidden_size = int(w2.shape[1])
- intermediate_size = int(w2.shape[2]) * 2
- unit_scale = self._unit_scale(w1.device, num_experts)
- w1_global_scale = self._weight_global_scale(
- w1.device, num_experts, self.g1_alphas, "w1 global scales"
- )
- w2_global_scale = self._weight_global_scale(
- w2.device, num_experts, self.g2_alphas, "w2 global scales"
- )
- if quant_mode in ("nvfp4", "w4a8_nvfp4"):
- if self.a1_gscale is None or self.a2_gscale is None:
- raise ValueError("b12x NVFP4 MoE requires activation global scales")
- a1_gscale = _normalize_expert_scale(self.a1_gscale).to(w1.device)
- a2_gscale = _normalize_expert_scale(self.a2_gscale).to(w2.device)
- else:
- a1_gscale = unit_scale
- a2_gscale = unit_scale
- weight_plan = fused_moe.plan_weights(
- quant_modes=quant_mode,
- source_format=self._source_format,
- activation=_b12x_activation_name(activation),
- params_dtype=params_dtype,
- num_experts=num_experts,
- hidden_size=hidden_size,
- intermediate_size=intermediate_size,
- w13_layout=self._w13_layout,
- )
- return fused_moe.prepare_weights(
- plan=weight_plan,
- w1_fp4=w1,
- w1_blockscale=self.w1_scale,
- w1_global_scale=w1_global_scale,
- a1_gscale=a1_gscale,
- w2_fp4=w2,
- w2_blockscale=self.w2_scale,
- w2_global_scale=w2_global_scale,
- a2_gscale=a2_gscale,
- params_dtype=params_dtype,
- )
- def _refresh_quant_config(self, layer: torch.nn.Module) -> None:
- self.quant_config._w1.scale = layer.w13_weight_scale
- self.quant_config._w2.scale = layer.w2_weight_scale
- if self._source_format != "modelopt_nvfp4":
- return
- self.quant_config._w1.alpha_or_gscale = layer.w13_weight_scale_2
- self.quant_config._w2.alpha_or_gscale = layer.w2_weight_scale_2
- if self._quant_mode in ("nvfp4", "w4a8_nvfp4"):
- self.quant_config._a1.alpha_or_gscale = 1.0 / layer.w13_input_scale
- self.quant_config._a2.alpha_or_gscale = 1.0 / layer.w2_input_scale
- def _release_source_parameters(self, layer: torch.nn.Module) -> None:
- if self._source_parameters_released:
- return
- w1_scale = _replace_parameter_with_empty(layer, "w13_weight_scale")
- w2_scale = _replace_parameter_with_empty(layer, "w2_weight_scale")
- if w1_scale is not None:
- self.quant_config._w1.scale = w1_scale
- if w2_scale is not None:
- self.quant_config._w2.scale = w2_scale
- _replace_parameter_with_empty(layer, "w13_weight")
- _replace_parameter_with_empty(layer, "w2_weight")
- self._source_parameters_released = True
- def _reuse_prepared_storage(self, layer: torch.nn.Module, prepared: Any) -> Any:
- previous = getattr(layer, "_b12x_prepared_experts", None)
- prepared = reuse_packed_weight_storage(previous, prepared)
- if prepared is not previous:
- self._plans.clear()
- self._prepared_experts = prepared
- layer._b12x_prepared_experts = prepared
- return prepared
- def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
- self._apply_router_weight_on_input = layer.apply_router_weight_on_input
- if self._apply_router_weight_on_input and self._quant_mode != "w4a16":
- raise ValueError(
- "b12x MoE supports apply_router_weight_on_input only with W4A16"
- )
- self._source_parameters_released = False
- self._refresh_quant_config(layer)
- prepared = self._prepare_experts(
- w1=layer.w13_weight,
- w2=layer.w2_weight,
- activation=layer.activation,
- params_dtype=self.moe_config.in_dtype,
- )
- prepared = self._reuse_prepared_storage(layer, prepared)
- if prepared.plan.discards_source_parameters:
- self._release_source_parameters(layer)
- layer.b12x_warmup_provider = self
- @staticmethod
- def is_supported_config(
- cls: type[mk.FusedMoEExperts],
- moe_config: mk.FusedMoEConfig,
- weight_key: QuantKey | None,
- activation_key: QuantKey | None,
- activation_format: mk.FusedMoEActivationFormat,
- ) -> tuple[bool, str | None]:
- if moe_config.has_bias:
- return False, "kernel does not support expert biases"
- if moe_config.in_dtype not in (torch.float16, torch.bfloat16):
- return (
- False,
- f"kernel does not support {moe_config.in_dtype} input/output dtype",
- )
- if moe_config.activation == MoEActivation.SITU and (
- moe_config.activation_situ_beta != 4.0
- or moe_config.activation_situ_linear_beta != 25.0
- ):
- return False, "kernel supports only SiTU beta=4 and linear_beta=25"
- if (
- activation_key is not None
- and moe_config.activation == MoEActivation.SWIGLUOAI_UNINTERLEAVE
- ):
- return (
- False,
- "kernel does not support swigluoai_uninterleave with W4A8",
- )
- unpadded_intermediate_size = (
- moe_config.intermediate_size_per_partition_unpadded
- or moe_config.intermediate_size_per_partition
- )
- if weight_key == kMxfp4Static and unpadded_intermediate_size % 32 != 0:
- return (
- False,
- "MXFP4 requires the per-rank intermediate size to be divisible by 32",
- )
- if weight_key == kMxfp4Static and activation_key == kMxfp8Dynamic:
- if moe_config.activation not in (
- MoEActivation.SILU,
- MoEActivation.SITU,
- ):
- return False, "MXFP4 W4A8 supports only SiLU and SiTU"
- if (
- moe_config.hidden_dim % 256 != 0
- or moe_config.intermediate_size_per_partition % 32 != 0
- ):
- return (
- False,
- "MXFP4 W4A8 requires hidden size divisible by 256 and "
- "per-rank intermediate size divisible by 32",
- )
- return mk.FusedMoEExperts.is_supported_config(
- cls, moe_config, weight_key, activation_key, activation_format
- )
- @staticmethod
- def _supports_current_device() -> bool:
- if not (
- current_platform.is_cuda()
- and current_platform.is_device_capability_family(120)
- ):
- return False
- fused_moe = get_b12x_fused_moe()
- if fused_moe is None:
- return False
- return fused_moe.is_supported()
- @staticmethod
- def _supports_no_act_and_mul() -> bool:
- return True
- @staticmethod
- def _supports_quant_scheme(
- weight_key: QuantKey | None,
- activation_key: QuantKey | None,
- ) -> bool:
- return (weight_key, activation_key) in (
- (kMxfp4Static, kMxfp8Dynamic),
- (kMxfp4Static, None),
- (kNvfp4Static, kNvfp4Dynamic),
- (kNvfp4Static, kMxfp8Dynamic),
- (kNvfp4Static, None),
- )
- @staticmethod
- def _supports_activation(activation: MoEActivation) -> bool:
- return activation in (
- MoEActivation.SILU,
- MoEActivation.SITU,
- MoEActivation.SWIGLUOAI_UNINTERLEAVE,
- MoEActivation.RELU2_NO_MUL,
- )
- @staticmethod
- def _supports_parallel_config(
- moe_parallel_config: FusedMoEParallelConfig,
- ) -> bool:
- return (
- not moe_parallel_config.use_ep
- and moe_parallel_config.ep_size == 1
- and not moe_parallel_config.use_all2all_kernels
- and not moe_parallel_config.enable_eplb
- )
- @staticmethod
- def activation_format() -> mk.FusedMoEActivationFormat:
- return mk.FusedMoEActivationFormat.Standard
- @property
- def expects_unquantized_inputs(self) -> bool:
- return True
- def supports_expert_map(self) -> bool:
- return False
- def finalize_weight_and_reduce_impl(self) -> mk.TopKWeightAndReduce:
- return TopKWeightAndReduceNoOP()
- def _prepared(self) -> Any:
- if self._prepared_experts is None:
- raise RuntimeError(
- "b12x MoE weights must be prepared by process_weights_after_loading"
- )
- return self._prepared_experts
- def moe_problem_size(
- self,
- a1: torch.Tensor,
- w1: torch.Tensor,
- w2: torch.Tensor,
- topk_ids: torch.Tensor,
- ) -> tuple[int, int, int, int, int]:
- if w1.numel() and w2.numel():
- return super().moe_problem_size(a1, w1, w2, topk_ids)
- prepared = self._prepared()
- tokens = int(a1.shape[0] if a1.ndim == 2 else a1.shape[1])
- return (
- int(prepared.num_experts),
- tokens,
- int(prepared.intermediate_size) * 2,
- int(a1.shape[-1]),
- int(topk_ids.shape[1]),
- )
- def _plan(
- self,
- *,
- tokens: int,
- topk: int,
- activation: MoEActivation,
- apply_router_weight_on_input: bool = False,
- ) -> Any:
- fused_moe = _require_b12x_fused_moe()
- key = (
- max(int(tokens), 1),
- int(topk),
- activation,
- bool(apply_router_weight_on_input),
- )
- plan = self._plans.get(key)
- if plan is not None:
- return plan
- if _is_current_stream_capturing():
- raise RuntimeError("b12x MoE plans must be created before CUDA capture")
- limit, alpha, beta = self._swiglu_params(activation)
- prepared = self._prepared()
- plan = fused_moe.plan(
- fused_moe.Caps(
- max_tokens=key[0],
- num_topk=key[1],
- device=prepared.w1_fp4.device,
- weight_plan=prepared.plan,
- core_token_counts=(key[0],),
- route_num_experts=0,
- quant_mode=self._quant_mode,
- apply_router_weight_on_input=key[3],
- swiglu_limit=limit,
- swiglu_alpha=alpha,
- swiglu_beta=beta,
- frozen=True,
- )
- )
- self._plans[key] = plan
- return plan
- def get_b12x_warmup_unit(
- self,
- layer: torch.nn.Module,
- token_counts: tuple[int, ...],
- output_dtype: torch.dtype,
- ) -> B12xWarmupUnit:
- assert output_dtype == self.moe_config.in_dtype
- prepared = self._prepared()
- activation = layer.activation
- limit, alpha, beta = self._swiglu_params(activation)
- def compile() -> None:
- self.warmup_launches(layer, token_counts=token_counts)
- return B12xWarmupUnit(
- name="MoE",
- key=(
- type(self),
- prepared.w1_fp4.device,
- output_dtype,
- self._quant_mode,
- self._source_format,
- self._w13_layout,
- int(prepared.num_experts),
- int(prepared.hidden_size),
- int(prepared.intermediate_size),
- int(self.moe_config.experts_per_token),
- _b12x_activation_name(activation),
- bool(layer.apply_router_weight_on_input),
- limit,
- alpha,
- beta,
- ),
- compile=compile,
- )
- @torch.inference_mode()
- def warmup_launches(
- self,
- layer: torch.nn.Module,
- *,
- token_counts: Iterable[int],
- ) -> int:
- """Compile one representative launch for every planned regime."""
- activation = layer.activation
- dtype = self.moe_config.in_dtype
- topk = int(self.moe_config.experts_per_token)
- apply_router_weight_on_input = bool(layer.apply_router_weight_on_input)
- limit, alpha, beta = self._swiglu_params(activation)
- prepared = self._prepared()
- device = prepared.w1_fp4.device
- launch_tokens: dict[tuple[Any, ...], int] = {}
- for tokens in sorted({int(count) for count in token_counts if int(count) > 0}):
- execution_plan = _b12x_moe_execution_plan(
- tokens=tokens,
- topk=topk,
- prepared=prepared,
- quant_mode=self._quant_mode,
- apply_router_weight_on_input=apply_router_weight_on_input,
- swiglu_limit=limit,
- swiglu_alpha=alpha,
- swiglu_beta=beta,
- )
- signature = (execution_plan.implementation, execution_plan.execution)
- launch_tokens.setdefault(signature, tokens)
- for tokens in launch_tokens.values():
- hidden_states = torch.zeros(
- (tokens, int(prepared.hidden_size)),
- dtype=dtype,
- device=device,
- )
- output = torch.empty_like(hidden_states)
- topk_ids = (
- torch.arange(topk, device=device, dtype=torch.int32)
- .unsqueeze(0)
- .expand(tokens, -1)
- .contiguous()
- )
- topk_ids.remainder_(int(prepared.num_experts))
- topk_weights = torch.full(
- (tokens, topk),
- 1.0 / topk,
- dtype=torch.float32,
- device=device,
- )
- plan = self._plan(
- tokens=tokens,
- topk=topk,
- activation=activation,
- apply_router_weight_on_input=apply_router_weight_on_input,
- )
- scratch = torch.empty(
- (_b12x_scratch_nbytes(plan),),
- dtype=torch.uint8,
- device=device,
- )
- _run_b12x_moe_plan(
- plan=plan,
- scratch=scratch,
- hidden_states=hidden_states,
- prepared=prepared,
- topk_weights=topk_weights,
- topk_ids=topk_ids,
- output=output,
- unit_scale_contract=self._quant_mode == "w4a16",
- )
- return len(launch_tokens)
- def workspace_shapes(
- self,
- M: int,
- N: int,
- K: int,
- topk: int,
- global_num_experts: int,
- local_num_experts: int,
- expert_tokens_meta: mk.ExpertTokensMetadata | None,
- activation: MoEActivation,
- ) -> tuple[tuple[int, ...], tuple[int, ...], tuple[int, ...]]:
- del N, global_num_experts, local_num_experts, expert_tokens_meta
- plan = self._plan(
- tokens=M,
- topk=topk,
- activation=activation,
- apply_router_weight_on_input=self._apply_router_weight_on_input,
- )
- itemsize = self.moe_config.in_dtype.itemsize
- scratch_elements = max(
- 1, (_b12x_scratch_nbytes(plan) + itemsize - 1) // itemsize
- )
- return (0,), (scratch_elements,), (M, K)
- def apply(
- self,
- output: torch.Tensor,
- hidden_states: torch.Tensor,
- w1: torch.Tensor,
- w2: torch.Tensor,
- topk_weights: torch.Tensor,
- topk_ids: torch.Tensor,
- activation: MoEActivation,
- global_num_experts: int,
- expert_map: torch.Tensor | None,
- a1q_scale: torch.Tensor | None,
- a2_scale: torch.Tensor | None,
- workspace13: torch.Tensor | None,
- workspace2: torch.Tensor | None,
- expert_tokens_meta: mk.ExpertTokensMetadata | None,
- apply_router_weight_on_input: bool | None,
- ) -> None:
- del w1, w2, global_num_experts
- del a1q_scale, a2_scale, workspace13, expert_tokens_meta
- if expert_map is not None:
- raise ValueError("b12x TP MoE does not support expert maps")
- if bool(apply_router_weight_on_input) != self._apply_router_weight_on_input:
- raise ValueError(
- "apply_router_weight_on_input does not match the prepared b12x MoE plan"
- )
- prepared = self._prepared()
- topk_ids = _normalize_topk_ids(topk_ids)
- topk_weights = _normalize_topk_weights(topk_weights)
- plan = self._plan(
- tokens=int(hidden_states.shape[0]),
- topk=int(topk_ids.shape[1]),
- activation=activation,
- apply_router_weight_on_input=bool(apply_router_weight_on_input),
- )
- scratch = _workspace_as_b12x_scratch(workspace2, plan)
- _run_b12x_moe_plan(
- plan=plan,
- scratch=scratch,
- hidden_states=hidden_states,
- prepared=prepared,
- topk_weights=topk_weights,
- topk_ids=topk_ids,
- output=output,
- unit_scale_contract=self._quant_mode == "w4a16",
- )
- def moe_sum(self, input: torch.Tensor, output: torch.Tensor) -> None:
- raise NotImplementedError("LoRA is not supported for B12xExperts")
|