# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project import torch # this import will also register the custom ops # import vllm.model_executor.kernels.mhc # noqa: F401 import vllm.model_executor.kernels.mhc as mhc_kernels from vllm._aiter_ops import is_aiter_found_and_supported from vllm.model_executor.custom_op import CustomOp from vllm.platforms import current_platform from vllm.utils.import_utils import has_tilelang def _has_tilelang_mhc() -> bool: if not has_tilelang(): return False if current_platform.is_cuda(): return True if current_platform.is_rocm(): from vllm.platforms.rocm import on_gfx942 # TileLang MHC currently produces incorrect results on gfx942. Keep # gfx942 on the existing torch/triton fallbacks until that path is fixed. return not on_gfx942() return False HAS_TILELANG_MHC = _has_tilelang_mhc() HAS_AITER_MHC = is_aiter_found_and_supported() # --8<-- [start:mhc_pre] @CustomOp.register("mhc_pre") class MHCPreOp(CustomOp): """MHC pre block. Computes mix logits from RMS-normalized HC residual streams, then returns post_mix, comb_mix, and layer_input = sum_i pre_mix_i * residual_i. """ # --8<-- [end:mhc_pre] @classmethod def enabled(cls) -> bool: return True def forward_cuda( self, residual: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: return torch.ops.vllm.mhc_pre_tilelang( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, norm_weight, norm_eps, ) def forward_hip( self, residual: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: hidden_size = residual.shape[-1] if HAS_AITER_MHC and hidden_size % 256 == 0: return torch.ops.vllm.mhc_pre_aiter( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, ) elif HAS_TILELANG_MHC: return torch.ops.vllm.mhc_pre_tilelang( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, norm_weight, norm_eps, ) else: return self.forward_native( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, norm_weight, norm_eps, ) def forward_native( self, residual: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: return mhc_kernels.mhc_pre_torch( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, ) def forward_xpu( self, residual: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: return self.forward_native( residual, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, norm_weight, norm_eps, ) # --8<-- [start:mhc_post] @CustomOp.register("mhc_post") class MHCPostOp(CustomOp): """MHC post block. Combines the layer output with the HC residual streams: out_j = post_layer_mix_j * x + sum_i comb_res_mix_ij * residual_i. """ # --8<-- [end:mhc_post] @classmethod def enabled(cls) -> bool: return True def forward_cuda( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, ) -> torch.Tensor: return torch.ops.vllm.mhc_post_tilelang( x, residual, post_layer_mix, comb_res_mix ) def forward_hip( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, ) -> torch.Tensor: hidden_size = residual.shape[-1] if HAS_AITER_MHC and hidden_size % 256 == 0: return torch.ops.vllm.mhc_post_aiter( x, residual, post_layer_mix, comb_res_mix, ) if HAS_TILELANG_MHC: return torch.ops.vllm.mhc_post_tilelang( x, residual, post_layer_mix, comb_res_mix ) else: return self.forward_native(x, residual, post_layer_mix, comb_res_mix) def forward_native( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, ) -> torch.Tensor: return mhc_kernels.mhc_post_torch( x, residual, post_layer_mix, comb_res_mix, ) def forward_xpu( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, ) -> torch.Tensor: return self.forward_native( x, residual, post_layer_mix, comb_res_mix, ) # --8<-- [start:hc_head] @CustomOp.register("hc_head") class HCHeadOp(CustomOp): """HC head reduction for DeepSeek V4. Computes gates from the RMS-normalized flattened HC residual and returns out = sum_i gate_i * residual_i, collapsing hc_mult streams to one. """ # --8<-- [end:hc_head] @classmethod def enabled(cls) -> bool: return True def forward_cuda( self, hidden_states: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_norm_eps: float, hc_eps: float, ) -> torch.Tensor: hc_mult, hidden_size = hidden_states.shape[-2:] outer_shape = hidden_states.shape[:-2] hs_flat = hidden_states.view(-1, hc_mult, hidden_size) out = torch.ops.vllm.hc_head_fused_kernel_tilelang( hs_flat, hc_fn, hc_scale, hc_base, rms_norm_eps, hc_eps, ) return out.view(*outer_shape, hidden_size) def forward_hip( self, hidden_states: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_norm_eps: float, hc_eps: float, ) -> torch.Tensor: hc_mult, hidden_size = hidden_states.shape[-2:] outer_shape = hidden_states.shape[:-2] hs_flat = hidden_states.view(-1, hc_mult, hidden_size) if HAS_TILELANG_MHC: out = torch.ops.vllm.hc_head_fused_kernel_tilelang( hs_flat, hc_fn, hc_scale, hc_base, rms_norm_eps, hc_eps, ) else: num_tokens = hs_flat.shape[0] out = torch.empty( num_tokens, hidden_size, dtype=torch.bfloat16, device=hidden_states.device, ) torch.ops.vllm.hc_head_triton( hs_flat, hc_fn, hc_scale, hc_base, out, hidden_size, rms_norm_eps, hc_eps, hc_mult, ) return out.view(*outer_shape, hidden_size) def forward_native(self, *args, **kwargs): raise NotImplementedError("Native implementation of hc_head is not available") def forward_xpu( self, hidden_states: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_norm_eps: float, hc_eps: float, ) -> torch.Tensor: hc_mult, hidden_size = hidden_states.shape[-2:] outer_shape = hidden_states.shape[:-2] hs_flat = hidden_states.view(-1, hc_mult, hidden_size) num_tokens = hs_flat.shape[0] out = torch.empty( num_tokens, hidden_size, dtype=torch.bfloat16, device=hidden_states.device ) torch.ops.vllm.hc_head_triton( hs_flat, hc_fn, hc_scale, hc_base, out, hidden_size, rms_norm_eps, hc_eps, hc_mult, ) return out.view(*outer_shape, hidden_size) # --8<-- [start:mhc_fused_post_pre] @CustomOp.register("mhc_fused_post_pre") class MHCFusedPostPreOp(CustomOp): """Fused MHC post block followed by the next MHC pre block. Equivalent to applying MHCPostOp and then MHCPreOp to the updated residual streams, returning residual_cur, post_mix_cur, comb_mix_cur, and layer_input_cur. """ # --8<-- [end:mhc_fused_post_pre] @classmethod def enabled(cls) -> bool: return True def forward_cuda( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, tile_n: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: return torch.ops.vllm.mhc_fused_post_pre_tilelang( x, residual, post_layer_mix, comb_res_mix, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, tile_n, norm_weight, norm_eps, ) def forward_hip( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, tile_n: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: if HAS_TILELANG_MHC: return torch.ops.vllm.mhc_fused_post_pre_tilelang( x, residual, post_layer_mix, comb_res_mix, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, tile_n, norm_weight, norm_eps, ) return self.forward_native( x, residual, post_layer_mix, comb_res_mix, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, tile_n, norm_weight, norm_eps, ) def forward_native( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, tile_n: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: # Decompose into post + pre (no fused kernel available). residual_cur = mhc_kernels.mhc_post_torch( x, residual, post_layer_mix, comb_res_mix ) post_mix_cur, comb_mix_cur, layer_input_cur = mhc_kernels.mhc_pre_torch( residual_cur, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, ) return residual_cur, post_mix_cur, comb_mix_cur, layer_input_cur def forward_xpu( self, x: torch.Tensor, residual: torch.Tensor, post_layer_mix: torch.Tensor, comb_res_mix: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, rms_eps: float, hc_pre_eps: float, hc_sinkhorn_eps: float, hc_post_mult_value: float, sinkhorn_repeat: int, n_splits: int = 1, tile_n: int = 1, norm_weight: torch.Tensor | None = None, norm_eps: float = 0.0, ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: return self.forward_native( x, residual, post_layer_mix, comb_res_mix, fn, hc_scale, hc_base, rms_eps, hc_pre_eps, hc_sinkhorn_eps, hc_post_mult_value, sinkhorn_repeat, n_splits, tile_n, norm_weight, norm_eps, )