# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project import torch import torch.nn.functional as F from torch import Tensor from vllm.triton_utils import tl, triton from vllm.utils.torch_utils import direct_register_custom_op @triton.jit def _rmsnorm_nw_kernel( x_ptr, out_ptr, stride_row, D, eps, RBLOCK: tl.constexpr, ): """Weight-free RMSNorm Triton kernel: out = x * rsqrt(mean(x², -1) + eps).""" row = tl.program_id(0) cols = tl.arange(0, RBLOCK) mask = cols < D x = tl.load( x_ptr + row * stride_row + cols, mask=mask, other=0.0, eviction_policy="evict_first", ).to(tl.float32) var = tl.sum(x * x, 0) / D rstd = tl.rsqrt(var + eps) out = (x * rstd).to(out_ptr.dtype.element_ty) tl.store(out_ptr + row * D + cols, out, mask=mask, eviction_policy="evict_first") def rmsnorm_nw(x: Tensor, eps: float) -> Tensor: """Weight-free RMSNorm over the last dimension. Treats *x* as ``[num_rows, D]`` where ``num_rows = product(shape[:-1])``. Returns a contiguous tensor with the same shape and dtype as *x*. """ orig_shape = x.shape D = orig_shape[-1] x_2d = x.reshape(-1, D) num_rows = x_2d.shape[0] out = torch.empty_like(x_2d) RBLOCK = triton.next_power_of_2(D) _rmsnorm_nw_kernel[(num_rows,)]( x_2d, out, x_2d.stride(0), D, eps, RBLOCK=RBLOCK, num_warps=1 if RBLOCK <= 512 else (4 if RBLOCK <= 4096 else 8), ) return out.view(orig_shape) @triton.jit def _hc_head_reduce_store_kernel( pre_ptr, x_ptr, out_ptr, hidden_size: tl.constexpr, hc_mult: tl.constexpr, pre_stride_t: tl.constexpr, pre_stride_m: tl.constexpr, x_stride_t: tl.constexpr, x_stride_m: tl.constexpr, x_stride_h: tl.constexpr, out_stride_t: tl.constexpr, out_stride_h: tl.constexpr, BLOCK_H: tl.constexpr, ): token_idx = tl.program_id(0) block_idx = tl.program_id(1) offsets = block_idx * BLOCK_H + tl.arange(0, BLOCK_H) mask = offsets < hidden_size acc = tl.zeros((BLOCK_H,), dtype=tl.float32) for mix_idx in tl.static_range(0, hc_mult): pre = tl.load(pre_ptr + token_idx * pre_stride_t + mix_idx * pre_stride_m).to( tl.float32 ) x = tl.load( x_ptr + token_idx * x_stride_t + mix_idx * x_stride_m + offsets * x_stride_h, mask=mask, other=0.0, ).to(tl.float32) acc += pre * x tl.store( out_ptr + token_idx * out_stride_t + offsets * out_stride_h, acc, mask=mask, ) def hc_head_reduce_triton_kernel( x: torch.Tensor, hc_fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, out: torch.Tensor, norm_eps: float, hc_eps: float, ) -> None: x_flat = x.flatten(-2) x_normed = rmsnorm_nw(x_flat, norm_eps) mixes = F.linear(x_normed.float(), hc_fn) pre = torch.sigmoid(mixes * hc_scale + hc_base) + hc_eps hidden_size = x.shape[-1] hc_mult = x.shape[-2] block_h = 1024 _hc_head_reduce_store_kernel[(x.shape[0], (hidden_size + block_h - 1) // block_h)]( pre, x, out, hidden_size, hc_mult, pre.stride(0), pre.stride(1), x.stride(0), x.stride(1), x.stride(2), out.stride(0), out.stride(1), BLOCK_H=block_h, num_warps=4, ) def _hc_head_triton( hs_flat: torch.Tensor, fn: torch.Tensor, hc_scale: torch.Tensor, hc_base: torch.Tensor, out: torch.Tensor, hidden_size: int, rms_eps: float, hc_eps: float, hc_mult: int, ) -> None: """Fill pre-allocated `out` (T, H) in-place with the hc_head result.""" if hs_flat.shape[0] == 0: return hc_head_reduce_triton_kernel( hs_flat, fn, hc_scale, hc_base, out, rms_eps, hc_eps, ) return direct_register_custom_op( op_name="hc_head_triton", op_func=_hc_head_triton, mutates_args=["out"], )