|
|
from typing import Optional |
|
|
|
|
|
import torch |
|
|
|
|
|
from ..utils import is_torch_npu_available, is_torch_xpu_available, logging |
|
|
from ..utils.import_utils import is_torch_greater_or_equal |
|
|
|
|
|
|
|
|
logger = logging.get_logger(__name__) |
|
|
|
|
|
|
|
|
_is_torch_greater_or_equal_than_2_5 = is_torch_greater_or_equal("2.5", accept_dev=True) |
|
|
_is_torch_greater_or_equal_than_2_8 = is_torch_greater_or_equal("2.8", accept_dev=True) |
|
|
_is_torch_xpu_available = is_torch_xpu_available() |
|
|
_is_torch_npu_available = is_torch_npu_available() |
|
|
|
|
|
|
|
|
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor: |
|
|
""" |
|
|
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch, |
|
|
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim) |
|
|
""" |
|
|
batch, num_key_value_heads, slen, head_dim = hidden_states.shape |
|
|
if n_rep == 1: |
|
|
return hidden_states |
|
|
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim) |
|
|
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim) |
|
|
|
|
|
|
|
|
def use_gqa_in_sdpa(attention_mask: Optional[torch.Tensor], key: torch.Tensor) -> bool: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if _is_torch_xpu_available: |
|
|
return _is_torch_greater_or_equal_than_2_8 and not isinstance(key, torch.fx.Proxy) |
|
|
if _is_torch_npu_available: |
|
|
return False |
|
|
return _is_torch_greater_or_equal_than_2_5 and attention_mask is None and not isinstance(key, torch.fx.Proxy) |
|
|
|
|
|
|
|
|
def sdpa_attention_forward( |
|
|
module: torch.nn.Module, |
|
|
query: torch.Tensor, |
|
|
key: torch.Tensor, |
|
|
value: torch.Tensor, |
|
|
attention_mask: Optional[torch.Tensor], |
|
|
dropout: float = 0.0, |
|
|
scaling: Optional[float] = None, |
|
|
is_causal: Optional[bool] = None, |
|
|
**kwargs, |
|
|
) -> tuple[torch.Tensor, None]: |
|
|
if kwargs.get("output_attentions", False) or kwargs.get("head_mask") is not None: |
|
|
logger.warning_once( |
|
|
"`sdpa` attention does not support `output_attentions=True` or `head_mask`." |
|
|
" Please set your attention to `eager` if you want any of these features." |
|
|
) |
|
|
sdpa_kwargs = {} |
|
|
if hasattr(module, "num_key_value_groups"): |
|
|
if not use_gqa_in_sdpa(attention_mask, key): |
|
|
key = repeat_kv(key, module.num_key_value_groups) |
|
|
value = repeat_kv(value, module.num_key_value_groups) |
|
|
else: |
|
|
sdpa_kwargs = {"enable_gqa": True} |
|
|
|
|
|
if attention_mask is not None and attention_mask.ndim == 4: |
|
|
attention_mask = attention_mask[:, :, :, : key.shape[-2]] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if is_causal is None: |
|
|
|
|
|
|
|
|
is_causal = query.shape[2] > 1 and attention_mask is None and getattr(module, "is_causal", True) |
|
|
|
|
|
|
|
|
|
|
|
if torch.jit.is_tracing() and isinstance(is_causal, torch.Tensor): |
|
|
is_causal = is_causal.item() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if _is_torch_npu_available: |
|
|
if attention_mask is not None and attention_mask.dtype != torch.bool: |
|
|
|
|
|
attention_mask = torch.logical_not(attention_mask.bool()).to(query.device) |
|
|
|
|
|
attn_output = torch.nn.functional.scaled_dot_product_attention( |
|
|
query, |
|
|
key, |
|
|
value, |
|
|
attn_mask=attention_mask, |
|
|
dropout_p=dropout, |
|
|
scale=scaling, |
|
|
is_causal=is_causal, |
|
|
**sdpa_kwargs, |
|
|
) |
|
|
attn_output = attn_output.transpose(1, 2).contiguous() |
|
|
|
|
|
return attn_output, None |
|
|
|