dplotnikov's picture
Upload StrataBERT diagnostic checkpoint
c30089a verified
Raw
History Blame Contribute Delete
4.14 kB
"""Attention layers used by the correctness-first scaffold."""
from __future__ import annotations
import math
import torch
from torch import nn
from .padding import masked_hidden
class RMSNorm(nn.Module):
def __init__(self, hidden_size: int, eps: float = 1e-5):
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.eps = eps
def forward(self, x: torch.Tensor) -> torch.Tensor:
variance = x.pow(2).mean(dim=-1, keepdim=True)
return x * torch.rsqrt(variance + self.eps) * self.weight
class FeedForward(nn.Module):
def __init__(self, hidden_size: int, intermediate_size: int, dropout: float, activation: str = "gelu"):
super().__init__()
self.activation_name = activation
if activation == "geglu":
self.in_proj = nn.Linear(hidden_size, intermediate_size * 2)
self.out_proj = nn.Linear(intermediate_size, hidden_size)
else:
self.in_proj = nn.Linear(hidden_size, intermediate_size)
self.out_proj = nn.Linear(intermediate_size, hidden_size)
self.dropout = nn.Dropout(dropout)
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = self.in_proj(x)
if self.activation_name == "geglu":
value, gate = x.chunk(2, dim=-1)
x = value * torch.nn.functional.gelu(gate)
else:
x = torch.nn.functional.gelu(x)
return self.out_proj(self.dropout(x))
class StrataBertAttentionLayer(nn.Module):
def __init__(self, config, layer_type: str):
super().__init__()
if config.hidden_size % config.num_attention_heads != 0:
raise ValueError("hidden_size must be divisible by num_attention_heads")
self.layer_type = layer_type
self.num_heads = config.num_attention_heads
self.head_dim = config.hidden_size // config.num_attention_heads
self.window = config.local_attention_window
self.norm = RMSNorm(config.hidden_size, config.norm_eps)
self.qkv = nn.Linear(config.hidden_size, config.hidden_size * 3)
self.out_proj = nn.Linear(config.hidden_size, config.hidden_size)
self.dropout = nn.Dropout(config.attention_dropout)
self.ffn_norm = RMSNorm(config.hidden_size, config.norm_eps)
self.ffn = FeedForward(
config.hidden_size,
config.intermediate_size,
config.hidden_dropout,
config.hidden_activation,
)
def forward(
self,
hidden_states: torch.Tensor,
attention_mask: torch.Tensor,
segment_ids: torch.Tensor | None = None,
) -> torch.Tensor:
residual = hidden_states
x = self.norm(hidden_states)
batch, length, hidden = x.shape
qkv = self.qkv(x).view(batch, length, 3, self.num_heads, self.head_dim)
q, k, v = qkv.unbind(dim=2)
q = q.transpose(1, 2)
k = k.transpose(1, 2)
v = v.transpose(1, 2)
scores = torch.matmul(q, k.transpose(-1, -2)) / math.sqrt(self.head_dim)
key_mask = attention_mask[:, None, None, :]
query_mask = attention_mask[:, None, :, None]
scores = scores.masked_fill(~key_mask, -1.0e4)
if segment_ids is not None:
same_segment = segment_ids[:, None, :, None] == segment_ids[:, None, None, :]
scores = scores.masked_fill(~same_segment, -1.0e4)
if self.layer_type == "local_attention":
idx = torch.arange(length, device=x.device)
local = (idx[None, :] - idx[:, None]).abs() <= self.window
scores = scores.masked_fill(~local[None, None, :, :], -1.0e4)
probs = torch.softmax(scores, dim=-1)
probs = self.dropout(probs) * query_mask.to(probs.dtype)
attended = torch.matmul(probs, v).transpose(1, 2).contiguous().view(batch, length, hidden)
hidden_states = residual + self.out_proj(attended)
hidden_states = masked_hidden(hidden_states, attention_mask)
hidden_states = hidden_states + self.ffn(self.ffn_norm(hidden_states))
return masked_hidden(hidden_states, attention_mask)