import torch import torch.nn as nn from torchtune.modules import RotaryPositionalEmbeddings from torch.nn.attention.flex_attention import flex_attention from torch.nn.attention import sdpa_kernel, SDPBackend class Attention(nn.Module): def __init__(self, config): super().__init__() self.config = config # Linear layers... self.W_q = nn.Linear(config.embed_dim, config.hidden_dim, bias=False) self.W_k = nn.Linear(config.embed_dim, config.hidden_dim, bias=False) self.W_v = nn.Linear(config.embed_dim, config.hidden_dim, bias=True) self.W_o = nn.Linear(config.hidden_dim, config.embed_dim, bias=True) # RoPE d_k = config.hidden_dim // config.n_heads self.rotary_embeddings = RotaryPositionalEmbeddings(d_k, max_seq_len=config.max_seq_len + 10) self.drop_resid = nn.Dropout(0.1) def forward(self, x): B, S, E = x.shape H = self.config.n_heads D_h = self.config.hidden_dim // H # 1. Project and Reshape (B, S, E) -> (B, S, H, D_h) q = self.W_q(x).view(B, S, H, D_h) k = self.W_k(x).view(B, S, H, D_h) v = self.W_v(x).view(B, S, H, D_h) # 2. Apply RoPE and Transpose to (B, H, S, D_h) q = self.rotary_embeddings(q).transpose(1, 2).contiguous() k = self.rotary_embeddings(k).transpose(1, 2).contiguous() v = v.transpose(1, 2).contiguous() # V is often transposed without RoPE # 3. Custom Bidirectional Masking Function (No-op) def _score_mod(scores, b, h, i, j): # This implements bidirectional attention by applying NO mask. # All tokens are visible to all other tokens. return scores # 4. Attention with Explicit Backend Control # sdpa_kernel controls the backend used for the attention operation within the block with sdpa_kernel(SDPBackend.FLASH_ATTENTION): attn_output = flex_attention( q, k, v, score_mod=_score_mod, # <-- Apply the custom bidirectional (no-op) mask scale=None, ) # 5. Combine Heads and Project Back # (B, H, S, D_h) -> (B, S, H*D_h) attn_output = attn_output.transpose(1, 2).contiguous().view(B, S, self.config.hidden_dim) attn_output = self.W_o(attn_output) attn_output = self.drop_resid(attn_output) return attn_output