sdpa_paged.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import torch
  2. from ..generation.continuous_batching.cache import PagedAttentionCache
  3. def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
  4. """
  5. This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
  6. num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
  7. """
  8. batch, num_key_value_heads, slen, head_dim = hidden_states.shape
  9. if n_rep == 1:
  10. return hidden_states
  11. hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
  12. return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
  13. def sdpa_attention_paged_forward(
  14. module: torch.nn.Module,
  15. query: torch.Tensor,
  16. key: torch.Tensor,
  17. value: torch.Tensor,
  18. attention_mask: torch.Tensor | None,
  19. dropout: float = 0.0,
  20. scaling: float | None = None,
  21. **kwargs,
  22. ) -> tuple[torch.Tensor, None]:
  23. # Add KV cache to the key and value tensors
  24. cache: PagedAttentionCache | None = kwargs.pop("cache", None)
  25. if cache is not None:
  26. # This changes the shape of k and v from [1, num_kv_heads, seqlen_kv, head_dim] to [-1, num_kv_heads, head_dim]
  27. key, value = cache.update(
  28. key_states=key,
  29. value_states=value,
  30. layer_idx=module.layer_idx,
  31. read_index=kwargs["read_index"],
  32. write_index=kwargs["write_index"],
  33. )
  34. key = key.transpose(0, 1).unsqueeze(0)
  35. value = value.transpose(0, 1).unsqueeze(0)
  36. # Repeat the key and value tensors for each group of key-value heads
  37. if hasattr(module, "num_key_value_groups"):
  38. key = repeat_kv(key, module.num_key_value_groups)
  39. value = repeat_kv(value, module.num_key_value_groups)
  40. # Get the right causal mask for the current layer
  41. causal_mask = attention_mask
  42. # Run the actual attention
  43. query = query.contiguous()
  44. key = key.contiguous()
  45. value = value.contiguous()
  46. attn_output = torch.nn.functional.scaled_dot_product_attention(
  47. query,
  48. key,
  49. value,
  50. attn_mask=causal_mask,
  51. dropout_p=dropout,
  52. scale=scaling,
  53. # Packed sequence format is used for input, so that it can never be causal.
  54. is_causal=False,
  55. )
  56. attn_output = attn_output.transpose(1, 2).contiguous()
  57. return attn_output, None