| import math |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
|
|
| class RMSNorm(nn.Module): |
| def __init__(self, dim, eps=1e-6): |
| super().__init__() |
| self.weight = nn.Parameter(torch.ones(dim)) |
| self.eps = eps |
|
|
| def forward(self, x): |
| variance = x.float().pow(2).mean(-1, keepdim=True) |
| x = x * torch.rsqrt(variance + self.eps) |
| return self.weight * x |
|
|
|
|
| def rotate_half(x): |
| x1 = x[..., : x.shape[-1] // 2] |
| x2 = x[..., x.shape[-1] // 2 :] |
| return torch.cat((-x2, x1), dim=-1) |
|
|
|
|
| def apply_rope(x, cos, sin): |
| return (x * cos) + (rotate_half(x) * sin) |
|
|
|
|
| class RotaryEmbedding(nn.Module): |
| def __init__(self, head_dim, max_seq_len, base=10000.0): |
| super().__init__() |
|
|
| inv_freq = 1.0 / ( |
| base ** ( |
| torch.arange(0, head_dim, 2).float() / head_dim |
| ) |
| ) |
|
|
| self.register_buffer("inv_freq", inv_freq, persistent=False) |
|
|
| positions = torch.arange(max_seq_len).float() |
|
|
| freqs = torch.outer(positions, inv_freq) |
|
|
| emb = torch.cat((freqs, freqs), dim=-1) |
|
|
| self.register_buffer( |
| "cos_cached", |
| emb.cos()[None, None, :, :], |
| persistent=False, |
| ) |
|
|
| self.register_buffer( |
| "sin_cached", |
| emb.sin()[None, None, :, :], |
| persistent=False, |
| ) |
|
|
| def forward(self, seq_len): |
| return ( |
| self.cos_cached[:, :, :seq_len, :], |
| self.sin_cached[:, :, :seq_len, :], |
| ) |
|
|
|
|
| class SwiGLU(nn.Module): |
| def __init__(self, hidden_size, intermediate_size): |
| super().__init__() |
|
|
| self.gate_proj = nn.Linear( |
| hidden_size, |
| intermediate_size, |
| bias=False, |
| ) |
|
|
| self.up_proj = nn.Linear( |
| hidden_size, |
| intermediate_size, |
| bias=False, |
| ) |
|
|
| self.down_proj = nn.Linear( |
| intermediate_size, |
| hidden_size, |
| bias=False, |
| ) |
|
|
| def forward(self, x): |
| return self.down_proj( |
| F.silu(self.gate_proj(x)) * self.up_proj(x) |
| ) |
|
|
|
|
| class GQAttention(nn.Module): |
| def __init__( |
| self, |
| hidden_size, |
| num_heads, |
| num_kv_heads, |
| max_seq_len, |
| ): |
| super().__init__() |
|
|
| assert hidden_size % num_heads == 0 |
|
|
| self.num_heads = num_heads |
| self.num_kv_heads = num_kv_heads |
| self.head_dim = hidden_size // num_heads |
|
|
| assert num_heads % num_kv_heads == 0 |
|
|
| self.q_proj = nn.Linear( |
| hidden_size, |
| num_heads * self.head_dim, |
| bias=False, |
| ) |
|
|
| self.k_proj = nn.Linear( |
| hidden_size, |
| num_kv_heads * self.head_dim, |
| bias=False, |
| ) |
|
|
| self.v_proj = nn.Linear( |
| hidden_size, |
| num_kv_heads * self.head_dim, |
| bias=False, |
| ) |
|
|
| self.o_proj = nn.Linear( |
| hidden_size, |
| hidden_size, |
| bias=False, |
| ) |
|
|
| self.rope = RotaryEmbedding( |
| self.head_dim, |
| max_seq_len, |
| ) |
|
|
| def forward(self, x): |
| batch, seq_len, hidden = x.shape |
|
|
| q = self.q_proj(x) |
| k = self.k_proj(x) |
| v = self.v_proj(x) |
|
|
| q = q.view( |
| batch, |
| seq_len, |
| self.num_heads, |
| self.head_dim, |
| ).transpose(1, 2) |
|
|
| k = k.view( |
| batch, |
| seq_len, |
| self.num_kv_heads, |
| self.head_dim, |
| ).transpose(1, 2) |
|
|
| v = v.view( |
| batch, |
| seq_len, |
| self.num_kv_heads, |
| self.head_dim, |
| ).transpose(1, 2) |
|
|
| cos, sin = self.rope(seq_len) |
|
|
| q = apply_rope(q, cos, sin) |
| k = apply_rope(k, cos, sin) |
|
|
| |
| repeat_factor = self.num_heads // self.num_kv_heads |
|
|
| k = k.repeat_interleave( |
| repeat_factor, |
| dim=1, |
| ) |
|
|
| v = v.repeat_interleave( |
| repeat_factor, |
| dim=1, |
| ) |
|
|
| y = F.scaled_dot_product_attention( |
| q, |
| k, |
| v, |
| is_causal=True, |
| ) |
|
|
| y = y.transpose(1, 2).contiguous() |
|
|
| y = y.view( |
| batch, |
| seq_len, |
| hidden, |
| ) |
|
|
| return self.o_proj(y) |
|
|
|
|
| class TransformerBlock(nn.Module): |
| def __init__( |
| self, |
| hidden_size, |
| num_heads, |
| num_kv_heads, |
| intermediate_size, |
| max_seq_len, |
| ): |
| super().__init__() |
|
|
| self.attn_norm = RMSNorm(hidden_size) |
| self.attn = GQAttention( |
| hidden_size, |
| num_heads, |
| num_kv_heads, |
| max_seq_len, |
| ) |
|
|
| self.ffn_norm = RMSNorm(hidden_size) |
|
|
| self.ffn = SwiGLU( |
| hidden_size, |
| intermediate_size, |
| ) |
|
|
| def forward(self, x): |
| x = x + self.attn( |
| self.attn_norm(x) |
| ) |
|
|
| x = x + self.ffn( |
| self.ffn_norm(x) |
| ) |
|
|
| return x |
|
|
|
|
| class VegaLM(nn.Module): |
| def __init__( |
| self, |
| vocab_size=32000, |
| hidden_size=512, |
| num_layers=12, |
| num_heads=8, |
| num_kv_heads=4, |
| intermediate_size=880, |
| max_seq_len=2048, |
| ): |
| super().__init__() |
|
|
| self.vocab_size = vocab_size |
| self.hidden_size = hidden_size |
|
|
| self.token_embedding = nn.Embedding( |
| vocab_size, |
| hidden_size, |
| ) |
|
|
| self.layers = nn.ModuleList( |
| [ |
| TransformerBlock( |
| hidden_size=hidden_size, |
| num_heads=num_heads, |
| num_kv_heads=num_kv_heads, |
| intermediate_size=intermediate_size, |
| max_seq_len=max_seq_len, |
| ) |
| for _ in range(num_layers) |
| ] |
| ) |
|
|
| self.final_norm = RMSNorm(hidden_size) |
|
|
| self.lm_head = nn.Linear( |
| hidden_size, |
| vocab_size, |
| bias=False, |
| ) |
|
|
| |
| self.lm_head.weight = self.token_embedding.weight |
|
|
| self.apply(self._init_weights) |
|
|
| def _init_weights(self, module): |
| if isinstance(module, nn.Linear): |
| nn.init.normal_( |
| module.weight, |
| mean=0.0, |
| std=0.02, |
| ) |
|
|
| elif isinstance(module, nn.Embedding): |
| nn.init.normal_( |
| module.weight, |
| mean=0.0, |
| std=0.02, |
| ) |
|
|
| def forward(self, input_ids, targets=None): |
| x = self.token_embedding(input_ids) |
|
|
| for layer in self.layers: |
| x = layer(x) |
|
|
| x = self.final_norm(x) |
|
|
| logits = self.lm_head(x) |
|
|
| loss = None |
|
|
| if targets is not None: |
| loss = F.cross_entropy( |
| logits.view(-1, self.vocab_size), |
| targets.view(-1), |
| ) |
|
|
| return logits, loss |
|
|
|
|
| def count_parameters(model): |
| return sum( |
| p.numel() |
| for p in model.parameters() |
| if p.requires_grad |
| ) |
|
|
|
|
| if __name__ == "__main__": |
| model = VegaLM() |
|
|
| params = count_parameters(model) |
|
|
| print(f"Parameters: {params:,}") |
| print(f"Parameters: {params / 1e6:.2f}M") |
|
|
| x = torch.randint( |
| 0, |
| 32000, |
| (2, 128), |
| ) |
|
|
| logits, _ = model(x) |
|
|
| print(f"Input: {x.shape}") |
| print(f"Output: {logits.shape}") |
|
|