Download modeling_vminibert.py from vprojectx/VMiniBert: direct link, hf CLI and curl.
- Browser
- Download file 7.61 kB
-
https://huggingface.co/vprojectx/VMiniBert/resolve/main/modeling_vminibert.py
- Command line
-
hf download hf://vprojectx/VMiniBert/modeling_vminibert.py
-
curl -L -o modeling_vminibert.py https://huggingface.co/vprojectx/VMiniBert/resolve/main/modeling_vminibert.py
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, | |
| ) | |