Signed-off-by: wangyu <410167048@qq.com> Signed-off-by: lishunyang12 <lishunyang12@163.com> Signed-off-by: [Your Name] <your.email@example.com> Signed-off-by: wangyu <53896905+yenuo26@users.noreply.github.com> Signed-off-by: Bo Li <22713281+bobboli@users.noreply.github.com> Co-authored-by: lishunyang12 <lishunyang12@163.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Bo Li <22713281+bobboli@users.noreply.github.com>
113 lines
4.8 KiB
Python
113 lines
4.8 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
|
|
|
import pytest
|
|
import torch
|
|
|
|
from vllm_omni.diffusion.attention.backends import flashinfer_attn
|
|
from vllm_omni.diffusion.attention.backends.abstract import AttentionMetadata
|
|
from vllm_omni.diffusion.attention.backends.flashinfer_attn import (
|
|
FlashInferAttentionBackend,
|
|
FlashInferAttentionImpl,
|
|
)
|
|
from vllm_omni.diffusion.data import AttentionSpec, AttnQuantSpec
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cpu]
|
|
|
|
|
|
def _impl(*, causal: bool = False, backend_explicit: bool = False):
|
|
# Avoid CUDA/wrapper init; these tests only cover mask validation.
|
|
obj = FlashInferAttentionImpl.__new__(FlashInferAttentionImpl)
|
|
obj.causal = causal
|
|
obj.softmax_scale = 0.5
|
|
obj.flashinfer_backend = "fa2"
|
|
obj.backend_explicit = backend_explicit
|
|
obj._sdpa_fallback = None
|
|
return obj
|
|
|
|
|
|
def test_flashinfer_rejects_float_mask_instead_of_falling_back(monkeypatch):
|
|
monkeypatch.setattr(flashinfer_attn, "HAS_FLASHINFER", True)
|
|
query = torch.randn(1, 2, 2, 8)
|
|
metadata = AttentionMetadata(attn_mask=torch.zeros(2, 2))
|
|
|
|
with pytest.raises(ValueError, match="boolean-only"):
|
|
_impl(backend_explicit=True).forward_cuda(query, query, query, metadata)
|
|
|
|
|
|
def test_flashinfer_rejects_causal_custom_mask_instead_of_falling_back(monkeypatch):
|
|
monkeypatch.setattr(flashinfer_attn, "HAS_FLASHINFER", True)
|
|
query = torch.randn(1, 2, 2, 8)
|
|
metadata = AttentionMetadata(attn_mask=torch.tensor([[True, False], [True, True]]))
|
|
|
|
with pytest.raises(ValueError, match="causal=True"):
|
|
_impl(causal=True, backend_explicit=True).forward_cuda(query, query, query, metadata)
|
|
|
|
|
|
def test_explicit_cute_dsl_rejects_custom_mask_instead_of_falling_back(monkeypatch):
|
|
monkeypatch.setattr(flashinfer_attn, "HAS_FLASHINFER", True)
|
|
impl = _impl(backend_explicit=True)
|
|
impl.flashinfer_backend = "cute-dsl"
|
|
query = torch.randn(1, 2, 2, 8)
|
|
metadata = AttentionMetadata(attn_mask=torch.tensor([[True, False], [True, True]]))
|
|
|
|
with pytest.raises(ValueError, match="cute-dsl"):
|
|
impl.forward_cuda(query, query, query, metadata)
|
|
|
|
|
|
def test_auto_cute_dsl_falls_back_to_sdpa_for_custom_mask(monkeypatch):
|
|
monkeypatch.setattr(flashinfer_attn, "HAS_FLASHINFER", True)
|
|
impl = _impl(backend_explicit=False)
|
|
impl.flashinfer_backend = "cute-dsl"
|
|
impl._run_batch_prefill = lambda *args, **kwargs: pytest.fail("unexpected cute-dsl prefill")
|
|
query = torch.randn(1, 2, 2, 8)
|
|
metadata = AttentionMetadata(attn_mask=torch.tensor([[True, False], [True, True]]))
|
|
|
|
output = impl.forward_cuda(query, query, query, metadata)
|
|
|
|
assert output.shape == query.shape
|
|
|
|
|
|
def test_explicit_cute_dsl_is_not_mask_capable(monkeypatch):
|
|
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda *args, **kwargs: (10, 0))
|
|
spec = AttentionSpec(backend="FLASHINFER_ATTN")
|
|
|
|
assert FlashInferAttentionBackend.supports_attention_mask() is True
|
|
assert FlashInferAttentionBackend.supports_attention_mask(spec) is False
|
|
|
|
|
|
def test_explicit_fa2_flashinfer_is_mask_capable(monkeypatch):
|
|
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda *args, **kwargs: (10, 0))
|
|
spec = AttentionSpec(backend="FLASHINFER_ATTN", quant=AttnQuantSpec(flashinfer_backend="fa2"))
|
|
|
|
assert FlashInferAttentionBackend.supports_attention_mask(spec) is True
|
|
|
|
|
|
def test_explicit_fa2_backend_kwargs_select_fa2_on_blackwell(monkeypatch):
|
|
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda *args, **kwargs: (10, 0))
|
|
spec = AttentionSpec(backend="FLASHINFER_ATTN", quant=AttnQuantSpec(flashinfer_backend="fa2"))
|
|
kwargs = spec.backend_kwargs() or {}
|
|
requested = (kwargs.get("quant") or {}).get("flashinfer_backend", "auto")
|
|
|
|
assert kwargs == {"quant": {"flashinfer_backend": "fa2"}}
|
|
assert FlashInferAttentionImpl._select_backend(requested) == "fa2"
|
|
assert FlashInferAttentionBackend.supports_attention_mask(spec) is True
|
|
|
|
|
|
def test_auto_flashinfer_backend_kwargs_select_cute_dsl_on_blackwell(monkeypatch):
|
|
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda *args, **kwargs: (10, 0))
|
|
spec = AttentionSpec(backend="FLASHINFER_ATTN")
|
|
kwargs = spec.backend_kwargs() or {}
|
|
requested = (kwargs.get("quant") or {}).get("flashinfer_backend", "auto")
|
|
|
|
assert "quant" not in kwargs
|
|
assert FlashInferAttentionImpl._select_backend(requested) == "cute-dsl"
|
|
assert FlashInferAttentionBackend.supports_attention_mask(spec) is False
|
|
|
|
|
|
def test_hopper_explicit_flashinfer_is_mask_capable(monkeypatch):
|
|
monkeypatch.setattr(torch.cuda, "get_device_capability", lambda *args, **kwargs: (9, 0))
|
|
spec = AttentionSpec(backend="FLASHINFER_ATTN")
|
|
|
|
assert FlashInferAttentionBackend.supports_attention_mask(spec) is True
|