bennymach commited on
Commit
ddd581d
·
verified ·
1 Parent(s): a88372a

Add Pluto model implementation

Browse files
Files changed (1) hide show
  1. model.py +154 -0
model.py ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from dataclasses import dataclass
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+
8
+
9
+ @dataclass
10
+ class GPTConfig:
11
+ vocab_size: int = 50257
12
+ block_size: int = 256
13
+ n_layer: int = 6
14
+ n_head: int = 6
15
+ n_embd: int = 384
16
+ dropout: float = 0.1
17
+ bias: bool = False
18
+
19
+
20
+ class CausalSelfAttention(nn.Module):
21
+ def __init__(self, cfg: GPTConfig):
22
+ super().__init__()
23
+ assert cfg.n_embd % cfg.n_head == 0
24
+ self.n_head = cfg.n_head
25
+ self.qkv = nn.Linear(cfg.n_embd, 3 * cfg.n_embd, bias=cfg.bias)
26
+ self.proj = nn.Linear(cfg.n_embd, cfg.n_embd, bias=cfg.bias)
27
+ self.attn_drop = cfg.dropout
28
+ self.resid_drop = nn.Dropout(cfg.dropout)
29
+
30
+ def forward(self, x):
31
+ B, T, C = x.shape
32
+ q, k, v = self.qkv(x).split(C, dim=2)
33
+ q, k, v = (t.view(B, T, self.n_head, C // self.n_head).transpose(1, 2) for t in (q, k, v))
34
+ y = F.scaled_dot_product_attention(
35
+ q, k, v,
36
+ dropout_p=self.attn_drop if self.training else 0.0,
37
+ is_causal=True,
38
+ )
39
+ y = y.transpose(1, 2).contiguous().view(B, T, C)
40
+ return self.resid_drop(self.proj(y))
41
+
42
+
43
+ class MLP(nn.Module):
44
+ def __init__(self, cfg: GPTConfig):
45
+ super().__init__()
46
+ self.fc = nn.Linear(cfg.n_embd, 4 * cfg.n_embd, bias=cfg.bias)
47
+ self.proj = nn.Linear(4 * cfg.n_embd, cfg.n_embd, bias=cfg.bias)
48
+ self.drop = nn.Dropout(cfg.dropout)
49
+
50
+ def forward(self, x):
51
+ return self.drop(self.proj(F.gelu(self.fc(x))))
52
+
53
+
54
+ class Block(nn.Module):
55
+ """Pre-LayerNorm transformer block."""
56
+
57
+ def __init__(self, cfg: GPTConfig):
58
+ super().__init__()
59
+ self.ln1 = nn.LayerNorm(cfg.n_embd, bias=cfg.bias)
60
+ self.attn = CausalSelfAttention(cfg)
61
+ self.ln2 = nn.LayerNorm(cfg.n_embd, bias=cfg.bias)
62
+ self.mlp = MLP(cfg)
63
+
64
+ def forward(self, x):
65
+ x = x + self.attn(self.ln1(x))
66
+ x = x + self.mlp(self.ln2(x))
67
+ return x
68
+
69
+
70
+ class GPT(nn.Module):
71
+ def __init__(self, cfg: GPTConfig):
72
+ super().__init__()
73
+ self.cfg = cfg
74
+ self.tok_emb = nn.Embedding(cfg.vocab_size, cfg.n_embd)
75
+ self.pos_emb = nn.Embedding(cfg.block_size, cfg.n_embd)
76
+ self.drop = nn.Dropout(cfg.dropout)
77
+ self.blocks = nn.ModuleList(Block(cfg) for _ in range(cfg.n_layer))
78
+ self.ln_f = nn.LayerNorm(cfg.n_embd, bias=cfg.bias)
79
+ self.lm_head = nn.Linear(cfg.n_embd, cfg.vocab_size, bias=False)
80
+ self.lm_head.weight = self.tok_emb.weight # weight tying
81
+
82
+ self.apply(self._init_weights)
83
+ for name, p in self.named_parameters():
84
+ if name.endswith("proj.weight"):
85
+ nn.init.normal_(p, mean=0.0, std=0.02 / math.sqrt(2 * cfg.n_layer))
86
+
87
+ def _init_weights(self, m):
88
+ if isinstance(m, nn.Linear):
89
+ nn.init.normal_(m.weight, mean=0.0, std=0.02)
90
+ if m.bias is not None:
91
+ nn.init.zeros_(m.bias)
92
+ elif isinstance(m, nn.Embedding):
93
+ nn.init.normal_(m.weight, mean=0.0, std=0.02)
94
+
95
+ def num_params(self):
96
+ return sum(p.numel() for p in self.parameters())
97
+
98
+ def forward(self, idx, targets=None):
99
+ B, T = idx.shape
100
+ assert T <= self.cfg.block_size, f"Sequence length {T} > block_size {self.cfg.block_size}"
101
+ pos = torch.arange(T, device=idx.device)
102
+ x = self.drop(self.tok_emb(idx) + self.pos_emb(pos))
103
+ for block in self.blocks:
104
+ x = block(x)
105
+ x = self.ln_f(x)
106
+
107
+ if targets is not None:
108
+ logits = self.lm_head(x)
109
+ loss = F.cross_entropy(logits.view(-1, logits.size(-1)), targets.view(-1), ignore_index=-1)
110
+ return logits, loss
111
+ return self.lm_head(x[:, [-1], :]), None
112
+
113
+ def configure_optimizer(self, lr=3e-4, weight_decay=0.1, betas=(0.9, 0.95)):
114
+ params = [p for p in self.parameters() if p.requires_grad]
115
+ decay = [p for p in params if p.dim() >= 2]
116
+ no_decay = [p for p in params if p.dim() < 2]
117
+ groups = [
118
+ {"params": decay, "weight_decay": weight_decay},
119
+ {"params": no_decay, "weight_decay": 0.0},
120
+ ]
121
+ return torch.optim.AdamW(groups, lr=lr, betas=betas)
122
+
123
+ @torch.no_grad()
124
+ def generate(self, idx, max_new_tokens, temperature=1.0, top_k=None):
125
+ self.eval()
126
+ eos_token_id = 50256
127
+
128
+ for _ in range(max_new_tokens):
129
+ idx_cond = idx[:, -self.cfg.block_size:]
130
+ logits, _ = self(idx_cond)
131
+ logits = logits[:, -1, :] / max(temperature, 1e-8)
132
+
133
+ if top_k is not None:
134
+ v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
135
+ logits[logits < v[:, [-1]]] = float("-inf")
136
+
137
+ probs = F.softmax(logits, dim=-1)
138
+ next_token = torch.multinomial(probs, 1)
139
+ idx = torch.cat([idx, next_token], dim=1)
140
+
141
+ if torch.all(next_token == eos_token_id):
142
+ break
143
+
144
+ return idx
145
+
146
+
147
+ if __name__ == "__main__":
148
+ cfg = GPTConfig(vocab_size=1000, block_size=64, n_layer=2, n_head=2, n_embd=64)
149
+ model = GPT(cfg)
150
+ print(f"params: {model.num_params():,}")
151
+ x = torch.randint(0, cfg.vocab_size, (4, 64))
152
+ logits, loss = model(x, targets=x)
153
+ print("loss:", loss.item())
154
+ print(model.generate(x[:1, :8], max_new_tokens=10).shape)