RiNALMo-giga / modeling_rinalmo.py
Taykhoom's picture
Upload folder using huggingface_hub
6cdb768 verified
Raw
History Blame Contribute Delete
13.7 kB
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import PreTrainedModel
from transformers.modeling_outputs import BaseModelOutput, MaskedLMOutput
try:
from .configuration_rinalmo import RiNALMoConfig
except ImportError:
from configuration_rinalmo import RiNALMoConfig
def _rotate_half(x):
x1, x2 = x.chunk(2, dim=-1)
return torch.cat((-x2, x1), dim=-1)
def _apply_rotary_pos_emb(q, k, cos, sin):
cos = cos.to(q.dtype)
sin = sin.to(q.dtype)
return (q * cos) + (_rotate_half(q) * sin), (k * cos) + (_rotate_half(k) * sin)
class RotaryPositionEmbedding(nn.Module):
def __init__(self, dim: int, base: int = 10000):
super().__init__()
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer("inv_freq", inv_freq)
self._seq_len_cached = None
self._cos_cached = None
self._sin_cached = None
def _update_cache(self, seq_len: int, device, dtype):
if seq_len != self._seq_len_cached:
self._seq_len_cached = seq_len
t = torch.arange(seq_len, device=device).type_as(self.inv_freq)
freqs = torch.einsum("i,j->ij", t, self.inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
self._cos_cached = emb.cos()[None, None, :, :]
self._sin_cached = emb.sin()[None, None, :, :]
def forward(self, q, k):
self._update_cache(q.shape[-2], q.device, q.dtype)
return _apply_rotary_pos_emb(q, k, self._cos_cached, self._sin_cached)
class RiNALMoAttention(nn.Module):
def __init__(self, config: RiNALMoConfig):
super().__init__()
self.embed_dim = config.embed_dim
self.num_heads = config.num_heads
self.head_dim = config.embed_dim // config.num_heads
self.qkv_proj = nn.Linear(config.embed_dim, 3 * config.embed_dim, bias=False)
self.out_proj = nn.Linear(config.embed_dim, config.embed_dim, bias=False)
self.attn_dropout = nn.Dropout(p=config.attention_dropout)
if config.use_rot_emb:
self.rotary_emb = RotaryPositionEmbedding(self.head_dim, base=config.rope_base)
else:
self.rotary_emb = None
def forward(self, x, key_padding_mask=None, output_attentions=False):
B, T, _ = x.shape
qkv = self.qkv_proj(x)
q, k, v = qkv.chunk(3, dim=-1)
q = q.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
k = k.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
v = v.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
if self.rotary_emb is not None:
q, k = self.rotary_emb(q, k)
scale = math.sqrt(self.head_dim)
attn = torch.matmul(q, k.transpose(-1, -2)) / scale
if key_padding_mask is not None:
attn = attn.masked_fill(key_padding_mask.unsqueeze(1).unsqueeze(2), float("-inf"))
attn = attn.softmax(dim=-1)
attn_weights = attn if output_attentions else None
attn = self.attn_dropout(attn)
out = torch.matmul(attn, v)
out = out.transpose(1, 2).contiguous().view(B, T, self.embed_dim)
out = self.out_proj(out)
return out, attn_weights
class RiNALMoSdpaAttention(RiNALMoAttention):
def forward(self, x, key_padding_mask=None, output_attentions=False):
if output_attentions:
return super().forward(x, key_padding_mask, output_attentions=True)
B, T, _ = x.shape
qkv = self.qkv_proj(x)
q, k, v = qkv.chunk(3, dim=-1)
q = q.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
k = k.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
v = v.view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
if self.rotary_emb is not None:
q, k = self.rotary_emb(q, k)
attn_mask = None
if key_padding_mask is not None:
attn_mask = torch.zeros(B, 1, 1, T, dtype=q.dtype, device=q.device)
attn_mask = attn_mask.masked_fill(key_padding_mask.unsqueeze(1).unsqueeze(2), float("-inf"))
out = F.scaled_dot_product_attention(q, k, v, attn_mask=attn_mask, dropout_p=0.0)
out = out.transpose(1, 2).contiguous().view(B, T, self.embed_dim)
out = self.out_proj(out)
return out, None
class RiNALMoFlashAttention2(RiNALMoAttention):
def forward(self, x, key_padding_mask=None, output_attentions=False):
if output_attentions:
return super().forward(x, key_padding_mask, output_attentions=True)
try:
from flash_attn import flash_attn_func, flash_attn_varlen_func
from flash_attn.bert_padding import pad_input, unpad_input
except ImportError as e:
raise ImportError(
"flash_attn is required for attn_implementation='flash_attention_2'. "
"Install with: pip install flash-attn --no-build-isolation"
) from e
B, T, _ = x.shape
qkv = self.qkv_proj(x)
q, k, v = qkv.chunk(3, dim=-1)
q = q.view(B, T, self.num_heads, self.head_dim)
k = k.view(B, T, self.num_heads, self.head_dim)
v = v.view(B, T, self.num_heads, self.head_dim)
if self.rotary_emb is not None:
q_t = q.transpose(1, 2)
k_t = k.transpose(1, 2)
q_t, k_t = self.rotary_emb(q_t, k_t)
q = q_t.transpose(1, 2)
k = k_t.transpose(1, 2)
orig_dtype = q.dtype
if q.dtype not in (torch.float16, torch.bfloat16):
q = q.to(torch.bfloat16)
k = k.to(torch.bfloat16)
v = v.to(torch.bfloat16)
if key_padding_mask is not None and key_padding_mask.any():
attend_mask = ~key_padding_mask
q_unpad, indices, cu_seqlens, max_seqlen, _ = unpad_input(q, attend_mask)
k_unpad, *_ = unpad_input(k, attend_mask)
v_unpad, *_ = unpad_input(v, attend_mask)
out_unpad = flash_attn_varlen_func(
q_unpad, k_unpad, v_unpad,
cu_seqlens_q=cu_seqlens, cu_seqlens_k=cu_seqlens,
max_seqlen_q=max_seqlen, max_seqlen_k=max_seqlen,
causal=False,
)
out = pad_input(out_unpad.view(-1, self.embed_dim), indices, B, T)
else:
out = flash_attn_func(q, k, v, causal=False)
out = out.view(B, T, self.embed_dim)
out = out.to(orig_dtype)
out = self.out_proj(out)
return out, None
RINALMO_ATTENTION_CLASSES = {
"eager": RiNALMoAttention,
"sdpa": RiNALMoSdpaAttention,
"flash_attention_2": RiNALMoFlashAttention2,
}
class RiNALMoSwiGLU(nn.Module):
def __init__(self, embed_dim: int, ffn_dim: int):
super().__init__()
self.linear = nn.Linear(embed_dim, ffn_dim, bias=True)
self.linear_gate = nn.Linear(embed_dim, ffn_dim, bias=True)
self.beta = nn.Parameter(torch.ones(1))
def forward(self, x):
gate = self.linear(x)
swish = gate * torch.sigmoid(self.beta * gate)
return swish * self.linear_gate(x)
class TokenDropout(nn.Module):
def __init__(self, active: bool, mask_ratio: float, mask_tkn_prob: float,
mask_idx: int, padding_idx: int):
super().__init__()
self.active = active
self.mask_ratio_train = mask_ratio * mask_tkn_prob
self.mask_idx = mask_idx
self.padding_idx = padding_idx
def forward(self, x, tokens):
if not self.active:
return x
pad_mask = tokens.eq(self.padding_idx)
src_lens = (~pad_mask).sum(dim=-1).to(x.dtype)
x = torch.where((tokens == self.mask_idx).unsqueeze(-1), torch.zeros_like(x), x)
mask_ratio_obs = (tokens == self.mask_idx).sum(dim=-1).to(x.dtype) / src_lens
scale = (1.0 - self.mask_ratio_train) / (1.0 - mask_ratio_obs)
x = x * scale[:, None, None]
return x
class RiNALMoLayer(nn.Module):
def __init__(self, config: RiNALMoConfig):
super().__init__()
ffn_dim = int(2 / 3 * config.transition_factor * config.embed_dim)
attn_cls = RINALMO_ATTENTION_CLASSES[getattr(config, "_attn_implementation", "eager")]
self.attn_layer_norm = nn.LayerNorm(config.embed_dim)
self.attn = attn_cls(config)
self.out_layer_norm = nn.LayerNorm(config.embed_dim)
self.ffn = RiNALMoSwiGLU(config.embed_dim, ffn_dim)
self.ffn_dropout = nn.Dropout(p=config.transition_dropout)
self.ffn_down = nn.Linear(ffn_dim, config.embed_dim, bias=True)
self.residual_dropout_1 = nn.Dropout(p=config.residual_dropout)
self.residual_dropout_2 = nn.Dropout(p=config.residual_dropout)
def forward(self, x, key_padding_mask=None, output_attentions=False):
x = self.attn_layer_norm(x)
attn_out, attn_weights = self.attn(x, key_padding_mask=key_padding_mask,
output_attentions=output_attentions)
x = x + self.residual_dropout_1(attn_out)
residual = x
x = self.out_layer_norm(x)
x = residual + self.residual_dropout_2(self.ffn_down(self.ffn_dropout(self.ffn(x))))
return x, attn_weights
class RiNALMoPreTrainedModel(PreTrainedModel):
config_class = RiNALMoConfig
base_model_prefix = "model"
_supports_sdpa = True
_supports_flash_attn_2 = True
def _init_weights(self, module):
if isinstance(module, (nn.Linear, nn.Embedding)):
module.weight.data.normal_(mean=0.0, std=0.02)
if isinstance(module, nn.Linear) and module.bias is not None:
module.bias.data.zero_()
elif isinstance(module, nn.LayerNorm):
module.bias.data.zero_()
module.weight.data.fill_(1.0)
class RiNALMoModel(RiNALMoPreTrainedModel):
def __init__(self, config: RiNALMoConfig):
super().__init__(config)
self.embedding = nn.Embedding(config.vocab_size, config.embed_dim, padding_idx=config.padding_idx)
self.token_dropout = TokenDropout(
active=config.token_dropout_active,
mask_ratio=config.mask_ratio,
mask_tkn_prob=config.mask_tkn_prob,
mask_idx=config.mask_idx,
padding_idx=config.padding_idx,
)
self.layers = nn.ModuleList([RiNALMoLayer(config) for _ in range(config.num_layers)])
self.final_layer_norm = nn.LayerNorm(config.embed_dim)
self.post_init()
def forward(
self,
input_ids,
attention_mask=None,
output_hidden_states=None,
output_attentions=None,
return_dict=None,
):
output_hidden_states = output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
if attention_mask is not None:
key_padding_mask = attention_mask.eq(0)
else:
key_padding_mask = input_ids.eq(self.config.padding_idx)
x = self.embedding(input_ids)
x = self.token_dropout(x, input_ids)
all_hidden_states = []
all_attentions = []
if output_hidden_states:
all_hidden_states.append(x)
for layer in self.layers:
x, attn_weights = layer(x, key_padding_mask=key_padding_mask,
output_attentions=output_attentions)
if output_hidden_states:
all_hidden_states.append(x)
if output_attentions:
all_attentions.append(attn_weights)
x = self.final_layer_norm(x)
return BaseModelOutput(
last_hidden_state=x,
hidden_states=tuple(all_hidden_states) if output_hidden_states else None,
attentions=tuple(all_attentions) if output_attentions else None,
)
class RiNALMoForMaskedLM(RiNALMoPreTrainedModel):
def __init__(self, config: RiNALMoConfig):
super().__init__(config)
self.model = RiNALMoModel(config)
self.lm_head = RiNALMoLMHead(config)
self.post_init()
def forward(
self,
input_ids,
attention_mask=None,
labels=None,
output_hidden_states=None,
output_attentions=None,
return_dict=None,
):
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
out = self.model(input_ids, attention_mask=attention_mask,
output_hidden_states=output_hidden_states,
output_attentions=output_attentions, return_dict=return_dict)
logits = self.lm_head(out.last_hidden_state)
loss = None
if labels is not None:
loss = F.cross_entropy(logits.view(-1, self.config.vocab_size),
labels.view(-1), ignore_index=-100)
return MaskedLMOutput(loss=loss, logits=logits,
hidden_states=out.hidden_states,
attentions=out.attentions)
class RiNALMoLMHead(nn.Module):
def __init__(self, config: RiNALMoConfig):
super().__init__()
self.linear1 = nn.Linear(config.embed_dim, config.embed_dim)
self.layer_norm = nn.LayerNorm(config.embed_dim)
self.linear2 = nn.Linear(config.embed_dim, config.vocab_size)
def forward(self, x):
x = self.linear1(x)
x = F.gelu(x)
x = self.layer_norm(x)
x = self.linear2(x)
return x