CoolFace
Apppublic

pruthvimv/DecoderonlyTransformer

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
transformer.py174 linesDownload Raw Back to root
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