jasonfan's picture
2026-03-19
3b2d368 verified
Raw
History Blame Contribute Delete
2.52 kB
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