# SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project """Fused kernels for the Wan VAE decoder on channels_last_3d activations. Adapted from SGLang's ``sglang.kernels.ops.diffusion`` (``norm/wan_rmsnorm_silu_triton.py`` and ``layout/nearest_upsample_nhwc_triton.py``, Apache-2.0), reduced to what the LingBot-World streaming decode uses. Each kernel comes with a ``can_use_*`` predicate and a torch reference of the eager op chain it replaces; the predicate decides, the kernel raises on an input it does not support. - :func:`wan_rmsnorm_silu`: ``SiLU(F.normalize(x, dim=1) * scale * gamma + bias)`` on a dense channels_last_3d ``[B, C, T, H, W]`` tensor, one program per pixel. fp32 channel statistics; the intermediate dtype boundaries of the eager chain are kept (normalise and ``* scale`` in ``x.dtype``, ``* gamma`` in the promoted dtype, SiLU in fp32) and the result is stored in ``x.dtype``, which is the dtype the following convolution reads under autocast anyway. Not bit-identical to aten (the channel reduction order differs), so it is gated with the bf16 decode option rather than mounted unconditionally. - :func:`nearest_upsample_nhwc`: integer-factor nearest upsample of a dense channels_last ``[N, C, H, W]`` tensor as a gather, bit-exact vs ``nn.Upsample`` in ``nearest`` and ``nearest-exact`` modes; aten's own NHWC nearest kernel is several times slower than its NCHW one, which is what a channels_last decoder would hit. """ from __future__ import annotations import math import torch import torch.nn.functional as F try: # Triton is optional: CPU tests and non-CUDA platforms use the torch references. import triton import triton.language as tl _HAS_TRITON = True except ImportError: # pragma: no cover _HAS_TRITON = False _MAX_CHANNELS = 1024 _MAX_INT32 = 2**31 - 1 _SUPPORTED_DTYPES = (torch.bfloat16, torch.float16, torch.float32) # --------------------------------------------------------------------------- RMSNorm + SiLU def wan_rmsnorm_silu_reference( x: torch.Tensor, gamma: torch.Tensor, bias: torch.Tensor | float, scale: float, eps: float = 1e-12, upcast: bool = True, ) -> torch.Tensor: """The eager norm chain followed by SiLU, cast back to ``x.dtype``. ``upcast=True`` is diffusers' ``WanRMS_norm`` (normalise in fp32, round to ``x.dtype``); ``upcast=False`` is vLLM-Omni's ``RMSNormVAE`` (``F.normalize`` on ``x`` itself, so every step rounds to ``x.dtype``). """ if upcast: normalized = F.normalize(x.float(), dim=1, eps=eps).to(x.dtype) else: normalized = F.normalize(x, dim=1, eps=eps) y = normalized * scale * gamma + bias return F.silu(y).to(x.dtype) def _dense_channels_last_3d(x: torch.Tensor) -> bool: if x.dim() != 5 or x.shape[1] <= 1: return False b, c, t, h, w = x.shape return x.stride() == (t * h * w * c, 1, h * w * c, w * c, c) def can_use_wan_rmsnorm_silu(x: torch.Tensor, gamma: torch.Tensor, bias: torch.Tensor | float | None) -> bool: return ( _HAS_TRITON and x.is_cuda and not (torch.is_grad_enabled() and x.requires_grad) and x.dtype in _SUPPORTED_DTYPES and x.numel() > 0 and 0 < x.shape[1] <= _MAX_CHANNELS and _dense_channels_last_3d(x) and gamma.is_cuda and gamma.device == x.device and gamma.numel() == x.shape[1] and (gamma.dtype == x.dtype or gamma.dtype == torch.float32) and ( not isinstance(bias, torch.Tensor) or (bias.device == x.device and bias.numel() == x.shape[1] and bias.dtype in (x.dtype, torch.float32)) ) ) if _HAS_TRITON: @triton.jit def _wan_rmsnorm_silu_kernel( x_ptr, gamma_ptr, bias_ptr, out_ptr, channels: tl.constexpr, rms_scale, eps, has_bias: tl.constexpr, round_affine: tl.constexpr, upcast: tl.constexpr, block_c: tl.constexpr, ): row = tl.program_id(0).to(tl.int64) offsets = tl.arange(0, block_c) mask = offsets < channels # Dense channels_last_3d stores each pixel as one contiguous channel row. row_offsets = row * channels + offsets x = tl.load(x_ptr + row_offsets, mask=mask, other=0.0).to(tl.float32) norm = tl.sqrt(tl.sum(x * x, axis=0)) if upcast: # WanRMS_norm: fp32 normalise, one rounding to x.dtype. y = (x / tl.maximum(norm, eps)).to(x_ptr.dtype.element_ty) else: # RMSNormVAE: F.normalize on x itself, so the norm, the clamp and the quotient each round to x.dtype. denom = tl.maximum(norm.to(x_ptr.dtype.element_ty).to(tl.float32), eps) denom = denom.to(x_ptr.dtype.element_ty).to(tl.float32) y = (x / denom).to(x_ptr.dtype.element_ty) # Then the eager boundaries: * scale in x.dtype, * gamma / + bias in the promoted dtype, SiLU in fp32, # stored in x.dtype. y = (y * rms_scale).to(x_ptr.dtype.element_ty) gamma = tl.load(gamma_ptr + offsets, mask=mask, other=1.0).to(tl.float32) y = y.to(tl.float32) * gamma if round_affine: # gamma (and bias) share x's dtype: the eager product and sum are rounded to it. y = y.to(x_ptr.dtype.element_ty).to(tl.float32) if has_bias: bias = tl.load(bias_ptr + offsets, mask=mask, other=0.0).to(tl.float32) y = y + bias if round_affine: y = y.to(x_ptr.dtype.element_ty).to(tl.float32) y = y * tl.sigmoid(y) tl.store(out_ptr + row_offsets, y, mask=mask) def wan_rmsnorm_silu( x: torch.Tensor, gamma: torch.Tensor, bias: torch.Tensor | float | None, scale: float, eps: float = 1e-12, upcast: bool = True, ) -> torch.Tensor: """Fused ``SiLU(normalize(x) * scale * gamma + bias)`` on a dense channels_last_3d tensor; raises otherwise.""" if not can_use_wan_rmsnorm_silu(x, gamma, bias): raise ValueError( "wan_rmsnorm_silu needs a CUDA, dense channels_last_3d, bf16/fp16/fp32 [B, C, T, H, W] tensor with " f"C <= {_MAX_CHANNELS}; got {x.device.type} {tuple(x.shape)} {x.dtype} strides {tuple(x.stride())}" ) b, c, t, h, w = x.shape out = torch.empty_strided(x.shape, x.stride(), device=x.device, dtype=x.dtype) has_bias = isinstance(bias, torch.Tensor) bias_arg = bias.reshape(-1) if isinstance(bias, torch.Tensor) else gamma # With affine parameters in x's dtype the eager chain rounds after ``* gamma`` and ``+ bias``; fp32 # parameters promote the chain to fp32 and the only rounding left is the store. round_affine = gamma.dtype == x.dtype and x.dtype != torch.float32 block_c = triton.next_power_of_2(c) num_warps = 1 if block_c <= 64 else 4 if block_c <= 512 else 8 with torch.get_device_module(x.device).device(x.device): _wan_rmsnorm_silu_kernel[(b * t * h * w,)]( x, gamma.reshape(-1), bias_arg, out, c, float(scale), float(eps), has_bias, round_affine, upcast, block_c, num_warps=num_warps, ) return out # --------------------------------------------------------------------------- nearest upsample, NHWC def _integer_scale(scale) -> tuple[int, int] | None: if isinstance(scale, bool): return None if isinstance(scale, (int, float)): scale = (scale, scale) if not isinstance(scale, (tuple, list)) or len(scale) != 2: return None out = [] for s in scale: if isinstance(s, bool) or not isinstance(s, (int, float)): return None f = float(s) if not math.isfinite(f) or f < 1.0 or f != int(f): return None out.append(int(f)) return out[0], out[1] def canonical_nhwc(x: torch.Tensor) -> bool: """Dense channels_last with ``C > 1`` and canonical strides on every dim, size-1 dims included.""" if x.dim() != 4: return False _, c, h, w = x.shape return c > 1 and x.stride() == (h * w * c, 1, w * c, c) def can_use_nearest_upsample_nhwc(x: torch.Tensor, scale_factor, mode: str) -> bool: return ( _HAS_TRITON and isinstance(x, torch.Tensor) and x.is_cuda and not (torch.is_grad_enabled() and x.requires_grad) and mode in ("nearest", "nearest-exact") and x.dim() == 4 and x.numel() > 0 and x.dtype in _SUPPORTED_DTYPES and canonical_nhwc(x) and _integer_scale(scale_factor) is not None ) if _HAS_TRITON: @triton.jit def _nearest_upsample_nhwc_kernel( x_ptr, out_ptr, total, channels, out_h, out_w, fh, fw, sxn, sxh, sxw, idx64: tl.constexpr, block: tl.constexpr ): pid = tl.program_id(0) if idx64: offs = pid.to(tl.int64) * block + tl.arange(0, block).to(tl.int64) else: offs = pid * block + tl.arange(0, block) mask = offs < total # Output is dense NHWC: offs = ((n * out_h + h) * out_w + w) * channels + c. c = offs % channels t = offs // channels w = t % out_w t = t // out_w h = t % out_h n = t // out_h src = n * sxn + (h // fh) * sxh + (w // fw) * sxw + c vals = tl.load(x_ptr + src, mask=mask) tl.store(out_ptr + offs, vals, mask=mask) def nearest_upsample_nhwc(x: torch.Tensor, scale_factor) -> torch.Tensor: """Integer-factor nearest upsample of a canonical channels_last ``[N, C, H, W]`` tensor, dense channels_last out.""" factors = _integer_scale(scale_factor) if factors is None or not can_use_nearest_upsample_nhwc(x, scale_factor, "nearest"): raise ValueError( "nearest_upsample_nhwc needs a CUDA, canonical channels_last 4D bf16/fp16/fp32 tensor and an integer " f"scale; got {x.device.type} {tuple(x.shape)} strides {tuple(x.stride())} scale {scale_factor!r}" ) fh, fw = factors n, c, h, w = x.shape out_h, out_w = h * fh, w * fw out = torch.empty((n, c, out_h, out_w), device=x.device, dtype=x.dtype, memory_format=torch.channels_last) total = out.numel() if total == 0: return out sxn, _, sxh, sxw = x.stride() block = 1024 with torch.get_device_module(x.device).device(x.device): _nearest_upsample_nhwc_kernel[(triton.cdiv(total, block),)]( x, out, total, c, out_h, out_w, fh, fw, sxn, sxh, sxw, idx64=total >= _MAX_INT32 or x.numel() >= _MAX_INT32, block=block, ) return out