[diffusion] Accelerate LingBot Video RMSNorm in quality=high (#35969)
This commit is contained in:
@@ -66,6 +66,7 @@ These fusion families mount under `quality="high"`:
|
|||||||
| LTX-2 RMSNorm + modulate | `rms_norm(x) * (1 + scale) + shift` in one launch |
|
| LTX-2 RMSNorm + modulate | `rms_norm(x) * (1 + scale) + shift` in one launch |
|
||||||
| Gate RMSNorm (BF16-native) | `RMSNorm + tanh + mul + add` in one pass |
|
| Gate RMSNorm (BF16-native) | `RMSNorm + tanh + mul + add` in one pass |
|
||||||
| HunyuanVideo strided QK RMSNorm | Per-head QK RMSNorm over the packed QKV layout |
|
| HunyuanVideo strided QK RMSNorm | Per-head QK RMSNorm over the packed QKV layout |
|
||||||
|
| LingBot Video fused RMSNorm | Replaces the handwritten cast, square, mean, rsqrt, and multiply chain with existing Triton RMSNorm kernels |
|
||||||
| SANA-Video BF16-input linear attention | Keeps the first linear-attention GEMM's inputs in BF16 with FP32 accumulation/output; the second GEMM remains FP32 |
|
| SANA-Video BF16-input linear attention | Keeps the first linear-attention GEMM's inputs in BF16 with FP32 accumulation/output; the second GEMM remains FP32 |
|
||||||
|
|
||||||
## Kernel inventory
|
## Kernel inventory
|
||||||
@@ -156,6 +157,7 @@ Kernels are written against a specific eager chain in a specific model, so cover
|
|||||||
| LTX-2 | QK-norm + split RoPE, ada-values split, RMSNorm+modulate, modulate, residual-gate add, linear+GELU |
|
| LTX-2 | QK-norm + split RoPE, ada-values split, RMSNorm+modulate, modulate, residual-gate add, linear+GELU |
|
||||||
| LTX-2.5 decoder | paired 3D RoPE with shared axis-table cache |
|
| LTX-2.5 decoder | paired 3D RoPE with shared axis-table cache |
|
||||||
| HunyuanVideo | QKV+RoPE pack, strided QK RMSNorm, linear+GELU |
|
| HunyuanVideo | QKV+RoPE pack, strided QK RMSNorm, linear+GELU |
|
||||||
|
| LingBot Video MoE | Fused RMSNorm at `quality=high` |
|
||||||
| Sana | LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add |
|
| Sana | LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add |
|
||||||
| SANA-Video | Packed QKV/KV; paired fp64 interleaved RoPE; LN+modulate, GLUMB bias+SiLU / bias+GLU, and residual-gate add during BCG; BF16-input linear attention at `quality=high` |
|
| SANA-Video | Packed QKV/KV; paired fp64 interleaved RoPE; LN+modulate, GLUMB bias+SiLU / bias+GLU, and residual-gate add during BCG; BF16-input linear attention at `quality=high` |
|
||||||
| Sana-WM | bidirectional gated delta-net, fused QK inverse-RMS |
|
| Sana-WM | bidirectional gated delta-net, fused QK inverse-RMS |
|
||||||
|
|||||||
@@ -470,6 +470,11 @@ _EXPORTS: dict[str, str] = {
|
|||||||
"mark_ltx2_rms_norm_modulate_site": "sites.ltx2_rmsnorm_modulate_site",
|
"mark_ltx2_rms_norm_modulate_site": "sites.ltx2_rmsnorm_modulate_site",
|
||||||
"mount_ltx2_rms_norm_modulate": "sites.ltx2_rmsnorm_modulate_site",
|
"mount_ltx2_rms_norm_modulate": "sites.ltx2_rmsnorm_modulate_site",
|
||||||
"unmount_ltx2_rms_norm_modulate": "sites.ltx2_rmsnorm_modulate_site",
|
"unmount_ltx2_rms_norm_modulate": "sites.ltx2_rmsnorm_modulate_site",
|
||||||
|
"lingbot_video_rmsnorm_active": "sites.lingbot_video_rmsnorm_site",
|
||||||
|
"mark_lingbot_video_rmsnorm_site": "sites.lingbot_video_rmsnorm_site",
|
||||||
|
"mount_lingbot_video_rmsnorm": "sites.lingbot_video_rmsnorm_site",
|
||||||
|
"try_lingbot_video_rmsnorm": "sites.lingbot_video_rmsnorm_site",
|
||||||
|
"unmount_lingbot_video_rmsnorm": "sites.lingbot_video_rmsnorm_site",
|
||||||
"mark_sana_video_linear_attention_site": "sites.sana_video_linear_attention_site",
|
"mark_sana_video_linear_attention_site": "sites.sana_video_linear_attention_site",
|
||||||
"mount_sana_video_linear_attention": "sites.sana_video_linear_attention_site",
|
"mount_sana_video_linear_attention": "sites.sana_video_linear_attention_site",
|
||||||
"sana_video_linear_attention_active": "sites.sana_video_linear_attention_site",
|
"sana_video_linear_attention_active": "sites.sana_video_linear_attention_site",
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
"""LingBot Video fused RMSNorm, gated by request quality.
|
||||||
|
|
||||||
|
LingBot Video keeps norm weights and statistics in FP32. Its reference module
|
||||||
|
spells RMSNorm as separate cast, square, mean, rsqrt, multiply, weight, and
|
||||||
|
output-cast operations. Some checkpoint norm weights remain BF16 after load;
|
||||||
|
the reference formula still promotes their multiplication through the FP32
|
||||||
|
hidden states. For ``quality="high"``, existing diffusion Triton RMSNorm
|
||||||
|
kernels replace that chain. Wide rows with FP32 weights use the one-row
|
||||||
|
``norm_infer`` kernel; the remaining sites use the tiled one-pass kernel. Their
|
||||||
|
reduction order is not bit-exact, so the default ``quality="lossless"`` path
|
||||||
|
remains unchanged.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from importlib import import_module
|
||||||
|
|
||||||
|
import torch
|
||||||
|
import torch.nn as nn
|
||||||
|
|
||||||
|
from sglang.kernels.ops.diffusion.sites.quality_gate import QualityGatedFusion
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
_FUSION = QualityGatedFusion(
|
||||||
|
name="LingBot Video fused RMSNorm",
|
||||||
|
marker_attr="_sgl_lingbot_video_rmsnorm_site",
|
||||||
|
enabled_attr="_sgl_lingbot_video_rmsnorm_enabled",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def mark_lingbot_video_rmsnorm_site(module: nn.Module) -> None:
|
||||||
|
"""Mark a LingBot RMSNorm module; it starts on the reference path."""
|
||||||
|
_FUSION.mark(module)
|
||||||
|
|
||||||
|
|
||||||
|
def lingbot_video_rmsnorm_active(module: nn.Module) -> bool:
|
||||||
|
return _FUSION.is_enabled(module)
|
||||||
|
|
||||||
|
|
||||||
|
def _site_reject_reason(site: nn.Module) -> str | None:
|
||||||
|
try:
|
||||||
|
import_module("triton")
|
||||||
|
except ImportError:
|
||||||
|
return "triton unavailable"
|
||||||
|
weight = getattr(site, "weight", None)
|
||||||
|
if not torch.is_tensor(weight) or weight.dim() != 1:
|
||||||
|
return "missing or non-1D norm weight"
|
||||||
|
if weight.dtype not in (torch.float16, torch.bfloat16, torch.float32):
|
||||||
|
return f"unsupported norm weight dtype {weight.dtype}"
|
||||||
|
if weight.stride(0) != 1:
|
||||||
|
return "non-contiguous norm weight"
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def mount_lingbot_video_rmsnorm(root: nn.Module) -> bool:
|
||||||
|
return _FUSION.mount(root, reject_reason=_site_reject_reason, logger=logger)
|
||||||
|
|
||||||
|
|
||||||
|
def unmount_lingbot_video_rmsnorm(root: nn.Module) -> None:
|
||||||
|
_FUSION.unmount(root)
|
||||||
|
|
||||||
|
|
||||||
|
def try_lingbot_video_rmsnorm(
|
||||||
|
site: nn.Module,
|
||||||
|
hidden_states: torch.Tensor,
|
||||||
|
weight: torch.Tensor,
|
||||||
|
eps: float,
|
||||||
|
) -> torch.Tensor | None:
|
||||||
|
"""Return the quality-gated RMSNorm result, or ``None`` to fall back."""
|
||||||
|
if not (
|
||||||
|
_FUSION.is_enabled(site)
|
||||||
|
and hidden_states.is_cuda
|
||||||
|
and hidden_states.dtype in (torch.float16, torch.bfloat16)
|
||||||
|
and hidden_states.is_contiguous()
|
||||||
|
and hidden_states.shape[-1] == weight.numel()
|
||||||
|
and weight.is_cuda
|
||||||
|
and weight.device == hidden_states.device
|
||||||
|
and weight.dtype in (hidden_states.dtype, torch.float32)
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
|
hidden_size = hidden_states.shape[-1]
|
||||||
|
if weight.dtype == torch.float32 and hidden_size > 128:
|
||||||
|
from sglang.kernels.ops.diffusion.norm.norm_triton import norm_infer
|
||||||
|
|
||||||
|
shape = hidden_states.shape
|
||||||
|
return norm_infer(
|
||||||
|
hidden_states.view(-1, hidden_size),
|
||||||
|
weight,
|
||||||
|
bias=None,
|
||||||
|
eps=eps,
|
||||||
|
is_rms_norm=True,
|
||||||
|
).view(shape)
|
||||||
|
|
||||||
|
from sglang.kernels.ops.diffusion.norm.rmsnorm_onepass_triton import (
|
||||||
|
triton_one_pass_rms_norm,
|
||||||
|
)
|
||||||
|
|
||||||
|
return triton_one_pass_rms_norm(hidden_states, weight, eps)
|
||||||
@@ -10,6 +10,10 @@ import torch.nn.functional as F
|
|||||||
from diffusers.models.embeddings import TimestepEmbedding, Timesteps
|
from diffusers.models.embeddings import TimestepEmbedding, Timesteps
|
||||||
from torch import nn
|
from torch import nn
|
||||||
|
|
||||||
|
from sglang.kernels.ops.diffusion import (
|
||||||
|
mark_lingbot_video_rmsnorm_site,
|
||||||
|
try_lingbot_video_rmsnorm,
|
||||||
|
)
|
||||||
from sglang.multimodal_gen.configs.models.dits.lingbot_video_moe import (
|
from sglang.multimodal_gen.configs.models.dits.lingbot_video_moe import (
|
||||||
LingBotVideoMoEConfig,
|
LingBotVideoMoEConfig,
|
||||||
)
|
)
|
||||||
@@ -75,8 +79,15 @@ class LingBotVideoRMSNorm(nn.Module):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.weight = nn.Parameter(torch.ones(dim))
|
self.weight = nn.Parameter(torch.ones(dim))
|
||||||
self.variance_epsilon = eps
|
self.variance_epsilon = eps
|
||||||
|
mark_lingbot_video_rmsnorm_site(self)
|
||||||
|
|
||||||
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
||||||
|
fused = try_lingbot_video_rmsnorm(
|
||||||
|
self, hidden_states, self.weight, self.variance_epsilon
|
||||||
|
)
|
||||||
|
if fused is not None:
|
||||||
|
return fused
|
||||||
|
|
||||||
input_dtype = hidden_states.dtype
|
input_dtype = hidden_states.dtype
|
||||||
hidden_states = hidden_states.to(torch.float32)
|
hidden_states = hidden_states.to(torch.float32)
|
||||||
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ from sglang.kernels.ops.diffusion import (
|
|||||||
mount_fused_linear_gelu,
|
mount_fused_linear_gelu,
|
||||||
mount_fused_ln_modulate,
|
mount_fused_ln_modulate,
|
||||||
mount_hunyuan_qknorm,
|
mount_hunyuan_qknorm,
|
||||||
|
mount_lingbot_video_rmsnorm,
|
||||||
mount_ltx2_rms_norm_modulate,
|
mount_ltx2_rms_norm_modulate,
|
||||||
mount_sana_video_linear_attention,
|
mount_sana_video_linear_attention,
|
||||||
unmount_fused_gate_rmsnorm,
|
unmount_fused_gate_rmsnorm,
|
||||||
unmount_fused_linear_gelu,
|
unmount_fused_linear_gelu,
|
||||||
unmount_fused_ln_modulate,
|
unmount_fused_ln_modulate,
|
||||||
unmount_hunyuan_qknorm,
|
unmount_hunyuan_qknorm,
|
||||||
|
unmount_lingbot_video_rmsnorm,
|
||||||
unmount_ltx2_rms_norm_modulate,
|
unmount_ltx2_rms_norm_modulate,
|
||||||
unmount_sana_video_linear_attention,
|
unmount_sana_video_linear_attention,
|
||||||
)
|
)
|
||||||
@@ -184,6 +186,11 @@ _QUALITY_FUSION_HANDLERS: tuple[
|
|||||||
mount_hunyuan_qknorm,
|
mount_hunyuan_qknorm,
|
||||||
unmount_hunyuan_qknorm,
|
unmount_hunyuan_qknorm,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"LingBot Video fused RMSNorm",
|
||||||
|
mount_lingbot_video_rmsnorm,
|
||||||
|
unmount_lingbot_video_rmsnorm,
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"SANA-Video BF16-input linear attention",
|
"SANA-Video BF16-input linear attention",
|
||||||
mount_sana_video_linear_attention,
|
mount_sana_video_linear_attention,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import torch.nn.functional as F
|
|||||||
|
|
||||||
import sglang.kernels.ops.diffusion.sites.fused_gate_rmsnorm_site as gate_rmsnorm
|
import sglang.kernels.ops.diffusion.sites.fused_gate_rmsnorm_site as gate_rmsnorm
|
||||||
import sglang.kernels.ops.diffusion.sites.fused_linear_gelu_site as linear_gelu
|
import sglang.kernels.ops.diffusion.sites.fused_linear_gelu_site as linear_gelu
|
||||||
|
import sglang.kernels.ops.diffusion.sites.lingbot_video_rmsnorm_site as lingbot_video_rmsnorm
|
||||||
import sglang.kernels.ops.diffusion.sites.sana_video_linear_attention_site as sana_video_linear_attention
|
import sglang.kernels.ops.diffusion.sites.sana_video_linear_attention_site as sana_video_linear_attention
|
||||||
from sglang.kernels.ops.diffusion import (
|
from sglang.kernels.ops.diffusion import (
|
||||||
BitExactFusionGate,
|
BitExactFusionGate,
|
||||||
@@ -456,5 +457,52 @@ def test_sana_video_linear_attention_quality_path_and_guards():
|
|||||||
assert not sana_video_linear_attention.sana_video_linear_attention_active(site)
|
assert not sana_video_linear_attention.sana_video_linear_attention_active(site)
|
||||||
|
|
||||||
|
|
||||||
|
@requires_cuda
|
||||||
|
@torch.no_grad()
|
||||||
|
def test_lingbot_video_rmsnorm_quality_path_and_guards():
|
||||||
|
torch.manual_seed(1)
|
||||||
|
site = nn.Module()
|
||||||
|
site.weight = nn.Parameter(torch.randn(2048, device="cuda", dtype=torch.float32))
|
||||||
|
lingbot_video_rmsnorm.mark_lingbot_video_rmsnorm_site(site)
|
||||||
|
hidden_states = torch.randn(1, 128, 2048, device="cuda", dtype=torch.bfloat16)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
lingbot_video_rmsnorm.try_lingbot_video_rmsnorm(
|
||||||
|
site, hidden_states, site.weight, 1e-6
|
||||||
|
)
|
||||||
|
is None
|
||||||
|
)
|
||||||
|
assert lingbot_video_rmsnorm.mount_lingbot_video_rmsnorm(site)
|
||||||
|
output = lingbot_video_rmsnorm.try_lingbot_video_rmsnorm(
|
||||||
|
site, hidden_states, site.weight, 1e-6
|
||||||
|
)
|
||||||
|
states_fp32 = hidden_states.float()
|
||||||
|
variance = states_fp32.pow(2).mean(-1, keepdim=True)
|
||||||
|
normalized = states_fp32 * torch.rsqrt(variance + 1e-6)
|
||||||
|
reference = (site.weight * normalized).bfloat16()
|
||||||
|
torch.testing.assert_close(output, reference, atol=2e-2, rtol=2e-2)
|
||||||
|
|
||||||
|
bf16_site = nn.Module()
|
||||||
|
bf16_site.weight = nn.Parameter(
|
||||||
|
torch.randn(2048, device="cuda", dtype=torch.bfloat16)
|
||||||
|
)
|
||||||
|
lingbot_video_rmsnorm.mark_lingbot_video_rmsnorm_site(bf16_site)
|
||||||
|
assert lingbot_video_rmsnorm.mount_lingbot_video_rmsnorm(bf16_site)
|
||||||
|
bf16_output = lingbot_video_rmsnorm.try_lingbot_video_rmsnorm(
|
||||||
|
bf16_site, hidden_states, bf16_site.weight, 1e-6
|
||||||
|
)
|
||||||
|
bf16_reference = (bf16_site.weight * normalized).bfloat16()
|
||||||
|
torch.testing.assert_close(bf16_output, bf16_reference, atol=3e-2, rtol=3e-2)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
lingbot_video_rmsnorm.try_lingbot_video_rmsnorm(
|
||||||
|
site, hidden_states.float(), site.weight, 1e-6
|
||||||
|
)
|
||||||
|
is None
|
||||||
|
)
|
||||||
|
lingbot_video_rmsnorm.unmount_lingbot_video_rmsnorm(site)
|
||||||
|
assert not lingbot_video_rmsnorm.lingbot_video_rmsnorm_active(site)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
sys.exit(pytest.main([__file__, "-v"]))
|
sys.exit(pytest.main([__file__, "-v"]))
|
||||||
|
|||||||
Reference in New Issue
Block a user