Spaces:
Running on L40S
Running on L40S
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| # SPDX-License-Identifier: OpenMDW-1.1 | |
| """ | |
| Imaginaire4 Attention Subpackage: | |
| Unified implementation for all Attention implementations. | |
| Frontend APIs | |
| """ | |
| import torch | |
| from cosmos_framework.model.attention.flash2.checks import flash2_attention_check | |
| from cosmos_framework.model.attention.flash3.checks import flash3_attention_check | |
| from cosmos_framework.model.attention.masks import CausalType | |
| from cosmos_framework.model.attention.natten.checks import natten_attention_check, natten_multi_dim_attention_check | |
| from cosmos_framework.model.attention.utils import get_arch_tag | |
| from cosmos_framework.model.attention.utils.environment import ( | |
| filter_attention_backends, | |
| filter_multi_dim_attention_backends, | |
| ) | |
| from cosmos_framework.model.attention.utils.safe_ops import log | |
| from cosmos_framework.model.attention.utils.safe_ops.functools import lru_cache | |
| BACKEND_CHECK_MAP = { | |
| "natten": natten_attention_check, | |
| "flash2": flash2_attention_check, | |
| "flash3": flash3_attention_check, | |
| } | |
| BACKEND_MULTI_DIM_CHECK_MAP = { | |
| "natten": natten_multi_dim_attention_check, | |
| } | |
| def is_backend_compatible( | |
| backend: str, | |
| query_shape: torch.Size, | |
| key_shape: torch.Size, | |
| value_shape: torch.Size, | |
| dtype: torch.dtype, | |
| device: torch.device, | |
| requires_grad: bool, | |
| is_causal: bool, | |
| causal_type: CausalType | None, | |
| is_varlen: bool, | |
| deterministic: bool = False, | |
| raise_error: bool = False, | |
| ) -> bool: | |
| """ | |
| Input validation function a specified backend. | |
| Runs the common and backend-specific checks. Returns False if any checks fail, otherwise True. | |
| Parameters: | |
| backend (str): selected backend. | |
| query_shape (torch.Size): Shape of 4-D query tensor (`[batch, seqlen, heads, head_dim]`). | |
| key_shape (torch.Size): Shape of 4-D key tensor (`[batch, seqlen_kv, heads_kv, head_dim]`). | |
| value_shape (torch.Size): Shape of 4-D value tensor (`[batch, seqlen_kv, heads_kv, head_dim_v]`). | |
| dtype (torch.dtype): Data type of tensors. | |
| device (torch.device): Device of tensors. | |
| requires_grad (bool): Whether tensors require gradients (training vs inference). | |
| is_causal (bool): whether or not causal masking is enabled. | |
| causal_type (CausalType): causal masking mode. Choices: `CausalType.TopLeft`, | |
| `CausalType.BottomRight`. Required when `is_causal = True`. | |
| is_varlen (bool): whether or not a variable length (varlen) use case. Must be inferred | |
| beforehand based on arguments such as seqlens_{Q,KV} or cumulative_seqlen_{Q,KV} being | |
| passed. | |
| deterministic (bool): Deterministic backward pass required. | |
| raise_error (bool): whether to raise an error if any checks fail or no backend is selected, | |
| instead of just returning False. Default is False. | |
| Returns: | |
| success (bool): whether use case is compatible with the backend. | |
| """ | |
| if backend is None: | |
| raise ValueError("Cannot pass None backend to is_backend_compatible.") | |
| if backend not in BACKEND_CHECK_MAP: | |
| raise ValueError(f"Unrecognized backend name {backend}.") | |
| return BACKEND_CHECK_MAP[backend]( | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| is_causal=is_causal, | |
| causal_type=causal_type, | |
| is_varlen=is_varlen, | |
| deterministic=deterministic, | |
| raise_error=raise_error, | |
| ) | |
| def get_backend_list(arch_tag: int) -> list[str]: | |
| """ | |
| Returns list of supported backends according to arch tag (attention.utils.get_arch_tag). | |
| Backends are ordered based on their known performance levels, so that the best-performing | |
| compatible backend is selected. | |
| The returned list can be filtered via environment variable. | |
| See `filter_attention_backends` for details. | |
| Parameters: | |
| arch_tag (int): Arch tag for the current CUDA device. Example: 80 for A100, 90 for H100. | |
| Returns: | |
| backend_list (list[str]): a list of backend names (string). Empty if device is not supported. | |
| """ | |
| if arch_tag < 75: | |
| log.debug(f"Minimum architecture supported for Attention is 75, got {arch_tag=}.") | |
| return [] | |
| default_backends = [] | |
| if arch_tag == 90: | |
| default_backends = [ | |
| "flash3", | |
| "natten", | |
| "flash2", | |
| ] | |
| elif arch_tag in [100, 103]: | |
| default_backends = [ | |
| "natten", | |
| "flash2", | |
| ] | |
| elif arch_tag >= 80: | |
| default_backends = [ | |
| "flash2", | |
| "natten", | |
| ] | |
| else: | |
| default_backends = ["natten"] | |
| # Apply environment variable filtering | |
| return filter_attention_backends(default_backends) | |
| def choose_backend( | |
| query_shape: torch.Size, | |
| key_shape: torch.Size, | |
| value_shape: torch.Size, | |
| dtype: torch.dtype, | |
| device: torch.device, | |
| requires_grad: bool, | |
| is_causal: bool, | |
| causal_type: CausalType | None, | |
| is_varlen: bool, | |
| deterministic: bool = False, | |
| backend: str | None = None, | |
| raise_error: bool = True, | |
| ) -> str | None: | |
| """ | |
| Selects a compatible backend, unless one is already selected, which runs its corresponding | |
| checks. | |
| Parameters: | |
| query_shape (torch.Size): Shape of 4-D query tensor (`[batch, seqlen, heads, head_dim]`). | |
| key_shape (torch.Size): Shape of 4-D key tensor (`[batch, seqlen_kv, heads_kv, head_dim]`). | |
| value_shape (torch.Size): Shape of 4-D value tensor (`[batch, seqlen_kv, heads_kv, head_dim_v]`). | |
| dtype (torch.dtype): Data type of tensors. | |
| device (torch.device): Device of tensors. | |
| requires_grad (bool): Whether tensors require gradients (training vs inference). | |
| is_causal (bool): whether or not causal masking is enabled. | |
| causal_type (CausalType): causal masking mode. Choices: `CausalType.TopLeft`, | |
| `CausalType.BottomRight`. Required when `is_causal = True`. | |
| is_varlen (bool): whether or not a variable length (varlen) use case. Must be inferred | |
| beforehand based on arguments such as seqlens_{Q,KV} or cumulative_seqlen_{Q,KV} being | |
| passed. | |
| deterministic (bool): Deterministic backward pass required. | |
| backend (str | None): selected backend, if any. | |
| raise_error (bool): whether to raise an error if any checks fail or no backend is selected, | |
| instead of just returning False. Default is **True**. | |
| Returns: | |
| backend (str | None): selected backend, or None if no backends are compatible. | |
| """ | |
| if backend is not None: | |
| if is_backend_compatible( | |
| backend=backend, | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| is_causal=is_causal, | |
| causal_type=causal_type, | |
| is_varlen=is_varlen, | |
| deterministic=deterministic, | |
| raise_error=raise_error, | |
| ): | |
| return backend | |
| return None | |
| arch_tag = get_arch_tag(device) | |
| backend_list = get_backend_list(arch_tag) | |
| for backend in backend_list: | |
| if is_backend_compatible( | |
| backend=backend, | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| is_causal=is_causal, | |
| causal_type=causal_type, | |
| is_varlen=is_varlen, | |
| deterministic=deterministic, | |
| raise_error=False, | |
| ): | |
| return backend | |
| if not raise_error: | |
| return None | |
| raise ValueError( | |
| "Could not find a compatible Attention backend for this use case / device. " | |
| "Try running with debug logs to find out why." | |
| ) | |
| def is_multi_dim_backend_compatible( | |
| backend: str, | |
| query_shape: torch.Size, | |
| key_shape: torch.Size, | |
| value_shape: torch.Size, | |
| dtype: torch.dtype, | |
| device: torch.device, | |
| requires_grad: bool, | |
| deterministic: bool = False, | |
| raise_error: bool = False, | |
| ) -> bool: | |
| """ | |
| Input validation function a specified multi-dimensional backend. | |
| Runs the common and backend-specific checks. Returns False if any checks fail, otherwise True. | |
| Parameters: | |
| backend (str): selected backend. | |
| query_shape (torch.Size): Shape of 4-D, 5-D, or 6-D query tensor (`[batch, *token_layout_shape, heads, head_dim]`). | |
| key_shape (torch.Size): Shape of 4-D, 5-D, or 6-D key tensor (`[batch, *token_layout_shape, heads_kv, head_dim]`). | |
| value_shape (torch.Size): Shape of 4-D, 5-D, or 6-D value tensor (`[batch, *token_layout_shape, heads_kv, head_dim_v]`). | |
| dtype (torch.dtype): Data type of tensors. | |
| device (torch.device): Device of tensors. | |
| requires_grad (bool): Whether tensors require gradients (training vs inference). | |
| deterministic (bool): Deterministic backward pass required. | |
| raise_error (bool): whether to raise an error if any checks fail or no backend is selected, | |
| instead of just returning False. Default is False. | |
| Returns: | |
| success (bool): whether use case is compatible with the backend. | |
| """ | |
| if backend is None: | |
| raise ValueError("Cannot pass None backend to is_backend_compatible.") | |
| if backend not in BACKEND_MULTI_DIM_CHECK_MAP: | |
| raise ValueError(f"Unrecognized backend name {backend}.") | |
| return BACKEND_MULTI_DIM_CHECK_MAP[backend]( | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| deterministic=deterministic, | |
| raise_error=raise_error, | |
| ) | |
| def get_multi_dim_backend_list(arch_tag: int) -> list[str]: | |
| """ | |
| Returns list of supported multi-dimensional backends according to arch tag (attention.utils.get_arch_tag). | |
| Backends are ordered based on their known performance levels, so that the best-performing | |
| compatible backend is selected. | |
| The returned list can be filtered via environment variable. | |
| See `filter_multi_dim_attention_backends` for details. | |
| Parameters: | |
| arch_tag (int): Arch tag for the current CUDA device. Example: 80 for A100, 90 for H100. | |
| Returns: | |
| backend_list (list[str]): a list of backend names (string). Empty if device is not supported. | |
| """ | |
| if arch_tag < 75: | |
| log.debug(f"Minimum architecture supported for Multi-Dimensional Attention is 75, got {arch_tag=}.") | |
| return [] | |
| # NATTEN is the only supported backend for now | |
| default_backends = ["natten"] | |
| # Apply environment variable filtering | |
| return filter_multi_dim_attention_backends(default_backends) | |
| def choose_multi_dim_backend( | |
| query_shape: torch.Size, | |
| key_shape: torch.Size, | |
| value_shape: torch.Size, | |
| dtype: torch.dtype, | |
| device: torch.device, | |
| requires_grad: bool, | |
| deterministic: bool = False, | |
| backend: str | None = None, | |
| ) -> str: | |
| """ | |
| Selects a compatible multi-dimensional backend, unless one is already selected, which runs its | |
| corresponding checks. | |
| Parameters: | |
| query_shape (torch.Size): Shape of 4-D, 5-D, or 6-D query tensor (`[batch, *token_layout_shape, heads, head_dim]`). | |
| key_shape (torch.Size): Shape of 4-D, 5-D, or 6-D key tensor (`[batch, *token_layout_shape, heads_kv, head_dim]`). | |
| value_shape (torch.Size): Shape of 4-D, 5-D, or 6-D value tensor (`[batch, *token_layout_shape, heads_kv, head_dim_v]`). | |
| dtype (torch.dtype): Data type of tensors. | |
| device (torch.device): Device of tensors. | |
| requires_grad (bool): Whether tensors require gradients (training vs inference). | |
| deterministic (bool): Deterministic backward pass required. | |
| backend (str | None): selected backend, if any. | |
| Returns: | |
| backend (str): selected backend. | |
| """ | |
| if backend is not None: | |
| assert is_multi_dim_backend_compatible( | |
| backend=backend, | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| deterministic=deterministic, | |
| raise_error=True, | |
| ) | |
| return backend | |
| arch_tag = get_arch_tag(device) | |
| backend_list = get_multi_dim_backend_list(arch_tag) | |
| for backend in backend_list: | |
| if is_multi_dim_backend_compatible( | |
| backend=backend, | |
| query_shape=query_shape, | |
| key_shape=key_shape, | |
| value_shape=value_shape, | |
| dtype=dtype, | |
| device=device, | |
| requires_grad=requires_grad, | |
| deterministic=deterministic, | |
| raise_error=False, | |
| ): | |
| return backend | |
| raise ValueError( | |
| "Could not find a compatible Multi-Dimensional Attention backend for this use case / device. " | |
| "Try running with debug logs to find out why." | |
| ) | |