Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def get_impl_cls() -> type["AttentionImpl"]:
def supports_packed_varlen(cls) -> bool:
return cls.get_impl_cls().forward_varlen is not AttentionImpl.forward_varlen

@classmethod
def supports_ring_rotation(cls) -> bool:
"""Whether this backend can serve as the ring-attention kernel; the
per-hop online-softmax merge needs the kernel's softmax LSE."""
return False

@classmethod
def unsupported_requirements(
cls, requirements: AttentionRequirements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
import torch

from sglang.kernels.ops.attention.flash_attention import flash_attn_varlen_func
from sglang.multimodal_gen.runtime.layers.attention.backends.attention_backend import (
AttentionBackend,
AttentionImpl,
AttentionMetadata,
AttentionMetadataBuilder,
)
from sglang.multimodal_gen.runtime.layers.utils import register_custom_op
from sglang.multimodal_gen.runtime.platforms import (
AttentionBackendEnum,
Expand Down Expand Up @@ -285,13 +291,6 @@ def flash_attn_varlen_func_op_lse(
)


from sglang.multimodal_gen.runtime.layers.attention.backends.attention_backend import (
AttentionBackend,
AttentionImpl,
AttentionMetadata,
AttentionMetadataBuilder,
)

fa_ver = 3


Expand Down Expand Up @@ -330,6 +329,11 @@ def build( # type: ignore


class FlashAttentionBackend(AttentionBackend):

@classmethod
def supports_ring_rotation(cls) -> bool:
return True

accept_output_buffer: bool = True

@staticmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ def _trailing_padding_used_len(


class SageAttentionBackend(AttentionBackend):

@classmethod
def supports_ring_rotation(cls) -> bool:
return True

accept_output_buffer: bool = True

@staticmethod
Expand Down
13 changes: 5 additions & 8 deletions python/sglang/multimodal_gen/runtime/layers/attention/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -689,15 +689,12 @@ def __init__(
head_size, dtype, supported_attention_backends=supported_attention_backends
)
if get_ring_parallel_world_size() > 1:
backend_enum = attn_backend.get_enum()
if backend_enum not in (
AttentionBackendEnum.FA,
AttentionBackendEnum.SAGE_ATTN,
):
if not attn_backend.supports_ring_rotation():
raise RuntimeError(
f"Ring Attention is only supported for FlashAttention or SageAttention backends, "
f"but got {backend_enum.name}. "
f"Please ensure your platform supports these backends."
f"Ring Attention requires a backend whose kernel exposes the "
f"softmax LSE for the per-hop merge; "
f"{attn_backend.get_enum().name} does not declare support "
f"(see AttentionBackend.supports_ring_rotation)."
)
impl_cls: Type[AttentionImpl] = attn_backend.get_impl_cls()
self.allow_cudnn_sdp = bool(extra_impl_args.get("allow_cudnn_sdp", False))
Expand Down
8 changes: 8 additions & 0 deletions python/sglang/multimodal_gen/runtime/models/dits/zimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,14 @@ def forward(
use_full_unified_sequence = (
get_sp_world_size() > 1 and get_ring_parallel_world_size() > 1
)
if use_full_unified_sequence:
# Ring support for this attention layout is not implemented; the
# full-sequence gather is correct but gives up ring's memory and
# overlap benefits.
logger.warning_once(
"zimage under ring_degree > 1 falls back to a full-sequence "
"K/V gather"
)
x_local_seq_len = x.shape[1]
if use_full_unified_sequence:
x = sequence_model_parallel_all_gather(x.contiguous(), dim=1)
Expand Down
20 changes: 13 additions & 7 deletions python/sglang/multimodal_gen/runtime/server_args/server_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
# H200-class GPUs (>=130 GiB total) can usually keep both LTX2 DiTs resident.
LTX2_RESIDENT_AUTO_ENABLE_MEM_GB = 130
LORA_MERGE_MODES = ("auto", "merge", "dynamic")
# Mirrors AttentionBackend.supports_ring_rotation; the name-level check
# runs before backend classes are importable on every platform.
RING_CAPABLE_ATTENTION_BACKENDS = ("fa", "sage_attn")


def _normalize_ltx2_two_stage_device_mode(mode: str | None) -> str | None:
Expand Down Expand Up @@ -756,18 +759,21 @@ def _adjust_attention_backend(self):
self.component_attention_backends["text_encoder"] = "torch_sdpa"

if self.ring_degree > 1:
if self.attention_backend is not None and self.attention_backend not in (
"fa",
"sage_attn",
if (
self.attention_backend is not None
and self.attention_backend not in RING_CAPABLE_ATTENTION_BACKENDS
):
raise ValueError(
"Ring Attention is only supported for flash attention or sage attention backend for now"
"Ring Attention requires one of the ring-capable backends "
f"({', '.join(RING_CAPABLE_ATTENTION_BACKENDS)}), got "
f"{self.attention_backend!r}"
)
if self.attention_backend is None:
self.attention_backend = "fa"
self.attention_backend = RING_CAPABLE_ATTENTION_BACKENDS[0]
logger.info(
"Ring Attention is currently only supported for flash attention or sage attention; "
"attention_backend has been automatically set to flash attention"
"Ring Attention requires a ring-capable backend; "
"attention_backend has been automatically set to %s",
self.attention_backend,
)

if self.attention_backend is None and self.backend != Backend.DIFFUSERS:
Expand Down
39 changes: 39 additions & 0 deletions python/sglang/multimodal_gen/test/unit/test_ring_admission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: Apache-2.0
"""Ring admission is a backend capability, not a name whitelist."""

import unittest

from sglang.multimodal_gen.runtime.layers.attention.backends.attention_backend import (
AttentionBackend,
)
from sglang.multimodal_gen.runtime.layers.attention.backends.flash_attn import (
FlashAttentionBackend,
)
from sglang.multimodal_gen.runtime.layers.attention.backends.sdpa import SDPABackend
from sglang.multimodal_gen.runtime.server_args.server_args import (
RING_CAPABLE_ATTENTION_BACKENDS,
)


class TestRingAdmission(unittest.TestCase):
def test_default_is_not_ring_capable(self):
self.assertFalse(AttentionBackend.supports_ring_rotation())
self.assertFalse(SDPABackend.supports_ring_rotation())

def test_lse_backends_declare_support(self):
self.assertTrue(FlashAttentionBackend.supports_ring_rotation())

def test_server_args_names_match_capabilities(self):
# the name-level list gates before backend classes are importable on
# every platform; keep it consistent with the classes it mirrors
self.assertIn(
FlashAttentionBackend.get_enum().name.lower(),
RING_CAPABLE_ATTENTION_BACKENDS,
)
self.assertNotIn(
SDPABackend.get_enum().name.lower(), RING_CAPABLE_ATTENTION_BACKENDS
)


if __name__ == "__main__":
unittest.main()
Loading