[diffusion] Clean up shared bitexact gates, helpers, and stale naming (#34180)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Xiaoyu Zhang
2026-08-10 22:14:09 +08:00
committed by GitHub
co-authored by Cursor Claude Fable 5
parent 77c90e7e54
commit fd3036523a
24 changed files with 496 additions and 288 deletions
@@ -1,4 +1,4 @@
// Minimal native-CUDA fast path for Qwen-Image diffusion norm-scale-shift. // Minimal native-CUDA fast path for generic bf16 hidden=3072 norm-scale-shift.
// //
// Supported shape family: // Supported shape family:
// - bf16 activations, B == 1, hidden dim == 3072 // - bf16 activations, B == 1, hidden dim == 3072
@@ -36,7 +36,7 @@ constexpr float kInvHidden = 1.0f / float(kHidden);
static_assert(kThreads == 192); static_assert(kThreads == 192);
static_assert(kWarps == 6); static_assert(kWarps == 6);
struct QwenImageNormParams { struct NormScaleShiftParams {
void* y; void* y;
void* res_out; void* res_out;
const void* x; const void* x;
@@ -66,7 +66,7 @@ SGL_DEVICE float cta_reduce_sum(float v, int warp, int lane, float* scratch) {
} }
template <bool kHasResidual> template <bool kHasResidual>
__global__ void qwen_image_norm_scale_shift_kernel(const QwenImageNormParams __grid_constant__ params) { __global__ void norm_scale_shift_kernel(const NormScaleShiftParams __grid_constant__ params) {
using namespace device; using namespace device;
using Vec = AlignedVector<bf16_t, kVecElems>; using Vec = AlignedVector<bf16_t, kVecElems>;
@@ -135,14 +135,14 @@ __global__ void qwen_image_norm_scale_shift_kernel(const QwenImageNormParams __g
yv.store(static_cast<bf16_t*>(params.y) + row_offset + elem_offset); yv.store(static_cast<bf16_t*>(params.y) + row_offset + elem_offset);
} }
inline uint32_t verify_qwen_geometry(host::SymbolicSize& num_rows) { inline uint32_t verify_nss_geometry(host::SymbolicSize& num_rows) {
using namespace host; using namespace host;
RuntimeCheck(num_rows.unwrap() > 0, "num_rows must be positive"); RuntimeCheck(num_rows.unwrap() > 0, "num_rows must be positive");
RuntimeCheck(num_rows.unwrap() <= int64_t(UINT32_MAX), "num_rows out of range"); RuntimeCheck(num_rows.unwrap() <= int64_t(UINT32_MAX), "num_rows out of range");
return static_cast<uint32_t>(num_rows.unwrap()); return static_cast<uint32_t>(num_rows.unwrap());
} }
struct QwenImageNormScaleShiftKernel { struct NormScaleShiftKernel {
static void static void
run(tvm::ffi::TensorView y, run(tvm::ffi::TensorView y,
tvm::ffi::TensorView x, tvm::ffi::TensorView x,
@@ -157,8 +157,8 @@ struct QwenImageNormScaleShiftKernel {
TensorMatcher({N, kHidden}).with_dtype<bf16_t>().with_device(device).verify(x).verify(y); TensorMatcher({N, kHidden}).with_dtype<bf16_t>().with_device(device).verify(x).verify(y);
TensorMatcher({kHidden}).with_dtype<bf16_t>().with_device(device).verify(scale).verify(shift); TensorMatcher({kHidden}).with_dtype<bf16_t>().with_device(device).verify(scale).verify(shift);
const uint32_t grid = verify_qwen_geometry(N); const uint32_t grid = verify_nss_geometry(N);
const auto params = QwenImageNormParams{ const auto params = NormScaleShiftParams{
.y = y.data_ptr(), .y = y.data_ptr(),
.res_out = nullptr, .res_out = nullptr,
.x = x.data_ptr(), .x = x.data_ptr(),
@@ -168,11 +168,11 @@ struct QwenImageNormScaleShiftKernel {
.shift = shift.data_ptr(), .shift = shift.data_ptr(),
.eps = static_cast<float>(eps), .eps = static_cast<float>(eps),
}; };
LaunchKernel(grid, kThreads, device.unwrap())(qwen_image_norm_scale_shift_kernel<false>, params); LaunchKernel(grid, kThreads, device.unwrap())(norm_scale_shift_kernel<false>, params);
} }
}; };
struct QwenImageScaleResidualNormScaleShiftKernel { struct ScaleResidualNormScaleShiftKernel {
static void static void
run(tvm::ffi::TensorView y, run(tvm::ffi::TensorView y,
tvm::ffi::TensorView res_out, tvm::ffi::TensorView res_out,
@@ -196,8 +196,8 @@ struct QwenImageScaleResidualNormScaleShiftKernel {
.verify(res_out); .verify(res_out);
TensorMatcher({kHidden}).with_dtype<bf16_t>().with_device(device).verify(gate).verify(scale).verify(shift); TensorMatcher({kHidden}).with_dtype<bf16_t>().with_device(device).verify(gate).verify(scale).verify(shift);
const uint32_t grid = verify_qwen_geometry(N); const uint32_t grid = verify_nss_geometry(N);
const auto params = QwenImageNormParams{ const auto params = NormScaleShiftParams{
.y = y.data_ptr(), .y = y.data_ptr(),
.res_out = res_out.data_ptr(), .res_out = res_out.data_ptr(),
.x = x.data_ptr(), .x = x.data_ptr(),
@@ -207,7 +207,7 @@ struct QwenImageScaleResidualNormScaleShiftKernel {
.shift = shift.data_ptr(), .shift = shift.data_ptr(),
.eps = static_cast<float>(eps), .eps = static_cast<float>(eps),
}; };
LaunchKernel(grid, kThreads, device.unwrap())(qwen_image_norm_scale_shift_kernel<true>, params); LaunchKernel(grid, kThreads, device.unwrap())(norm_scale_shift_kernel<true>, params);
} }
}; };
+14 -11
View File
@@ -1,6 +1,7 @@
"""Registered diffusion-model kernels and their public wrappers. """Registered diffusion-model kernels and their public wrappers.
Implementations use the backend recorded by each kernel specification. Hot paths import concrete implementations from submodules. The package-level
wrappers remain available for backward compatibility.
""" """
from __future__ import annotations from __future__ import annotations
@@ -54,6 +55,18 @@ register_kernel(
description="Fused QK-norm + RoPE (sglang.kernels.jit).", description="Fused QK-norm + RoPE (sglang.kernels.jit).",
) )
) )
# Migrated from multimodal_gen (RFC #29630, Phase 2.5). Hot paths import the
# Triton symbol directly; the registry entry remains for namespace discovery.
register_kernel(
KernelSpec(
op="diffusion.sparse_linear_attn_fwd",
backend=KernelBackend.TRITON,
target="sglang.kernels.ops.diffusion.sparse_linear_attn_kernels:_attn_fwd",
capabilities=_CUDA,
format_signature=FormatSignature(description="sparse linear attention fwd"),
description="Sparse linear attention forward (Triton).",
)
)
def apply_group_norm_silu( def apply_group_norm_silu(
@@ -107,13 +120,3 @@ __all__ = [
"residual_gate_add", "residual_gate_add",
"fused_inplace_qknorm_rope", "fused_inplace_qknorm_rope",
] ]
# Migrated from multimodal_gen (RFC #29630, Phase 2.5).
register_kernel(
KernelSpec(
op="diffusion.sparse_linear_attn_fwd",
backend=KernelBackend.TRITON,
target="sglang.kernels.ops.diffusion.sparse_linear_attn_kernels:_attn_fwd",
)
)
@@ -0,0 +1,118 @@
"""Shared first-sight verification for bit-exact diffusion fast paths."""
from __future__ import annotations
import logging
from collections.abc import Callable
from typing import Any, TypeVar
import torch
T = TypeVar("T")
EqualFn = Callable[[Any, Any], bool]
class BitExactFusionGate:
"""Track permanent disable + first-sight ``torch.equal`` verification.
Two modes:
* **once-for-all** (default): the first successful equal-check enables the
fused path for every later call (GLM / Ernie).
* **per-signature**: each distinct ``sig`` is verified independently
(FLUX / Sana), matching aten LayerNorm dispatch that can vary by shape.
The first-sight check runs the eager reference chain plus a host sync, so
it must never happen inside ``torch.compile`` tracing or CUDA graph
capture. Once-for-all callers get both guards from
:meth:`can_attempt_once`; per-signature callers must keep their own
compile/capture checks next to the signature lookup (see FLUX / Sana).
"""
__slots__ = ("name", "disabled", "verified", "verified_sigs")
def __init__(self, name: str, *, per_signature: bool = False) -> None:
self.name = name
self.disabled = False
# This is a plain field because steady-state DiT blocks read it on
# every invocation; a property descriptor is measurable at this scale.
self.verified = False
self.verified_sigs: set[Any] | None = set() if per_signature else None
def is_verified(self, sig: Any = None) -> bool:
if self.verified_sigs is not None:
return sig in self.verified_sigs
return self.verified
def mark_verified(self, sig: Any = None) -> None:
if self.verified_sigs is not None:
assert sig is not None
self.verified_sigs.add(sig)
self.verified = True
def disable(self) -> None:
self.disabled = True
def can_attempt_once(self) -> bool:
"""Once-for-all mode: may we launch the fused kernel right now?"""
if self.disabled:
return False
if self.verified:
return True
# First-sight verify runs the eager reference chain and a host sync:
# attempt neither inside compile tracing nor CUDA graph capture (the
# sync would abort the capture; BCG then blocks the signature). Once
# verified, the fused kernel runs alone and is compile/capture-safe.
if torch.compiler.is_compiling():
return False
return not (
torch.cuda.is_available() and torch.cuda.is_current_stream_capturing()
)
def on_exception(
self,
exc: BaseException,
*,
logger: logging.Logger | None = None,
re_raise_if_compiling: bool = True,
) -> None:
if re_raise_if_compiling and torch.compiler.is_compiling():
raise exc
if logger is not None:
logger.warning_once(f"Disabling {self.name} fast path: {exc}")
self.disable()
def accept_or_fallback(
self,
out: T,
ref: T,
*,
sig: Any = None,
equal: EqualFn | None = None,
logger: logging.Logger | None = None,
mismatch_msg: str | None = None,
) -> T:
"""Return ``out`` when bit-exact; otherwise disable and return ``ref``."""
if self.is_verified(sig):
return out
eq = equal or torch.equal
if eq(out, ref):
self.mark_verified(sig)
return out
if logger is not None:
logger.warning_once(
mismatch_msg
or (
f"{self.name} fast path is not bit-exact against this "
"platform's reference dispatch; falling back to eager"
)
)
self.disable()
return ref
def tensors_equal(a: Any, b: Any) -> bool:
"""``torch.equal`` for a tensor or a sequence of tensors."""
if isinstance(a, torch.Tensor):
return torch.equal(a, b)
return all(torch.equal(x, y) for x, y in zip(a, b, strict=True))
@@ -24,7 +24,7 @@ def _blackwell_or_newer(device: torch.device) -> bool:
) )
def _qwen_activation(t, like=None) -> bool: def _nss_activation(t, like=None) -> bool:
return ( return (
isinstance(t, torch.Tensor) isinstance(t, torch.Tensor)
and t.is_cuda and t.is_cuda
@@ -61,16 +61,16 @@ def _row_bf16(t, device: torch.device):
@cache_once @cache_once
def norm_scale_shift_module() -> Module: def norm_scale_shift_module() -> Module:
return load_jit( return load_jit(
"qwen_image_norm_scale_shift_native", "norm_scale_shift_native",
cuda_files=["diffusion/norm_scale_shift.cuh"], cuda_files=["diffusion/norm_scale_shift.cuh"],
cuda_wrappers=[ cuda_wrappers=[
( (
"qwen_image_nss_bf16_row", "nss_bf16_row",
"norm_scale_shift::QwenImageNormScaleShiftKernel::run", "norm_scale_shift::NormScaleShiftKernel::run",
), ),
( (
"qwen_image_srnss_bf16_row", "srnss_bf16_row",
"norm_scale_shift::" "QwenImageScaleResidualNormScaleShiftKernel::run", "norm_scale_shift::ScaleResidualNormScaleShiftKernel::run",
), ),
], ],
) )
@@ -82,7 +82,7 @@ _module = norm_scale_shift_module
def try_fused_norm_scale_shift(x, weight, bias, scale, shift, norm_type, eps): def try_fused_norm_scale_shift(x, weight, bias, scale, shift, norm_type, eps):
if norm_type != "layer" or weight is not None or bias is not None: if norm_type != "layer" or weight is not None or bias is not None:
return None return None
if not _qwen_activation(x) or not _blackwell_or_newer(x.device): if not _nss_activation(x) or not _blackwell_or_newer(x.device):
return None return None
scale = _row_bf16(scale, x.device) scale = _row_bf16(scale, x.device)
@@ -91,7 +91,7 @@ def try_fused_norm_scale_shift(x, weight, bias, scale, shift, norm_type, eps):
return None return None
y = torch.empty_like(x) y = torch.empty_like(x)
_module().qwen_image_nss_bf16_row( _module().nss_bf16_row(
y.view(-1, _HIDDEN), x.view(-1, _HIDDEN), scale, shift, float(eps) y.view(-1, _HIDDEN), x.view(-1, _HIDDEN), scale, shift, float(eps)
) )
return y return y
@@ -103,8 +103,8 @@ def try_fused_scale_residual_norm_scale_shift(
if norm_type != "layer" or weight is not None or bias is not None: if norm_type != "layer" or weight is not None or bias is not None:
return None return None
if not ( if not (
_qwen_activation(x) _nss_activation(x)
and _qwen_activation(residual, x) and _nss_activation(residual, x)
and _blackwell_or_newer(x.device) and _blackwell_or_newer(x.device)
): ):
return None return None
@@ -117,7 +117,7 @@ def try_fused_scale_residual_norm_scale_shift(
y = torch.empty_like(x) y = torch.empty_like(x)
residual_out = torch.empty_like(x) residual_out = torch.empty_like(x)
_module().qwen_image_srnss_bf16_row( _module().srnss_bf16_row(
y.view(-1, _HIDDEN), y.view(-1, _HIDDEN),
residual_out.view(-1, _HIDDEN), residual_out.view(-1, _HIDDEN),
residual.view(-1, _HIDDEN), residual.view(-1, _HIDDEN),
@@ -619,7 +619,7 @@ the known mainline families.
| --- | --- | | --- | --- |
| `fused_inplace_qknorm_rope` missing, but separate qk norm plus rope show up | Check whether the fused diffusion `QK norm + RoPE` path should have engaged | | `fused_inplace_qknorm_rope` missing, but separate qk norm plus rope show up | Check whether the fused diffusion `QK norm + RoPE` path should have engaged |
| `to_q -> to_k -> to_v` on NVFP4 or Nunchaku FLUX-family checkpoints | Treat as a packed-QKV fast-path miss or checkpoint-format mismatch | | `to_q -> to_k -> to_v` on NVFP4 or Nunchaku FLUX-family checkpoints | Treat as a packed-QKV fast-path miss or checkpoint-format mismatch |
| `zimage_rmsnorm_scale` or `zimage_rmsnorm_tanh_residual` missing on Z-Image | Check the bf16-native Triton eligibility guards before proposing a new fusion | | `rmsnorm_scale` or `rmsnorm_tanh_residual` missing on Z-Image | Check the bf16-native Triton eligibility guards before proposing a new fusion |
| FLUX.1, GLM-Image, or SANA shows separate LayerNorm plus adaLN elementwise kernels | Check the bit-exact `modulate_scale_shift` and `fused_layernorm_modulate` guards/self-test before proposing another norm fusion | | FLUX.1, GLM-Image, or SANA shows separate LayerNorm plus adaLN elementwise kernels | Check the bit-exact `modulate_scale_shift` and `fused_layernorm_modulate` guards/self-test before proposing another norm fusion |
| `quality=high` shows the same FLUX/GLM DiT or FLUX-family/Wan VAE chain as `lossless` | Check whether the request-scoped quality gate mounted and whether every site passed its all-or-nothing compatibility checks | | `quality=high` shows the same FLUX/GLM DiT or FLUX-family/Wan VAE chain as `lossless` | Check whether the request-scoped quality gate mounted and whether every site passed its all-or-nothing compatibility checks |
| LTX-2 split RoPE appears as a long PyTorch elementwise chain | Check the `apply_ltx2_split_rotary_emb` Triton path and its shape guards | | LTX-2 split RoPE appears as a long PyTorch elementwise chain | Check the `apply_ltx2_split_rotary_emb` Triton path and its shape guards |
@@ -14,6 +14,7 @@ framework-specific optimization workflow.
- `python/sglang/kernels/ops/diffusion/modulate_scale_shift.py` - `python/sglang/kernels/ops/diffusion/modulate_scale_shift.py`
- `python/sglang/kernels/ops/diffusion/fused_ln_modulate.py` - `python/sglang/kernels/ops/diffusion/fused_ln_modulate.py`
- `python/sglang/kernels/ops/diffusion/quality_gate.py` - `python/sglang/kernels/ops/diffusion/quality_gate.py`
- `python/sglang/kernels/ops/diffusion/bitexact_gate.py`
- `python/sglang/kernels/ops/diffusion/group_norm_silu.py` - `python/sglang/kernels/ops/diffusion/group_norm_silu.py`
- `python/sglang/kernels/ops/diffusion/triton/group_norm_silu.py` - `python/sglang/kernels/ops/diffusion/triton/group_norm_silu.py`
- `python/sglang/kernels/ops/diffusion/triton/group_norm_silu_twopass.py` - `python/sglang/kernels/ops/diffusion/triton/group_norm_silu_twopass.py`
@@ -24,6 +25,8 @@ framework-specific optimization workflow.
- `python/sglang/kernels/ops/diffusion/triton/zimage_native_norm.py` - `python/sglang/kernels/ops/diffusion/triton/zimage_native_norm.py`
- `python/sglang/kernels/ops/diffusion/triton/rotary.py` - `python/sglang/kernels/ops/diffusion/triton/rotary.py`
- `python/sglang/kernels/ops/diffusion/triton/ltx2_rotary.py` - `python/sglang/kernels/ops/diffusion/triton/ltx2_rotary.py`
- `python/sglang/kernels/ops/diffusion/ltx2_qknorm_split_rope.py`
- `python/sglang/kernels/ops/diffusion/ltx2_rmsnorm_modulate.py`
- `python/sglang/kernels/ops/diffusion/triton/indexed_modulation.py` - `python/sglang/kernels/ops/diffusion/triton/indexed_modulation.py`
- `python/sglang/kernels/ops/diffusion/triton/ulysses_qkv.py` - `python/sglang/kernels/ops/diffusion/triton/ulysses_qkv.py`
- `python/sglang/kernels/ops/diffusion/usp_relayout.py` - `python/sglang/kernels/ops/diffusion/usp_relayout.py`
@@ -48,6 +51,8 @@ framework-specific optimization workflow.
- `test/registered/kernels/ops/diffusion/test_glm_image_ln_modulate.py` - `test/registered/kernels/ops/diffusion/test_glm_image_ln_modulate.py`
- `test/registered/kernels/ops/diffusion/test_sana_ln_modulate.py` - `test/registered/kernels/ops/diffusion/test_sana_ln_modulate.py`
- `test/registered/kernels/ops/diffusion/test_quality_gate.py` - `test/registered/kernels/ops/diffusion/test_quality_gate.py`
- `test/registered/kernels/ops/diffusion/test_ltx2_rms_norm_modulate.py`
- `test/registered/kernels/ops/diffusion/test_bitexact_gate.py`
- `test/registered/kernels/ops/diffusion/test_wan_causal_cache.py` - `test/registered/kernels/ops/diffusion/test_wan_causal_cache.py`
- `test/registered/kernels/ops/diffusion/test_stage_profiler_sync.py` - `test/registered/kernels/ops/diffusion/test_stage_profiler_sync.py`
- `test/registered/kernels/benchmark/diffusion/bench_qwen_image_modulation.py` - `test/registered/kernels/benchmark/diffusion/bench_qwen_image_modulation.py`
@@ -116,9 +121,9 @@ framework-specific optimization workflow.
`test_vae_fast_path_gate.py`. `test_vae_fast_path_gate.py`.
5. Z-Image bf16-native RMSNorm modulation (Triton) 5. Z-Image bf16-native RMSNorm modulation (Triton)
- Kernels: `zimage_rmsnorm_scale`, `zimage_rmsnorm_tanh_residual` - Kernels: `rmsnorm_scale`, `rmsnorm_tanh_residual`
- Locations: `triton/native_bf16_rmsnorm.py`, compatibility exports in - Locations: `triton/native_bf16_rmsnorm.py`, with wrappers in `zimage.py` and
`triton/zimage_native_norm.py`, and `zimage.py` `fused_gate_rmsnorm.py`. Note: `triton/zimage_native_norm.py` is QK-only.
- Use cases: - Use cases:
- `y = rmsnorm(x) * scale` - `y = rmsnorm(x) * scale`
- `y = residual + tanh(gate) * rmsnorm(x)` - `y = residual + tanh(gate) * rmsnorm(x)`
@@ -162,7 +167,7 @@ framework-specific optimization workflow.
- Locations: `diffusion/residual_gate_add.py`, `csrc/diffusion/residual_gate_add.cuh`, `runtime/models/dits/ltx_2.py` - Locations: `diffusion/residual_gate_add.py`, `csrc/diffusion/residual_gate_add.cuh`, `runtime/models/dits/ltx_2.py`
- Use case: `residual + update * gate` in LTX2 self-attention, prompt cross-attention, audio/video cross-attention, and feed-forward residual updates. - Use case: `residual + update * gate` in LTX2 self-attention, prompt cross-attention, audio/video cross-attention, and feed-forward residual updates.
- Constraints: `residual`, `update`, and `gate` must be CUDA tensors on the same device, contiguous, same dtype (`fp16`, `bf16`, or `fp32`), with `update.shape == residual.shape`; `gate` can match `residual` or be row-broadcast with the last dimension matching. - Constraints: `residual`, `update`, and `gate` must be CUDA tensors on the same device, contiguous, same dtype (`fp16`, `bf16`, or `fp32`), with `update.shape == residual.shape`; `gate` can match `residual` or be row-broadcast with the last dimension matching.
- Behavior: `_ltx2_residual_gate_add(...)` uses the CUDA custom op while guards pass. On a runtime exception outside `torch.compile`, it logs once, disables the fast path for the process, and falls back to `residual + update * gate`. - Behavior: LTX2 calls `residual_gate_add(...)` from the kernels package directly. The CUDA custom op is used while guards pass. On a runtime exception outside `torch.compile`, it logs once, disables the fast path for the process, and falls back to `residual + update * gate`.
- Validation: `test/registered/kernels/ops/diffusion/test_residual_gate_add.py`. - Validation: `test/registered/kernels/ops/diffusion/test_residual_gate_add.py`.
- Microbench: `test/registered/kernels/benchmark/diffusion/bench_residual_gate_add.py`. - Microbench: `test/registered/kernels/benchmark/diffusion/bench_residual_gate_add.py`.
- Workflow rule: if LTX2 traces show repeated elementwise `mul` + `add` ladders around attention or MLP residuals, check whether this existing CUDA path was disabled by shape, dtype, contiguity, or a prior runtime failure before proposing another elementwise fusion. - Workflow rule: if LTX2 traces show repeated elementwise `mul` + `add` ladders around attention or MLP residuals, check whether this existing CUDA path was disabled by shape, dtype, contiguity, or a prior runtime failure before proposing another elementwise fusion.
@@ -291,17 +296,27 @@ framework-specific optimization workflow.
- Request-scoped high-quality acceleration: `QualityGatedFusion` in - Request-scoped high-quality acceleration: `QualityGatedFusion` in
`quality_gate.py`, `_maybe_toggle_quality_fusions` in `denoising.py`, and `quality_gate.py`, `_maybe_toggle_quality_fusions` in `denoising.py`, and
`use_vae_fast_path` in `decoding.py`. `use_vae_fast_path` in `decoding.py`.
- Bit-exact first-sight verify/disable: `BitExactFusionGate` in
`bitexact_gate.py`, used by FLUX / GLM / Sana / Ernie fused norm sites.
- Qwen-Image gating: `fuse_layernorm_scale_shift_gate_select01_kernel` and `fuse_residual_layernorm_scale_shift_gate_select01_kernel` through `fused_scale_shift_gate.py` and `qwen_image.py`. - Qwen-Image gating: `fuse_layernorm_scale_shift_gate_select01_kernel` and `fuse_residual_layernorm_scale_shift_gate_select01_kernel` through `fused_scale_shift_gate.py` and `qwen_image.py`.
- Z-Image native norm modulation: `zimage_rmsnorm_scale` and - Z-Image native norm modulation: `rmsnorm_scale` and `rmsnorm_tanh_residual`
`zimage_rmsnorm_tanh_mul_add` in `zimage.py`, backed by the shared in `triton/native_bf16_rmsnorm.py`, with wrappers in `zimage.py` /
`triton/native_bf16_rmsnorm.py` kernels. `fused_gate_rmsnorm.py`. `zimage_native_norm.py` is QK-only.
- HunyuanVideo VAE and LTX upsampler GroupNorm+SiLU: `apply_group_norm_silu` in `hunyuanvae.py` and `latent_upsampler.py`; default-eligible when wrapper guards pass. - HunyuanVideo VAE and LTX upsampler GroupNorm+SiLU: `apply_group_norm_silu` in `hunyuanvae.py` and `latent_upsampler.py`; default-eligible when wrapper guards pass.
- MiniMax-H3 indexed modulation: `_modulate_scale_shift` and `_modulate_gate` in `minimax_h3.py`, backed by `triton/indexed_modulation.py`. - MiniMax-H3 indexed modulation: `_modulate_scale_shift` and `_modulate_gate` in `minimax_h3.py`, backed by `triton/indexed_modulation.py`.
- MiniMax-H3 Ulysses relayout: `_usp_input_all_to_all_packed_qkv` and `usp_merge_heads` through `runtime/layers/usp.py`. - MiniMax-H3 Ulysses relayout: `_usp_input_all_to_all_packed_qkv` and `usp_merge_heads` through `runtime/layers/usp.py`.
- QK norm: `apply_qk_norm` used in `flux.py`, `flux_2.py`, `qwen_image.py`, `zimage.py`, `wanvideo.py`, `ltx_2.py`, `hunyuanvideo.py`. - QK norm: `apply_qk_norm` used in `flux.py`, `flux_2.py`, `qwen_image.py`, `zimage.py`, `wanvideo.py`, `ltx_2.py`, `hunyuanvideo.py`.
- QK norm + RoPE: `apply_qk_norm_rope` in `layernorm.py`; use this path when the model wants fused attention prep instead of separate QK norm and RoPE calls. - QK norm + RoPE: `apply_qk_norm_rope` in `layernorm.py`; use this path when the model wants fused attention prep instead of separate QK norm and RoPE calls.
- LTX2 split RoPE: `apply_ltx2_split_rotary_emb` in `ltx_2.py`. - LTX2 split RoPE: `apply_ltx2_split_rotary_emb` in `ltx_2.py`.
- LTX2 residual-gate add: `_ltx2_residual_gate_add` in `ltx_2.py` wraps the CUDA `diffusion_residual_gate_add` custom op for attention, cross-attention, and MLP residual updates. - LTX2 RMSNorm+modulate and FFN GELU epilogue under `quality="high"`:
`mark_ltx2_rms_norm_modulate_site` / `fused_ltx2_rms_norm_modulate` in
`kernels/ops/diffusion/ltx2_rmsnorm_modulate.py` (mount-based
`QualityGatedFusion`, not a first-sight `BitExactFusionGate` — the fused
kernel is <=1 ULP off aten, so it is request-gated instead of verified),
wired at the six `LTX2TransformerBlock` adaLN sites in `ltx_2.py`.
- LTX2 residual-gate add: `ltx_2.py` calls `residual_gate_add` from
`kernels/ops/diffusion/residual_gate_add.py` directly for attention,
cross-attention, and MLP residual updates.
- Wan causal VAE: `cat_pad_channels_last_3d` and `dup_up3d_add` in - Wan causal VAE: `cat_pad_channels_last_3d` and `dup_up3d_add` in
`wanvae.py`, backed by `triton/wan_causal_cache.py`. `wanvae.py`, backed by `triton/wan_causal_cache.py`.
- Varlen USP attention: `fused_pack_qkv` and `fused_scatter_to_padded` in `attention/layer.py`. - Varlen USP attention: `fused_pack_qkv` and `fused_scatter_to_padded` in `attention/layer.py`.
@@ -1,5 +1,9 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
from typing import Any
import torch import torch
@@ -16,3 +20,46 @@ def modulate(
if scale is None: if scale is None:
return x + shift.unsqueeze(1) # type: ignore[union-attr] return x + shift.unsqueeze(1) # type: ignore[union-attr]
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1) return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
def get_qkv_projections(
attn: Any,
hidden_states: torch.Tensor,
encoder_hidden_states: torch.Tensor | None = None,
) -> tuple[
torch.Tensor,
torch.Tensor,
torch.Tensor,
torch.Tensor | None,
torch.Tensor | None,
torch.Tensor | None,
]:
"""Shared fused/unfused QKV (+ optional added-KV) projection helper.
Used by FLUX / FLUX.2 / Qwen-Image attention blocks that expose the same
``to_qkv`` / ``to_added_qkv`` packing flags. ``use_fused_qkv`` is always
set by those blocks' constructors, and ``use_fused_added_qkv`` whenever
``added_kv_proj_dim`` is not ``None`` — direct attribute access so a
renamed flag fails loudly instead of silently unfusing.
"""
if attn.use_fused_qkv:
qkv, _ = attn.to_qkv(hidden_states)
query, key, value = [t.contiguous() for t in qkv.chunk(3, dim=-1)]
else:
query, _ = attn.to_q(hidden_states)
key, _ = attn.to_k(hidden_states)
value, _ = attn.to_v(hidden_states)
encoder_query = encoder_key = encoder_value = None
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
if attn.use_fused_added_qkv:
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
encoder_query, encoder_key, encoder_value = [
t.contiguous() for t in added_qkv.chunk(3, dim=-1)
]
else:
encoder_query, _ = attn.add_q_proj(encoder_hidden_states)
encoder_key, _ = attn.add_k_proj(encoder_hidden_states)
encoder_value, _ = attn.add_v_proj(encoder_hidden_states)
return query, key, value, encoder_query, encoder_key, encoder_value
@@ -19,6 +19,10 @@ import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from diffusers.models.embeddings import TimestepEmbedding, Timesteps from diffusers.models.embeddings import TimestepEmbedding, Timesteps
from sglang.kernels.ops.diffusion.bitexact_gate import (
BitExactFusionGate,
tensors_equal,
)
from sglang.kernels.ops.diffusion.residual_gate_add import residual_gate_add from sglang.kernels.ops.diffusion.residual_gate_add import residual_gate_add
from sglang.kernels.ops.diffusion.triton.rmsnorm_scale_shift_bitexact import ( from sglang.kernels.ops.diffusion.triton.rmsnorm_scale_shift_bitexact import (
can_use_fused_rmsnorm_scale_shift, can_use_fused_rmsnorm_scale_shift,
@@ -52,10 +56,8 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
logger = init_logger(__name__) logger = init_logger(__name__)
_ERNIE_FUSED_NORM_DISABLED = False _ERNIE_NORM = BitExactFusionGate("ERNIE fused-norm")
_ERNIE_FUSED_NORM_VERIFIED = False _ERNIE_GATED_NORM = BitExactFusionGate("ERNIE fused gated-norm")
_ERNIE_FUSED_GATED_NORM_DISABLED = False
_ERNIE_FUSED_GATED_NORM_VERIFIED = False
def _eager_norm_scale_shift( def _eager_norm_scale_shift(
@@ -75,36 +77,31 @@ def _ernie_norm_scale_shift(
first call verifies ``torch.equal`` against the eager chain and disables first call verifies ``torch.equal`` against the eager chain and disables
the fast path permanently on any mismatch. the fast path permanently on any mismatch.
""" """
global _ERNIE_FUSED_NORM_DISABLED, _ERNIE_FUSED_NORM_VERIFIED verified = _ERNIE_NORM.verified
if ( if (
not _ERNIE_FUSED_NORM_DISABLED not _ERNIE_NORM.disabled
and norm.variance_size_override is None and norm.variance_size_override is None
and can_use_fused_rmsnorm_scale_shift(x, norm.weight, scale, shift) and can_use_fused_rmsnorm_scale_shift(x, norm.weight, scale, shift)
and (_ERNIE_FUSED_NORM_VERIFIED or not torch.compiler.is_compiling()) and (verified or _ERNIE_NORM.can_attempt_once())
): ):
try: try:
out = fused_rmsnorm_scale_shift_bitexact( out = fused_rmsnorm_scale_shift_bitexact(
x, norm.weight, scale, shift, norm.variance_epsilon x, norm.weight, scale, shift, norm.variance_epsilon
) )
except Exception as exc: except Exception as exc:
if torch.compiler.is_compiling(): _ERNIE_NORM.on_exception(exc, logger=logger)
raise
logger.warning_once(f"Disabling ERNIE fused-norm fast path: {exc}")
_ERNIE_FUSED_NORM_DISABLED = True
else: else:
if _ERNIE_FUSED_NORM_VERIFIED: if verified:
return out return out
ref = _eager_norm_scale_shift(norm, x, scale, shift) return _ERNIE_NORM.accept_or_fallback(
if torch.equal(out, ref): out,
_ERNIE_FUSED_NORM_VERIFIED = True _eager_norm_scale_shift(norm, x, scale, shift),
return out logger=logger,
logger.warning_once( mismatch_msg=(
"ERNIE fused-norm fast path is not bit-exact against this " "ERNIE fused-norm fast path is not bit-exact against this "
"platform's rmsnorm dispatch; falling back to eager" "platform's rmsnorm dispatch; falling back to eager"
),
) )
_ERNIE_FUSED_NORM_DISABLED = True
return ref
return _eager_norm_scale_shift(norm, x, scale, shift) return _eager_norm_scale_shift(norm, x, scale, shift)
@@ -123,15 +120,14 @@ def _ernie_gated_norm_scale_shift(
(and the ``residual_gate_add_cuda`` fast path) + norm chain; first call (and the ``residual_gate_add_cuda`` fast path) + norm chain; first call
self-verifies like :func:`_ernie_norm_scale_shift`. self-verifies like :func:`_ernie_norm_scale_shift`.
""" """
global _ERNIE_FUSED_GATED_NORM_DISABLED, _ERNIE_FUSED_GATED_NORM_VERIFIED verified = _ERNIE_GATED_NORM.verified
if ( if (
not _ERNIE_FUSED_GATED_NORM_DISABLED not _ERNIE_GATED_NORM.disabled
and norm.variance_size_override is None and norm.variance_size_override is None
and can_use_fused_scale_residual_rmsnorm_scale_shift( and can_use_fused_scale_residual_rmsnorm_scale_shift(
residual, update, gate, norm.weight, scale, shift residual, update, gate, norm.weight, scale, shift
) )
and (_ERNIE_FUSED_GATED_NORM_VERIFIED or not torch.compiler.is_compiling()) and (verified or _ERNIE_GATED_NORM.can_attempt_once())
): ):
try: try:
out, res = fused_scale_residual_rmsnorm_scale_shift_bitexact( out, res = fused_scale_residual_rmsnorm_scale_shift_bitexact(
@@ -144,24 +140,22 @@ def _ernie_gated_norm_scale_shift(
norm.variance_epsilon, norm.variance_epsilon,
) )
except Exception as exc: except Exception as exc:
if torch.compiler.is_compiling(): _ERNIE_GATED_NORM.on_exception(exc, logger=logger)
raise
logger.warning_once(f"Disabling ERNIE fused gated-norm fast path: {exc}")
_ERNIE_FUSED_GATED_NORM_DISABLED = True
else: else:
if _ERNIE_FUSED_GATED_NORM_VERIFIED: if verified:
return out, res return out, res
res_ref = residual + gate * update res_ref = residual + gate * update
ref = _eager_norm_scale_shift(norm, res_ref, scale, shift) ref = _eager_norm_scale_shift(norm, res_ref, scale, shift)
if torch.equal(out, ref) and torch.equal(res, res_ref): return _ERNIE_GATED_NORM.accept_or_fallback(
_ERNIE_FUSED_GATED_NORM_VERIFIED = True (out, res),
return out, res (ref, res_ref),
logger.warning_once( equal=tensors_equal,
logger=logger,
mismatch_msg=(
"ERNIE fused gated-norm fast path is not bit-exact against " "ERNIE fused gated-norm fast path is not bit-exact against "
"this platform's rmsnorm dispatch; falling back to eager" "this platform's rmsnorm dispatch; falling back to eager"
),
) )
_ERNIE_FUSED_GATED_NORM_DISABLED = True
return ref, res_ref
res = residual_gate_add(residual, update, gate) res = residual_gate_add(residual, update, gate)
return _eager_norm_scale_shift(norm, res, scale, shift), res return _eager_norm_scale_shift(norm, res, scale, shift), res
@@ -28,6 +28,7 @@ from diffusers.models.normalization import (
) )
from torch.nn import LayerNorm as LayerNorm from torch.nn import LayerNorm as LayerNorm
from sglang.kernels.ops.diffusion.bitexact_gate import BitExactFusionGate
from sglang.kernels.ops.diffusion.fused_linear_gelu import ( from sglang.kernels.ops.diffusion.fused_linear_gelu import (
can_fuse_linear_gelu, can_fuse_linear_gelu,
fused_gelu_active, fused_gelu_active,
@@ -91,16 +92,18 @@ from sglang.multimodal_gen.runtime.managers.memory_managers.layerwise_offload im
LayerwiseOffloadableModuleMixin, LayerwiseOffloadableModuleMixin,
) )
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
from sglang.multimodal_gen.runtime.models.dits.common import get_qkv_projections
from sglang.multimodal_gen.runtime.platforms import current_platform from sglang.multimodal_gen.runtime.platforms import current_platform
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
logger = init_logger(__name__) # pylint: disable=invalid-name logger = init_logger(__name__) # pylint: disable=invalid-name
_get_qkv_projections = get_qkv_projections
_FLUX_FUSED_LN_MOD_DISABLED = False _FLUX_LN_MOD = BitExactFusionGate("FLUX fused LN+modulate", per_signature=True)
# (shape, stride, eps) signatures whose fused output has been verified # Keep the pre-refactor direct set lookup in this launch-sensitive hot path.
# ``torch.equal`` against the live eager chain. _FLUX_LN_MOD_SIGS = _FLUX_LN_MOD.verified_sigs
_FLUX_FUSED_LN_MOD_VERIFIED: set = set() assert _FLUX_LN_MOD_SIGS is not None
def _flux_fused_ln_modulate( def _flux_fused_ln_modulate(
@@ -118,10 +121,8 @@ def _flux_fused_ln_modulate(
verified ``torch.equal`` against the eager chain on first sight, and any verified ``torch.equal`` against the eager chain on first sight, and any
mismatch disables the fast path permanently. mismatch disables the fast path permanently.
""" """
global _FLUX_FUSED_LN_MOD_DISABLED
if ( if (
_FLUX_FUSED_LN_MOD_DISABLED _FLUX_LN_MOD.disabled
or not is_plain_layer_norm(norm, x.shape[-1]) or not is_plain_layer_norm(norm, x.shape[-1])
or not can_use_fused_layernorm_modulate(x, scale, shift) or not can_use_fused_layernorm_modulate(x, scale, shift)
): ):
@@ -135,7 +136,7 @@ def _flux_fused_ln_modulate(
shift.stride(), shift.stride(),
norm.eps, norm.eps,
) )
verified = sig in _FLUX_FUSED_LN_MOD_VERIFIED verified = sig in _FLUX_LN_MOD_SIGS
if not verified and ( if not verified and (
torch.compiler.is_compiling() or torch.cuda.is_current_stream_capturing() torch.compiler.is_compiling() or torch.cuda.is_current_stream_capturing()
): ):
@@ -145,23 +146,21 @@ def _flux_fused_ln_modulate(
try: try:
out = fused_layernorm_modulate(x, scale, shift, norm.eps) out = fused_layernorm_modulate(x, scale, shift, norm.eps)
except Exception as exc: except Exception as exc:
if torch.compiler.is_compiling(): _FLUX_LN_MOD.on_exception(exc, logger=logger)
raise
logger.warning_once(f"Disabling FLUX fused LN+modulate fast path: {exc}")
_FLUX_FUSED_LN_MOD_DISABLED = True
return None return None
if verified: if verified:
return out return out
ref = modulate_scale_shift(norm(x), scale, shift) ref = modulate_scale_shift(norm(x), scale, shift)
if torch.equal(out, ref): return _FLUX_LN_MOD.accept_or_fallback(
_FLUX_FUSED_LN_MOD_VERIFIED.add(sig) out,
return out ref,
logger.warning_once( sig=sig,
logger=logger,
mismatch_msg=(
"FLUX fused LN+modulate fast path is not bit-exact against this " "FLUX fused LN+modulate fast path is not bit-exact against this "
"platform's LayerNorm dispatch; falling back to eager" "platform's LayerNorm dispatch; falling back to eager"
),
) )
_FLUX_FUSED_LN_MOD_DISABLED = True
return ref
def _flux_norm_modulate( def _flux_norm_modulate(
@@ -373,32 +372,6 @@ def _fused_gelu_mlp(
return output.view(batch_size, seq_len, -1) return output.view(batch_size, seq_len, -1)
def _get_qkv_projections(
attn: "FluxAttention", hidden_states, encoder_hidden_states=None
):
if getattr(attn, "use_fused_qkv", False):
qkv, _ = attn.to_qkv(hidden_states)
query, key, value = [x.contiguous() for x in qkv.chunk(3, dim=-1)]
else:
query, _ = attn.to_q(hidden_states)
key, _ = attn.to_k(hidden_states)
value, _ = attn.to_v(hidden_states)
encoder_query = encoder_key = encoder_value = None
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
if attn.use_fused_added_qkv:
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
encoder_query, encoder_key, encoder_value = [
x.contiguous() for x in added_qkv.chunk(3, dim=-1)
]
else:
encoder_query, _ = attn.add_q_proj(encoder_hidden_states)
encoder_key, _ = attn.add_k_proj(encoder_hidden_states)
encoder_value, _ = attn.add_v_proj(encoder_hidden_states)
return query, key, value, encoder_query, encoder_key, encoder_value
class FluxGELU(nn.Module): class FluxGELU(nn.Module):
def __init__( def __init__(
self, self,
@@ -58,6 +58,7 @@ from sglang.multimodal_gen.runtime.managers.memory_managers.layerwise_offload im
LayerwiseOffloadableModuleMixin, LayerwiseOffloadableModuleMixin,
) )
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
from sglang.multimodal_gen.runtime.models.dits.common import get_qkv_projections
from sglang.multimodal_gen.runtime.platforms import ( from sglang.multimodal_gen.runtime.platforms import (
AttentionBackendEnum, AttentionBackendEnum,
current_platform, current_platform,
@@ -66,31 +67,7 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
logger = init_logger(__name__) # pylint: disable=invalid-name logger = init_logger(__name__) # pylint: disable=invalid-name
_get_qkv_projections = get_qkv_projections
def _get_qkv_projections(
attn: "Flux2Attention", hidden_states, encoder_hidden_states=None
):
if attn.use_fused_qkv:
qkv, _ = attn.to_qkv(hidden_states)
query, key, value = [t.contiguous() for t in qkv.chunk(3, dim=-1)]
else:
query, _ = attn.to_q(hidden_states)
key, _ = attn.to_k(hidden_states)
value, _ = attn.to_v(hidden_states)
encoder_query = encoder_key = encoder_value = None
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
if attn.use_fused_added_qkv:
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
encoder_query, encoder_key, encoder_value = [
t.contiguous() for t in added_qkv.chunk(3, dim=-1)
]
else:
encoder_query, _ = attn.add_q_proj(encoder_hidden_states)
encoder_key, _ = attn.add_k_proj(encoder_hidden_states)
encoder_value, _ = attn.add_v_proj(encoder_hidden_states)
return query, key, value, encoder_query, encoder_key, encoder_value
class Flux2SwiGLU(nn.Module): class Flux2SwiGLU(nn.Module):
@@ -18,6 +18,10 @@ import torch
import torch.nn as nn import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from sglang.kernels.ops.diffusion.bitexact_gate import (
BitExactFusionGate,
tensors_equal,
)
from sglang.kernels.ops.diffusion.fused_linear_gelu import ( from sglang.kernels.ops.diffusion.fused_linear_gelu import (
can_fuse_linear_gelu, can_fuse_linear_gelu,
fused_gelu_active, fused_gelu_active,
@@ -73,10 +77,8 @@ logger = init_logger(__name__)
_is_cuda = current_platform.is_cuda() _is_cuda = current_platform.is_cuda()
_GLM_FUSED_LN_MOD_DISABLED = False _GLM_LN_MOD = BitExactFusionGate("GLM fused LN+modulate")
_GLM_FUSED_LN_MOD_VERIFIED = False _GLM_QK_LN = BitExactFusionGate("GLM fused qk-LayerNorm")
_GLM_FUSED_QK_LN_DISABLED = False
_GLM_FUSED_QK_LN_VERIFIED = False
def _eager_ln_modulate( def _eager_ln_modulate(
@@ -102,36 +104,31 @@ def _glm_ln_modulate(
the first call verifies ``torch.equal`` against the eager chain and the first call verifies ``torch.equal`` against the eager chain and
disables the fast path permanently on any mismatch. disables the fast path permanently on any mismatch.
""" """
global _GLM_FUSED_LN_MOD_DISABLED, _GLM_FUSED_LN_MOD_VERIFIED verified = _GLM_LN_MOD.verified
if ( if (
not _GLM_FUSED_LN_MOD_DISABLED not _GLM_LN_MOD.disabled
and _is_cuda and _is_cuda
and dtype is x.dtype and dtype is x.dtype
and is_plain_layer_norm(norm, x.shape[-1]) and is_plain_layer_norm(norm, x.shape[-1])
and can_use_fused_layernorm_modulate(x, scale, shift) and can_use_fused_layernorm_modulate(x, scale, shift)
and (_GLM_FUSED_LN_MOD_VERIFIED or not torch.compiler.is_compiling()) and (verified or _GLM_LN_MOD.can_attempt_once())
): ):
try: try:
out = fused_layernorm_modulate(x, scale, shift, norm.eps) out = fused_layernorm_modulate(x, scale, shift, norm.eps)
except Exception as exc: except Exception as exc:
if torch.compiler.is_compiling(): _GLM_LN_MOD.on_exception(exc, logger=logger)
raise
logger.warning_once(f"Disabling GLM fused LN+modulate fast path: {exc}")
_GLM_FUSED_LN_MOD_DISABLED = True
else: else:
if _GLM_FUSED_LN_MOD_VERIFIED: if verified:
return out return out
ref = _eager_ln_modulate(norm, x, scale, shift, dtype) return _GLM_LN_MOD.accept_or_fallback(
if torch.equal(out, ref): out,
_GLM_FUSED_LN_MOD_VERIFIED = True _eager_ln_modulate(norm, x, scale, shift, dtype),
return out logger=logger,
logger.warning_once( mismatch_msg=(
"GLM fused LN+modulate fast path is not bit-exact against " "GLM fused LN+modulate fast path is not bit-exact against "
"this platform's LayerNorm dispatch; falling back to eager" "this platform's LayerNorm dispatch; falling back to eager"
),
) )
_GLM_FUSED_LN_MOD_DISABLED = True
return ref
return _eager_ln_modulate(norm, x, scale, shift, dtype) return _eager_ln_modulate(norm, x, scale, shift, dtype)
@@ -148,10 +145,9 @@ def _glm_qk_layernorm(
First call verifies ``torch.equal`` against the eager pair and falls First call verifies ``torch.equal`` against the eager pair and falls
back permanently on any mismatch. back permanently on any mismatch.
""" """
global _GLM_FUSED_QK_LN_DISABLED, _GLM_FUSED_QK_LN_VERIFIED verified = _GLM_QK_LN.verified
if ( if (
not _GLM_FUSED_QK_LN_DISABLED not _GLM_QK_LN.disabled
and _is_cuda and _is_cuda
and dtype is query.dtype and dtype is query.dtype
and dtype is key.dtype and dtype is key.dtype
@@ -159,29 +155,29 @@ def _glm_qk_layernorm(
and is_plain_layer_norm(norm_k, key.shape[-1]) and is_plain_layer_norm(norm_k, key.shape[-1])
and norm_q.eps == norm_k.eps and norm_q.eps == norm_k.eps
and can_use_fused_qk_head_layernorm(query, key) and can_use_fused_qk_head_layernorm(query, key)
and (_GLM_FUSED_QK_LN_VERIFIED or not torch.compiler.is_compiling()) and (verified or _GLM_QK_LN.can_attempt_once())
): ):
try: try:
q_out, k_out = fused_qk_head_layernorm(query, key, norm_q.eps) out = fused_qk_head_layernorm(query, key, norm_q.eps)
except Exception as exc: except Exception as exc:
if torch.compiler.is_compiling(): _GLM_QK_LN.on_exception(exc, logger=logger)
raise
logger.warning_once(f"Disabling GLM fused qk-LayerNorm fast path: {exc}")
_GLM_FUSED_QK_LN_DISABLED = True
else: else:
if _GLM_FUSED_QK_LN_VERIFIED: if verified:
return q_out, k_out return out
q_ref = norm_q(query).to(dtype=dtype) ref = (
k_ref = norm_k(key).to(dtype=dtype) norm_q(query).to(dtype=dtype),
if torch.equal(q_out, q_ref) and torch.equal(k_out, k_ref): norm_k(key).to(dtype=dtype),
_GLM_FUSED_QK_LN_VERIFIED = True )
return q_out, k_out return _GLM_QK_LN.accept_or_fallback(
logger.warning_once( out,
ref,
equal=tensors_equal,
logger=logger,
mismatch_msg=(
"GLM fused qk-LayerNorm fast path is not bit-exact against " "GLM fused qk-LayerNorm fast path is not bit-exact against "
"this platform's LayerNorm dispatch; falling back to eager" "this platform's LayerNorm dispatch; falling back to eager"
),
) )
_GLM_FUSED_QK_LN_DISABLED = True
return q_ref, k_ref
return norm_q(query).to(dtype=dtype), norm_k(key).to(dtype=dtype) return norm_q(query).to(dtype=dtype), norm_k(key).to(dtype=dtype)
@@ -73,6 +73,7 @@ from sglang.multimodal_gen.runtime.managers.memory_managers.layerwise_offload im
LayerwiseOffloadableModuleMixin, LayerwiseOffloadableModuleMixin,
) )
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
from sglang.multimodal_gen.runtime.models.dits.common import get_qkv_projections
from sglang.multimodal_gen.runtime.platforms import AttentionBackendEnum from sglang.multimodal_gen.runtime.platforms import AttentionBackendEnum
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import ( from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import (
@@ -104,32 +105,7 @@ def _local_seq_len(seq_len: int, sp_world_size: int) -> int:
return padded_len // sp_world_size return padded_len // sp_world_size
def _get_qkv_projections( _get_qkv_projections = get_qkv_projections
attn: "QwenImageCrossAttention", hidden_states, encoder_hidden_states=None
):
if attn.use_fused_qkv:
img_qkv, _ = attn.to_qkv(hidden_states)
img_query, img_key, img_value = [
x.contiguous() for x in img_qkv.chunk(3, dim=-1)
]
else:
img_query, _ = attn.to_q(hidden_states)
img_key, _ = attn.to_k(hidden_states)
img_value, _ = attn.to_v(hidden_states)
txt_query = txt_key = txt_value = None
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
if attn.use_fused_added_qkv:
txt_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
txt_query, txt_key, txt_value = [
x.contiguous() for x in txt_qkv.chunk(3, dim=-1)
]
else:
txt_query, _ = attn.add_q_proj(encoder_hidden_states)
txt_key, _ = attn.add_k_proj(encoder_hidden_states)
txt_value, _ = attn.add_v_proj(encoder_hidden_states)
return img_query, img_key, img_value, txt_query, txt_key, txt_value
class QwenTimestepProjEmbeddings(nn.Module): class QwenTimestepProjEmbeddings(nn.Module):
@@ -5,6 +5,7 @@ import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from diffusers.models.embeddings import PixArtAlphaTextProjection, TimestepEmbedding from diffusers.models.embeddings import PixArtAlphaTextProjection, TimestepEmbedding
from sglang.kernels.ops.diffusion.bitexact_gate import BitExactFusionGate
from sglang.kernels.ops.diffusion.triton.layernorm_modulate import ( from sglang.kernels.ops.diffusion.triton.layernorm_modulate import (
can_use_fused_layernorm_modulate, can_use_fused_layernorm_modulate,
fused_layernorm_modulate_raw, fused_layernorm_modulate_raw,
@@ -22,10 +23,12 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
logger = init_logger(__name__) logger = init_logger(__name__)
_SANA_FUSED_LN_MOD_DISABLED = False _SANA_LN_MOD = BitExactFusionGate("Sana fused LN+modulate", per_signature=True)
# (shape/stride/dtype/eps) signatures whose fused output was torch.equal- # Direct module-level state keeps BCG warmup launch overhead equal to the
# verified against the live eager chain. # pre-refactor path; the gate still owns first-sight verification transitions.
_SANA_FUSED_LN_MOD_OK_SIGS: set = set() _SANA_LN_MOD_SIGS = _SANA_LN_MOD.verified_sigs
assert _SANA_LN_MOD_SIGS is not None
_SANA_LN_MOD_DISABLED = False
def _eager_ln_modulate( def _eager_ln_modulate(
@@ -61,9 +64,9 @@ def _sana_ln_modulate(
layout); aten's LayerNorm contiguizes internally, and the fast path layout); aten's LayerNorm contiguizes internally, and the fast path
issues the same copy explicitly. issues the same copy explicitly.
""" """
global _SANA_FUSED_LN_MOD_DISABLED global _SANA_LN_MOD_DISABLED
if _SANA_FUSED_LN_MOD_DISABLED or torch.compiler.is_compiling() or not x.is_cuda: if _SANA_LN_MOD_DISABLED or torch.compiler.is_compiling() or not x.is_cuda:
return _eager_ln_modulate(norm, x, scale, shift) return _eager_ln_modulate(norm, x, scale, shift)
capturing = torch.cuda.is_current_stream_capturing() capturing = torch.cuda.is_current_stream_capturing()
@@ -79,7 +82,7 @@ def _sana_ln_modulate(
shift.stride(), shift.stride(),
norm.eps, norm.eps,
) )
if sig in _SANA_FUSED_LN_MOD_OK_SIGS: if sig in _SANA_LN_MOD_SIGS:
return fused_layernorm_modulate_raw( return fused_layernorm_modulate_raw(
x.contiguous(), scale[:, 0], shift[:, 0], norm.eps x.contiguous(), scale[:, 0], shift[:, 0], norm.eps
) )
@@ -101,19 +104,21 @@ def _sana_ln_modulate(
try: try:
out = fused_layernorm_modulate_raw(x_c, scale[:, 0], shift[:, 0], norm.eps) out = fused_layernorm_modulate_raw(x_c, scale[:, 0], shift[:, 0], norm.eps)
except Exception as exc: except Exception as exc:
logger.warning_once(f"Disabling Sana fused LN+modulate fast path: {exc}") _SANA_LN_MOD.on_exception(exc, logger=logger)
_SANA_FUSED_LN_MOD_DISABLED = True _SANA_LN_MOD_DISABLED = True
else: else:
ref = _eager_ln_modulate(norm, x, scale, shift) result = _SANA_LN_MOD.accept_or_fallback(
if torch.equal(out, ref): out,
_SANA_FUSED_LN_MOD_OK_SIGS.add(sig) _eager_ln_modulate(norm, x, scale, shift),
return out sig=sig,
logger.warning_once( logger=logger,
mismatch_msg=(
"Sana fused LN+modulate fast path is not bit-exact against " "Sana fused LN+modulate fast path is not bit-exact against "
"this platform's LayerNorm dispatch; falling back to eager" "this platform's LayerNorm dispatch; falling back to eager"
),
) )
_SANA_FUSED_LN_MOD_DISABLED = True _SANA_LN_MOD_DISABLED = _SANA_LN_MOD.disabled
return ref return result
return _eager_ln_modulate(norm, x, scale, shift) return _eager_ln_modulate(norm, x, scale, shift)
@@ -85,9 +85,6 @@ from sglang.multimodal_gen.runtime.layers.attention.STA_configuration import (
configure_sta, configure_sta,
save_mask_search_results, save_mask_search_results,
) )
from sglang.multimodal_gen.runtime.loader.component_loaders.transformer_loader import (
TransformerLoader,
)
from sglang.multimodal_gen.runtime.managers.forward_context import set_forward_context from sglang.multimodal_gen.runtime.managers.forward_context import set_forward_context
from sglang.multimodal_gen.runtime.managers.memory_managers.component_manager import ( from sglang.multimodal_gen.runtime.managers.memory_managers.component_manager import (
ComponentUse, ComponentUse,
@@ -125,6 +122,10 @@ from sglang.multimodal_gen.runtime.post_training.rollout_denoising_mixin import
RolloutDenoisingMixin, RolloutDenoisingMixin,
) )
from sglang.multimodal_gen.runtime.server_args import ServerArgs from sglang.multimodal_gen.runtime.server_args import ServerArgs
from sglang.multimodal_gen.runtime.utils.component_load import (
load_transformer_if_needed,
register_loaded_transformer,
)
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
from sglang.multimodal_gen.runtime.utils.nvtx_pytorch_hooks import maybe_nvtx_range from sglang.multimodal_gen.runtime.utils.nvtx_pytorch_hooks import maybe_nvtx_range
from sglang.multimodal_gen.runtime.utils.perf_logger import StageProfiler from sglang.multimodal_gen.runtime.utils.perf_logger import StageProfiler
@@ -886,22 +887,14 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
else: else:
cache_dit_num_inference_steps = num_inference_steps cache_dit_num_inference_steps = num_inference_steps
transformer_was_loaded = server_args.model_loaded["transformer"] freshly_loaded = load_transformer_if_needed(self, server_args)
if not transformer_was_loaded:
# FIXME: reuse more code
loader = TransformerLoader()
self.transformer = loader.load(
server_args.model_paths["transformer"], server_args, "transformer"
)
self._maybe_enable_cache_dit_and_torch_compile( self._maybe_enable_cache_dit_and_torch_compile(
cache_dit_num_inference_steps, batch cache_dit_num_inference_steps, batch
) )
if not transformer_was_loaded: if freshly_loaded:
if pipeline: register_loaded_transformer(self, server_args, pipeline)
pipeline.add_module("transformer", self.transformer)
server_args.model_loaded["transformer"] = True
if batch.rollout: if batch.rollout:
self._maybe_prepare_rollout(batch) self._maybe_prepare_rollout(batch)
@@ -16,9 +16,6 @@ import torch
from sglang.multimodal_gen.configs.pipeline_configs.hunyuan3d import ( from sglang.multimodal_gen.configs.pipeline_configs.hunyuan3d import (
Hunyuan3D2PipelineConfig, Hunyuan3D2PipelineConfig,
) )
from sglang.multimodal_gen.runtime.loader.component_loaders.transformer_loader import (
TransformerLoader,
)
from sglang.multimodal_gen.runtime.managers.forward_context import set_forward_context from sglang.multimodal_gen.runtime.managers.forward_context import set_forward_context
from sglang.multimodal_gen.runtime.pipelines_core.schedule_batch import OutputBatch, Req from sglang.multimodal_gen.runtime.pipelines_core.schedule_batch import OutputBatch, Req
from sglang.multimodal_gen.runtime.pipelines_core.stages.base import PipelineStage from sglang.multimodal_gen.runtime.pipelines_core.stages.base import PipelineStage
@@ -33,6 +30,10 @@ from sglang.multimodal_gen.runtime.pipelines_core.stages.validators import (
VerificationResult, VerificationResult,
) )
from sglang.multimodal_gen.runtime.server_args import ServerArgs from sglang.multimodal_gen.runtime.server_args import ServerArgs
from sglang.multimodal_gen.runtime.utils.component_load import (
load_transformer_if_needed,
register_loaded_transformer,
)
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
from sglang.multimodal_gen.runtime.utils.mesh3d_utils import export_to_trimesh from sglang.multimodal_gen.runtime.utils.mesh3d_utils import export_to_trimesh
@@ -293,16 +294,11 @@ class Hunyuan3DShapeDenoisingStage(DenoisingStage):
cache_dit_num_inference_steps = batch.extra.get( cache_dit_num_inference_steps = batch.extra.get(
"cache_dit_num_inference_steps", batch.num_inference_steps "cache_dit_num_inference_steps", batch.num_inference_steps
) )
if not server_args.model_loaded["transformer"]: freshly_loaded = load_transformer_if_needed(self, server_args)
loader = TransformerLoader() if freshly_loaded:
self.transformer = loader.load(
server_args.model_paths["transformer"], server_args, "transformer"
)
self._maybe_enable_cache_dit(cache_dit_num_inference_steps, batch) self._maybe_enable_cache_dit(cache_dit_num_inference_steps, batch)
self._maybe_torch_compile(self.transformer) self._maybe_torch_compile(self.transformer)
if pipeline: register_loaded_transformer(self, server_args, pipeline)
pipeline.add_module("transformer", self.transformer)
server_args.model_loaded["transformer"] = True
else: else:
self._maybe_enable_cache_dit(cache_dit_num_inference_steps, batch) self._maybe_enable_cache_dit(cache_dit_num_inference_steps, batch)
@@ -0,0 +1,29 @@
# SPDX-License-Identifier: Apache-2.0
"""Shared helpers for lazily loading pipeline components onto stages."""
from __future__ import annotations
from typing import Any
from sglang.multimodal_gen.runtime.loader.component_loaders.transformer_loader import (
TransformerLoader,
)
from sglang.multimodal_gen.runtime.server_args import ServerArgs
def load_transformer_if_needed(stage: Any, server_args: ServerArgs) -> bool:
"""Load transformer onto stage if not marked loaded. Returns True if freshly loaded."""
if server_args.model_loaded["transformer"]:
return False
stage.transformer = TransformerLoader().load(
server_args.model_paths["transformer"], server_args, "transformer"
)
return True
def register_loaded_transformer(
stage: Any, server_args: ServerArgs, pipeline: Any
) -> None:
if pipeline is not None:
pipeline.add_module("transformer", stage.transformer)
server_args.model_loaded["transformer"] = True
@@ -4,7 +4,7 @@ from typing import Iterator, Optional, Union
import torch import torch
from sglang.multimodal_gen.runtime.platforms import current_platform from sglang.multimodal_gen.runtime.platforms import current_platform
from sglang.multimodal_gen.utils import PRECISION_TO_TYPE from sglang.multimodal_gen.runtime.utils.precision_types import PRECISION_TO_TYPE
def precision_to_dtype(precision: str, field_name: str = "precision") -> torch.dtype: def precision_to_dtype(precision: str, field_name: str = "precision") -> torch.dtype:
@@ -0,0 +1,11 @@
"""Canonical string→dtype map for diffusion precision configs."""
import torch
PRECISION_TO_TYPE = {
"fp32": torch.float32,
"fp16": torch.float16,
"bf16": torch.bfloat16,
}
__all__ = ["PRECISION_TO_TYPE"]
+3 -8
View File
@@ -29,6 +29,9 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import (
SortedHelpFormatter, SortedHelpFormatter,
init_logger, init_logger,
) )
from sglang.multimodal_gen.runtime.utils.precision_types import (
PRECISION_TO_TYPE as PRECISION_TO_TYPE,
)
logger = init_logger(__name__) logger = init_logger(__name__)
@@ -52,14 +55,6 @@ def expand_path_fields(obj) -> None:
) )
# TODO(will): used to convert server_args.precision to torch.dtype. Find a
# cleaner way to do this.
PRECISION_TO_TYPE = {
"fp32": torch.float32,
"fp16": torch.float16,
"bf16": torch.bfloat16,
}
STR_BACKEND_ENV_VAR: str = "SGLANG_DIFFUSION_ATTENTION_BACKEND" STR_BACKEND_ENV_VAR: str = "SGLANG_DIFFUSION_ATTENTION_BACKEND"
STR_ATTN_CONFIG_ENV_VAR: str = "SGLANG_DIFFUSION_ATTENTION_CONFIG" STR_ATTN_CONFIG_ENV_VAR: str = "SGLANG_DIFFUSION_ATTENTION_CONFIG"
@@ -0,0 +1,80 @@
import sys
import pytest
import torch
from sglang.kernels.ops.diffusion.bitexact_gate import (
BitExactFusionGate,
tensors_equal,
)
from sglang.test.ci.ci_register import register_cpu_ci
register_cpu_ci(est_time=2, suite="base-a-test-cpu")
def test_bitexact_gate_once_mode_verifies_then_reuses():
gate = BitExactFusionGate("once")
calls = {"fused": 0, "ref": 0}
def fused():
calls["fused"] += 1
return torch.tensor([1.0])
def ref():
calls["ref"] += 1
return torch.tensor([1.0])
assert torch.equal(gate.accept_or_fallback(fused(), ref()), torch.tensor([1.0]))
assert gate.verified and not gate.disabled and calls == {"fused": 1, "ref": 1}
assert torch.equal(fused(), torch.tensor([1.0]))
assert calls == {"fused": 2, "ref": 1}
def test_bitexact_gate_mismatch_disables_permanently():
gate = BitExactFusionGate("mismatch")
out = gate.accept_or_fallback(
torch.tensor([1.0]),
torch.tensor([2.0]),
mismatch_msg="mismatch",
)
assert torch.equal(out, torch.tensor([2.0]))
assert gate.disabled and not gate.verified
def test_bitexact_gate_per_signature_tracks_each_sig():
gate = BitExactFusionGate("sig", per_signature=True)
a = torch.tensor([1.0])
assert torch.equal(gate.accept_or_fallback(a, a, sig=("a",)), a)
assert gate.is_verified(("a",))
assert not gate.is_verified(("b",))
assert torch.equal(gate.accept_or_fallback(a, a, sig=("b",)), a)
assert gate.verified_sigs == {("a",), ("b",)}
def test_bitexact_gate_skips_first_sight_during_graph_capture(monkeypatch):
# Negative-branch contract: an unverified gate must not attempt first-sight
# verification inside CUDA graph capture — the eager-reference host sync
# would abort the capture (and BCG would permanently block the signature).
gate = BitExactFusionGate("capture")
monkeypatch.setattr(torch.cuda, "is_available", lambda: True)
monkeypatch.setattr(torch.cuda, "is_current_stream_capturing", lambda: True)
assert not gate.can_attempt_once()
# A verified gate replays the fused kernel alone, which is capture-safe.
gate.mark_verified()
assert gate.can_attempt_once()
def test_tensors_equal_supports_sequences():
assert tensors_equal(
(torch.tensor([1.0]), torch.tensor([2.0])),
(torch.tensor([1.0]), torch.tensor([2.0])),
)
assert not tensors_equal(
(torch.tensor([1.0]), torch.tensor([2.0])),
(torch.tensor([1.0]), torch.tensor([3.0])),
)
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-v"]))
@@ -47,10 +47,10 @@ def test_fused_norm_scale_shift_is_bit_exact(shape):
assert torch.equal(out2, ref2) assert torch.equal(out2, ref2)
# the fast paths must actually be in use (not silently disabled) # the fast paths must actually be in use (not silently disabled)
assert ernie_image._ERNIE_FUSED_NORM_VERIFIED assert ernie_image._ERNIE_NORM.verified
assert ernie_image._ERNIE_FUSED_GATED_NORM_VERIFIED assert ernie_image._ERNIE_GATED_NORM.verified
assert not ernie_image._ERNIE_FUSED_NORM_DISABLED assert not ernie_image._ERNIE_NORM.disabled
assert not ernie_image._ERNIE_FUSED_GATED_NORM_DISABLED assert not ernie_image._ERNIE_GATED_NORM.disabled
if __name__ == "__main__": if __name__ == "__main__":
@@ -48,8 +48,8 @@ def test_flux_fused_ln_modulate_is_bit_exact(shape, chunks):
out = _flux_fused_ln_modulate(norm, x, scale, shift) out = _flux_fused_ln_modulate(norm, x, scale, shift)
assert out is not None assert out is not None
assert torch.equal(out, _eager(norm, x, scale, shift)) assert torch.equal(out, _eager(norm, x, scale, shift))
assert not flux._FLUX_FUSED_LN_MOD_DISABLED assert not flux._FLUX_LN_MOD.disabled
assert flux._FLUX_FUSED_LN_MOD_VERIFIED assert flux._FLUX_LN_MOD.verified
def test_flux_norm_modulate_bitexact_supersedes_high_fold(): def test_flux_norm_modulate_bitexact_supersedes_high_fold():
@@ -28,8 +28,8 @@ def test_fused_ln_modulate_is_bit_exact(shape):
shift, scale = chunks[0], chunks[2] shift, scale = chunks[0], chunks[2]
out = _glm_ln_modulate(norm, x, scale, shift, x.dtype) out = _glm_ln_modulate(norm, x, scale, shift, x.dtype)
assert torch.equal(out, _eager_ln_modulate(norm, x, scale, shift, x.dtype)) assert torch.equal(out, _eager_ln_modulate(norm, x, scale, shift, x.dtype))
assert glm_image._GLM_FUSED_LN_MOD_VERIFIED assert glm_image._GLM_LN_MOD.verified
assert not glm_image._GLM_FUSED_LN_MOD_DISABLED assert not glm_image._GLM_LN_MOD.disabled
@pytest.mark.parametrize("shape", [(1, 4360, 32, 128), (2, 37, 3, 40), (1, 129, 5, 64)]) @pytest.mark.parametrize("shape", [(1, 4360, 32, 128), (2, 37, 3, 40), (1, 129, 5, 64)])
@@ -45,8 +45,8 @@ def test_fused_qk_head_layernorm_is_bit_exact(shape):
q_out, k_out = _glm_qk_layernorm(norm_q, norm_k, q, k, q.dtype) q_out, k_out = _glm_qk_layernorm(norm_q, norm_k, q, k, q.dtype)
assert torch.equal(q_out, norm_q(q).to(q.dtype)) assert torch.equal(q_out, norm_q(q).to(q.dtype))
assert torch.equal(k_out, norm_k(k).to(k.dtype)) assert torch.equal(k_out, norm_k(k).to(k.dtype))
assert glm_image._GLM_FUSED_QK_LN_VERIFIED assert glm_image._GLM_QK_LN.verified
assert not glm_image._GLM_FUSED_QK_LN_DISABLED assert not glm_image._GLM_QK_LN.disabled
if __name__ == "__main__": if __name__ == "__main__":
@@ -36,17 +36,17 @@ def test_sana_fused_ln_modulate_is_bit_exact(shape, nmod, transposed):
emb = torch.randn(batch, nmod, hidden, device="cuda").bfloat16() emb = torch.randn(batch, nmod, hidden, device="cuda").bfloat16()
shift, scale = emb.chunk(nmod, dim=1)[0], emb.chunk(nmod, dim=1)[-1] shift, scale = emb.chunk(nmod, dim=1)[0], emb.chunk(nmod, dim=1)[-1]
# default-stream eager serving must stay on the untouched eager chain # default-stream eager serving must stay on the untouched eager chain
n_sigs = len(sana._SANA_FUSED_LN_MOD_OK_SIGS) n_sigs = len(sana._SANA_LN_MOD.verified_sigs)
_sana_ln_modulate(norm, x, scale, shift) _sana_ln_modulate(norm, x, scale, shift)
assert len(sana._SANA_FUSED_LN_MOD_OK_SIGS) == n_sigs assert len(sana._SANA_LN_MOD.verified_sigs) == n_sigs
# the fusion engages on non-default streams (the BCG warmup/capture path) # the fusion engages on non-default streams (the BCG warmup/capture path)
with torch.cuda.stream(torch.cuda.Stream()): with torch.cuda.stream(torch.cuda.Stream()):
out = _sana_ln_modulate(norm, x, scale, shift) out = _sana_ln_modulate(norm, x, scale, shift)
assert len(sana._SANA_FUSED_LN_MOD_OK_SIGS) == n_sigs + 1 # verified assert len(sana._SANA_LN_MOD.verified_sigs) == n_sigs + 1 # verified
out2 = _sana_ln_modulate(norm, x, scale, shift) # verified-sig lane out2 = _sana_ln_modulate(norm, x, scale, shift) # verified-sig lane
torch.cuda.synchronize() torch.cuda.synchronize()
assert torch.equal(out, _eager_ln_modulate(norm, x, scale, shift)) assert torch.equal(out, _eager_ln_modulate(norm, x, scale, shift))
assert torch.equal(out2, out) and not sana._SANA_FUSED_LN_MOD_DISABLED assert torch.equal(out2, out) and not sana._SANA_LN_MOD.disabled
if __name__ == "__main__": if __name__ == "__main__":