| """Quark-50M model definition — standalone.""" |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| from dataclasses import dataclass |
|
|
| @dataclass |
| class ModelConfig: |
| vocab_size: int = 16384; d_model: int = 512; n_heads: int = 8 |
| n_kv_heads: int = 4; n_layers: int = 12; d_ff: int = 1408 |
| head_dim: int = 64; max_seq_len: int = 2048; rope_theta: float = 10000.0 |
| rms_eps: float = 1e-5; qkv_bias: bool = False; dropout: float = 0.0 |
|
|
| class RMSNorm(nn.Module): |
| def __init__(self, dim, eps=1e-5): |
| super().__init__(); self.eps = eps; self.scale = nn.Parameter(torch.ones(dim)) |
| def forward(self, x): |
| return (x.float() * x.float().pow(2).mean(-1, keepdim=True).add(self.eps).rsqrt()).to(x.dtype) * self.scale |
|
|
| class RotaryEmbedding(nn.Module): |
| def __init__(self, head_dim, max_seq_len, theta=10000.0): |
| super().__init__() |
| inv_freq = 1.0 / (theta ** (torch.arange(0, head_dim, 2).float() / head_dim)) |
| self.register_buffer("inv_freq", inv_freq, persistent=False); self._build(max_seq_len) |
| def _build(self, seq_len): |
| t = torch.arange(seq_len, device=self.inv_freq.device).float() |
| freqs = torch.outer(t, self.inv_freq); emb = torch.cat([freqs, freqs], dim=-1) |
| self.register_buffer("cos_cache", emb.cos()[None, None], persistent=False) |
| self.register_buffer("sin_cache", emb.sin()[None, None], persistent=False); self._max = seq_len |
| @staticmethod |
| def _rot(x): |
| x1, x2 = x.chunk(2, dim=-1); return torch.cat([-x2, x1], dim=-1) |
| def forward(self, q, k): |
| T = q.size(2) |
| if T > self._max: self._build(T) |
| c, s = self.cos_cache[:,:,:T], self.sin_cache[:,:,:T] |
| return q*c + self._rot(q)*s, k*c + self._rot(k)*s |
|
|
| class GQA(nn.Module): |
| def __init__(self, cfg): |
| super().__init__() |
| self.n_heads, self.n_kv_heads = cfg.n_heads, cfg.n_kv_heads |
| self.n_groups, self.head_dim = cfg.n_heads // cfg.n_kv_heads, cfg.head_dim |
| self.q_proj = nn.Linear(cfg.d_model, cfg.n_heads * cfg.head_dim, bias=cfg.qkv_bias) |
| self.k_proj = nn.Linear(cfg.d_model, cfg.n_kv_heads * cfg.head_dim, bias=cfg.qkv_bias) |
| self.v_proj = nn.Linear(cfg.d_model, cfg.n_kv_heads * cfg.head_dim, bias=cfg.qkv_bias) |
| self.o_proj = nn.Linear(cfg.n_heads * cfg.head_dim, cfg.d_model, bias=False) |
| self.rope = RotaryEmbedding(cfg.head_dim, cfg.max_seq_len, cfg.rope_theta) |
| def forward(self, x): |
| B, T, _ = x.shape |
| q = self.q_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2) |
| k = self.k_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2) |
| v = self.v_proj(x).view(B, T, self.n_kv_heads, self.head_dim).transpose(1, 2) |
| q, k = self.rope(q, k) |
| if self.n_groups > 1: |
| B_r, _, T_r, D_r = k.shape |
| k = k[:,:,None,:,:].expand(B_r, self.n_kv_heads, self.n_groups, T_r, D_r).reshape(B_r, self.n_heads, T_r, D_r) |
| v = v[:,:,None,:,:].expand(B_r, self.n_kv_heads, self.n_groups, T_r, D_r).reshape(B_r, self.n_heads, T_r, D_r) |
| return self.o_proj(F.scaled_dot_product_attention(q, k, v, is_causal=True).transpose(1, 2).contiguous().view(B, T, -1)) |
|
|
| class Block(nn.Module): |
| def __init__(self, cfg): |
| super().__init__() |
| self.norm_attn = RMSNorm(cfg.d_model, cfg.rms_eps); self.attn = GQA(cfg) |
| self.norm_ffn = RMSNorm(cfg.d_model, cfg.rms_eps) |
| self.gate = nn.Linear(cfg.d_model, cfg.d_ff, bias=False) |
| self.up = nn.Linear(cfg.d_model, cfg.d_ff, bias=False) |
| self.down = nn.Linear(cfg.d_ff, cfg.d_model, bias=False) |
| def forward(self, x): |
| x = x + self.attn(self.norm_attn(x)) |
| h = self.norm_ffn(x); x = x + self.down(F.silu(self.gate(h)) * self.up(h)) |
| return x |
|
|
| class Quark(nn.Module): |
| def __init__(self, cfg): |
| super().__init__(); self.cfg = cfg |
| self.embed_tokens = nn.Embedding(cfg.vocab_size, cfg.d_model) |
| self.layers = nn.ModuleList([Block(cfg) for _ in range(cfg.n_layers)]) |
| self.norm = RMSNorm(cfg.d_model, cfg.rms_eps) |
| self.lm_head = nn.Linear(cfg.d_model, cfg.vocab_size, bias=False) |
| self.lm_head.weight = self.embed_tokens.weight |
| def forward(self, ids, labels=None): |
| x = self.embed_tokens(ids) |
| for layer in self.layers: x = layer(x) |
| logits = self.lm_head(self.norm(x)) |
| loss = None |
| if labels is not None: |
| loss = F.cross_entropy(logits.view(-1, self.cfg.vocab_size), labels.view(-1), ignore_index=-100) |
| return loss, logits |
|
|