Spaces:
Sleeping
Sleeping
NaveenKumar Namachivayam
feat: add GPT model implementation with training and generation scripts
ba05e77 | """GPT Model Architecture for Thirukkural Training.""" | |
| from dataclasses import dataclass | |
| import torch | |
| import torch.nn as nn | |
| class GPTConfig: | |
| """Configuration for GPT model.""" | |
| vocab_size: int = 65 # Will be set dynamically based on dataset | |
| block_size: int = 256 # Max sequence length | |
| n_layer: int = 6 # Number of transformer blocks | |
| n_head: int = 6 # Number of attention heads | |
| n_embd: int = 384 # Embedding dimension | |
| class CausalSelfAttention(nn.Module): | |
| """Multi-head causal self-attention layer.""" | |
| def __init__(self, config: GPTConfig): | |
| super().__init__() | |
| assert config.n_embd % config.n_head == 0 | |
| self.c_attn = nn.Linear(config.n_embd, 3 * config.n_embd) | |
| self.c_proj = nn.Linear(config.n_embd, config.n_embd) | |
| self.n_head = config.n_head | |
| self.n_embd = config.n_embd | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| B, T, C = x.shape | |
| qkv = self.c_attn(x) | |
| q, k, v = qkv.split(self.n_embd, dim=2) | |
| head_dim = C // self.n_head | |
| q = q.view(B, T, self.n_head, head_dim).transpose(1, 2) | |
| k = k.view(B, T, self.n_head, head_dim).transpose(1, 2) | |
| v = v.view(B, T, self.n_head, head_dim).transpose(1, 2) | |
| y = torch.nn.functional.scaled_dot_product_attention( | |
| q, k, v, is_causal=True | |
| ) | |
| y = y.transpose(1, 2).contiguous().view(B, T, C) | |
| return self.c_proj(y) | |
| class MLP(nn.Module): | |
| """Feed-forward network with GELU activation.""" | |
| def __init__(self, config: GPTConfig): | |
| super().__init__() | |
| self.c_fc = nn.Linear(config.n_embd, 4 * config.n_embd) | |
| self.gelu = nn.GELU(approximate="tanh") | |
| self.c_proj = nn.Linear(4 * config.n_embd, config.n_embd) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| x = self.c_fc(x) | |
| x = self.gelu(x) | |
| return self.c_proj(x) | |
| class Block(nn.Module): | |
| """Transformer block with attention and MLP.""" | |
| def __init__(self, config: GPTConfig): | |
| super().__init__() | |
| self.ln_1 = nn.LayerNorm(config.n_embd) | |
| self.attn = CausalSelfAttention(config) | |
| self.ln_2 = nn.LayerNorm(config.n_embd) | |
| self.mlp = MLP(config) | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| x = x + self.attn(self.ln_1(x)) | |
| x = x + self.mlp(self.ln_2(x)) | |
| return x | |
| class GPT(nn.Module): | |
| """GPT language model.""" | |
| def __init__(self, config: GPTConfig): | |
| super().__init__() | |
| self.config = config | |
| self.transformer = nn.ModuleDict( | |
| dict( | |
| wte=nn.Embedding(config.vocab_size, config.n_embd), | |
| wpe=nn.Embedding(config.block_size, config.n_embd), | |
| h=nn.ModuleList([Block(config) for _ in range(config.n_layer)]), | |
| ln_f=nn.LayerNorm(config.n_embd), | |
| ) | |
| ) | |
| self.lm_head = nn.Linear(config.n_embd, config.vocab_size, bias=False) | |
| self.transformer.wte.weight = self.lm_head.weight | |
| def forward( | |
| self, idx: torch.Tensor, targets: torch.Tensor | None = None | |
| ) -> tuple[torch.Tensor, torch.Tensor | None]: | |
| B, T = idx.shape | |
| pos = torch.arange(0, T, device=idx.device) | |
| tok_emb = self.transformer.wte(idx) | |
| pos_emb = self.transformer.wpe(pos) | |
| x = tok_emb + pos_emb | |
| for block in self.transformer.h: | |
| x = block(x) | |
| x = self.transformer.ln_f(x) | |
| logits = self.lm_head(x) | |
| loss = None | |
| if targets is not None: | |
| loss = nn.functional.cross_entropy( | |
| logits.view(-1, logits.size(-1)), targets.view(-1) | |
| ) | |
| return logits, loss | |