VMiniBert / modeling_vminibert.py
vprojectx's picture
Upload folder using huggingface_hub
b74c422 verified
Raw History Blame Contribute Delete
7.61 kB
import math
from typing import Optional, Tuple, Union
import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import PreTrainedModel
from transformers.modeling_outputs import MaskedLMOutput
from .configuration_vminibert import VMiniBertConfig
class RMSNorm(nn.Module):
def __init__(self, dim: int, eps: float = 1e-6):
super().__init__()
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
def forward(self, x: torch.Tensor) -> torch.Tensor:
norm = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
return norm * self.weight
class RotaryEmbedding(nn.Module):
def __init__(self, dim: int, max_seq_len: int = 512, base: float = 10000.0):
super().__init__()
self.dim = dim
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer("inv_freq", inv_freq, persistent=False)
def forward(self, x: torch.Tensor, seq_len: int):
t = torch.arange(seq_len, device=x.device, dtype=self.inv_freq.dtype)
freqs = torch.einsum("i,j->ij", t, self.inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos()[None, None, :, :]
sin = emb.sin()[None, None, :, :]
return cos, sin
def rotate_half(x: torch.Tensor) -> torch.Tensor:
x1, x2 = x[..., :x.shape[-1] // 2], x[..., x.shape[-1] // 2:]
return torch.cat((-x2, x1), dim=-1)
def apply_rotary_pos_emb(q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor):
q_rot = (q * cos) + (rotate_half(q) * sin)
k_rot = (k * cos) + (rotate_half(k) * sin)
return q_rot, k_rot
class VectorizedMultiHeadAttention(nn.Module):
def __init__(self, config: VMiniBertConfig):
super().__init__()
self.num_heads = config.num_attention_heads
self.head_dim = config.hidden_size // config.num_attention_heads
self.q_proj = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
self.k_proj = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
self.v_proj = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
self.out_proj = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
self.dropout = nn.Dropout(config.attention_probs_dropout_prob)
self.rotary_emb = RotaryEmbedding(self.head_dim, max_seq_len=config.max_position_embeddings)
def forward(self, x: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor:
B, S, H = x.shape
Q = self.q_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2)
K = self.k_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2)
V = self.v_proj(x).view(B, S, self.num_heads, self.head_dim).transpose(1, 2)
cos, sin = self.rotary_emb(Q, S)
Q, K = apply_rotary_pos_emb(Q, K, cos, sin)
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.head_dim)
if mask is not None:
scores = scores.masked_fill(mask == 0, -1e4)
attn_weights = self.dropout(F.softmax(scores, dim=-1))
out = torch.matmul(attn_weights, V).transpose(1, 2).contiguous().view(B, S, H)
return self.out_proj(out)
class GeGLU(nn.Module):
def __init__(self, config: VMiniBertConfig):
super().__init__()
self.w_gate = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
self.w_up = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
self.w_down = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
self.dropout = nn.Dropout(config.hidden_dropout_prob)
def forward(self, x: torch.Tensor) -> torch.Tensor:
gate = F.gelu(self.w_gate(x))
up = self.w_up(x)
hidden = self.dropout(gate * up)
return self.w_down(hidden)
class EncoderLayer(nn.Module):
def __init__(self, config: VMiniBertConfig):
super().__init__()
self.norm1 = RMSNorm(config.hidden_size, eps=config.layer_norm_eps)
self.mha = VectorizedMultiHeadAttention(config)
self.norm2 = RMSNorm(config.hidden_size, eps=config.layer_norm_eps)
self.ffn = GeGLU(config)
self.dropout = nn.Dropout(config.hidden_dropout_prob)
def forward(self, x: torch.Tensor, mask: Optional[torch.Tensor] = None) -> torch.Tensor:
normed_x = self.norm1(x)
attn_out = self.mha(normed_x, mask=mask)
x = x + self.dropout(attn_out)
normed_x = self.norm2(x)
ffn_out = self.ffn(normed_x)
x = x + self.dropout(ffn_out)
return x
class VMiniBertForMaskedLM(PreTrainedModel):
config_class = VMiniBertConfig
base_model_prefix = "vminibert"
_tied_weights_keys = {"mlm_head.weight": "token_embedding.weight"}
def __init__(self, config: VMiniBertConfig):
super().__init__(config)
self.config = config
self.token_embedding = nn.Embedding(config.vocab_size, config.hidden_size, padding_idx=config.pad_token_id)
self.embed_norm = RMSNorm(config.hidden_size, eps=config.layer_norm_eps)
self.dropout = nn.Dropout(config.hidden_dropout_prob)
self.layers = nn.ModuleList([EncoderLayer(config) for _ in range(config.num_hidden_layers)])
self.final_norm = RMSNorm(config.hidden_size, eps=config.layer_norm_eps)
self.transform = nn.Sequential(
nn.Linear(config.hidden_size, config.hidden_size),
nn.GELU(),
RMSNorm(config.hidden_size, eps=config.layer_norm_eps)
)
self.mlm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=True)
self.mlm_head.weight = self.token_embedding.weight
self.post_init()
def get_input_embeddings(self) -> nn.Module:
return self.token_embedding
def set_input_embeddings(self, value: nn.Module):
self.token_embedding = value
def get_output_embeddings(self) -> nn.Module:
return self.mlm_head
def set_output_embeddings(self, new_embeddings: nn.Module):
self.mlm_head = new_embeddings
def forward(
self,
input_ids: Optional[torch.Tensor] = None,
attention_mask: Optional[torch.Tensor] = None,
labels: Optional[torch.Tensor] = None,
return_dict: Optional[bool] = None,
**kwargs
) -> Union[Tuple[torch.Tensor, ...], MaskedLMOutput]:
return_dict = return_dict if return_dict is not None else True
tok_embeds = self.token_embedding(input_ids)
x = self.dropout(self.embed_norm(tok_embeds))
if attention_mask is not None:
mask = attention_mask.unsqueeze(1).unsqueeze(2)
else:
mask = (input_ids != self.config.pad_token_id).unsqueeze(1).unsqueeze(2)
for layer in self.layers:
x = layer(x, mask=mask)
x = self.final_norm(x)
x = self.transform(x)
logits = self.mlm_head(x)
loss = None
if labels is not None:
loss_fct = nn.CrossEntropyLoss(ignore_index=-100)
loss = loss_fct(logits.view(-1, self.config.vocab_size), labels.view(-1))
if not return_dict:
output = (logits,)
return ((loss,) + output) if loss is not None else output
return MaskedLMOutput(
loss=loss,
logits=logits,
hidden_states=None,
attentions=None,
)