pruthvimv/DecoderonlyTransformer
0
1import torch2import torch.nn as nn3import torch.nn.functional as F4from dataclasses import dataclass5from transformers import GPT2Tokenizer6import tiktoken7 8@dataclass9class Config:10 vocab_size: int = 5025711 max_seq_len: int = 204812 dim: int = 76813 num_layers: int = 1214 num_heads: int = 1215 dropout: float = 0.116 17class MultiHeadAttention(nn.Module):18 def __init__(self, config):19 super().__init__()20 self.config = config21 self.n_head = config.num_heads22 self.n_embd = config.dim23 24 # Linear projections for Q, K, V25 self.c_attn = nn.Linear(config.dim, 3 * config.dim) # [n_embd, 3 * n_embd]26 self.c_proj = nn.Linear(config.dim, config.dim) # [n_embd, n_embd]27 28 self.attn_dropout = nn.Dropout(config.dropout)29 self.resid_dropout = nn.Dropout(config.dropout)30 31 def forward(self, x):32 B, T, C = x.size() # [B, T, n_embd]33 34 # Linear projection and split into Q, K, V35 q, k, v = self.c_attn(x).split(self.n_embd, dim=2) # [B, T, n_embd] each36 37 # Reshape for multi-head attention38 k = k.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # [B, n_head, T, n_embd/n_head]39 q = q.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # [B, n_head, T, n_embd/n_head]40 v = v.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) # [B, n_head, T, n_embd/n_head]41 42 # Attention scores43 att = (q @ k.transpose(-2, -1)) * (1.0 / (k.size(-1) ** 0.5)) # [B, n_head, T, T]44 att = F.softmax(att, dim=-1) # [B, n_head, T, T]45 att = self.attn_dropout(att) # [B, n_head, T, T]46 47 # Weighted sum of values48 y = att @ v # [B, n_head, T, n_embd/n_head]49 50 # Reshape and project51 y = y.transpose(1, 2).contiguous().view(B, T, C) # [B, T, n_embd]52 y = self.c_proj(y) # [B, T, n_embd]53 y = self.resid_dropout(y) # [B, T, n_embd]54 55 return y56 57class FeedForward(nn.Module):58 def __init__(self, config):59 super().__init__()60 self.c_fc = nn.Linear(config.dim, 4 * config.dim) # [n_embd, 4 * n_embd]61 self.c_proj = nn.Linear(4 * config.dim, config.dim) # [4 * n_embd, n_embd]62 self.dropout = nn.Dropout(config.dropout)63 64 def forward(self, x):65 x = self.c_fc(x) # [B, T, 4 * n_embd]66 x = F.gelu(x) # [B, T, 4 * n_embd]67 x = self.c_proj(x) # [B, T, n_embd]68 x = self.dropout(x) # [B, T, n_embd]69 return x70 71class TransformerBlock(nn.Module):72 def __init__(self, config):73 super().__init__()74 self.ln_1 = nn.LayerNorm(config.dim) # [n_embd]75 self.attn = MultiHeadAttention(config)76 self.ln_2 = nn.LayerNorm(config.dim) # [n_embd]77 self.mlp = FeedForward(config)78 79 def forward(self, x):80 x = x + self.attn(self.ln_1(x)) # [B, T, n_embd]81 82class DecoderOnlyTransformer(nn.Module):83 def __init__(self, config):84 super().__init__()85 self.config = config86 self.wte = nn.Embedding(config.vocab_size, config.dim) # [vocab_size, n_embd]87 self.wpe = nn.Embedding(config.max_seq_len, config.dim) # [max_seq_len, n_embd]88 self.drop = nn.Dropout(config.dropout)89 self.blocks = nn.ModuleList([TransformerBlock(config) for _ in range(config.num_layers)])90 self.ln_f = nn.LayerNorm(config.dim) # [n_embd]91 self.lm_head = nn.Linear(config.dim, config.vocab_size, bias=False) # [n_embd, vocab_size]92 93 self.apply(self._init_weights)94 95 def _init_weights(self, module):96 if isinstance(module, (nn.Linear, nn.Embedding)):97 module.weight.data.normal_(mean=0.0, std=0.02)98 if isinstance(module, nn.Linear) and module.bias is not None:99 module.bias.data.zero_()100 elif isinstance(module, nn.LayerNorm):101 module.bias.data.zero_()102 module.weight.data.fill_(1.0)103 104 def forward(self, idx):105 B, T = idx.size() # [B, T]106 107 # Positional embeddings108 pos = torch.arange(0, T, dtype=torch.long, device=idx.device).unsqueeze(0) # [1, T]109 110 # Token and position embeddings111 tok_emb = self.wte(idx) # [B, T, n_embd]112 pos_emb = self.wpe(pos) # [1, T, n_embd]113 114 # Combine embeddings and apply dropout115 x = self.drop(tok_emb + pos_emb) # [B, T, n_embd]116 117 # Transformer blocks118 for block in self.blocks:119 x = block(x) # [B, T, n_embd]120 121 # Final layer norm and linear projection122 x = self.ln_f(x) # [B, T, n_embd]123 logits = self.lm_head(x) # [B, T, vocab_size]124 125 return logits126 127class DataLoaderLite:128 def __init__(self, B, T):129 self.B = B130 self.T = T131 # at init load tokens from disk and store them in memory132 with open('input.txt', 'r') as f:133 text = f.read()134 enc = tiktoken.get_encoding('gpt2')135 tokens = enc.encode(text)136 self.tokens = torch.tensor(tokens)137 print(f'loaded {len(self.tokens)} tokens')138 print(f'1 epoch = {len(self.tokens) // (B * T)} batches')139 # state140 self.current_position = 0141 def next_batch(self):142 B, T = self.B, self.T143 buf = self.tokens[self.current_position: self.current_position + B * T + 1]144 x = (buf[:-1]).view(B, T) # inputs145 y = (buf[1:]).view(B, T) # targets146 # advance the position in the tensor147 self.current_position += B*T148 # if loading the next batch would be out of bounds, reset149 if self.current_position + (B * T + 1) > len(self.tokens):150 self.current_position = 0151 return x, y152 153if __name__ == '__main__':154 use_cuda = torch.cuda.is_available()155 device = torch.device("cuda" if use_cuda else "cpu")156 config = Config()157 model = DecoderOnlyTransformer(config)158 model.to(device)159 160 # Train the model161 train_loader = DataLoaderLite(B = 4, T = 128)162 # NEW CODE163 optimizer = torch.optim.AdamW(model.parameters(), lr = 3e-4)164 loss_fn = nn.CrossEntropyLoss() # Define loss_fn here165 for i in range(5000):166 x, y = train_loader.next_batch()167 x, y = x.to(device), y.to(device)168 optimizer.zero_grad()169 logits = model(x)170 loss = loss_fn(logits.reshape(-1, logits.size(-1)), y.reshape(-1)) # Calculate loss using logits and target171 loss.backward()172 optimizer.step()173 174 print(f"Iteration: {i + 1}, Loss: {loss.item()}") # Change to iteration