Devatri commited on
Commit
faed12c
·
verified ·
1 Parent(s): ded04a6

Upload model.py

Browse files
Files changed (1) hide show
  1. model.py +196 -0
model.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Dense decoder-only Transformer adapted from the Part 1 Model 1 architecture."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ import torch
8
+ from torch import nn
9
+ from torch.nn import functional as F
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class ModelConfig:
14
+ vocab_size: int
15
+ d_model: int = 512
16
+ n_heads: int = 8
17
+ n_layers: int = 6
18
+ mlp_hidden_size: int = 2048
19
+ max_sequence_length: int = 256
20
+ dropout: float = 0.1
21
+ tie_embeddings: bool = True
22
+
23
+ @classmethod
24
+ def from_mapping(cls, values: dict, vocab_size: int | None = None) -> ModelConfig:
25
+ clean = dict(values)
26
+ if vocab_size is not None:
27
+ clean["vocab_size"] = vocab_size
28
+ return cls(**clean)
29
+
30
+ def __post_init__(self) -> None:
31
+ if self.d_model % self.n_heads:
32
+ raise ValueError("d_model must be divisible by n_heads")
33
+ if self.d_model // self.n_heads % 2:
34
+ raise ValueError("attention head size must be even for rotary embeddings")
35
+ if self.max_sequence_length < 2:
36
+ raise ValueError("max_sequence_length must be at least 2")
37
+
38
+
39
+ class DenseMLP(nn.Module):
40
+ """Part 1 Model 1's standard two-layer GELU feed-forward network."""
41
+
42
+ def __init__(self, config: ModelConfig) -> None:
43
+ super().__init__()
44
+ self.up = nn.Linear(config.d_model, config.mlp_hidden_size, bias=False)
45
+ self.down = nn.Linear(config.mlp_hidden_size, config.d_model, bias=False)
46
+
47
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
48
+ return self.down(F.gelu(self.up(x)))
49
+
50
+
51
+ class CausalSelfAttention(nn.Module):
52
+ def __init__(self, config: ModelConfig) -> None:
53
+ super().__init__()
54
+ self.n_heads = config.n_heads
55
+ self.head_size = config.d_model // config.n_heads
56
+ self.dropout = config.dropout
57
+ self.qkv = nn.Linear(config.d_model, 3 * config.d_model, bias=False)
58
+ self.out = nn.Linear(config.d_model, config.d_model, bias=False)
59
+ positions = torch.arange(config.max_sequence_length)
60
+ frequencies = 10000.0 ** (-torch.arange(0, self.head_size, 2).float() / self.head_size)
61
+ angles = torch.outer(positions, frequencies)
62
+ self.register_buffer("rope_cos", angles.cos(), persistent=False)
63
+ self.register_buffer("rope_sin", angles.sin(), persistent=False)
64
+
65
+ def _apply_rope(self, tensor: torch.Tensor, position_offset: int) -> torch.Tensor:
66
+ length = tensor.shape[-2]
67
+ stop = position_offset + length
68
+ cosine = self.rope_cos[position_offset:stop].to(tensor.dtype)[None, None]
69
+ sine = self.rope_sin[position_offset:stop].to(tensor.dtype)[None, None]
70
+ even, odd = tensor[..., ::2], tensor[..., 1::2]
71
+ return torch.stack(
72
+ (even * cosine - odd * sine, even * sine + odd * cosine), dim=-1
73
+ ).flatten(-2)
74
+
75
+ def forward(
76
+ self,
77
+ x: torch.Tensor,
78
+ cache: tuple[torch.Tensor, torch.Tensor] | None = None,
79
+ ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
80
+ batch, length, width = x.shape
81
+ query, key, value = (
82
+ self.qkv(x)
83
+ .view(batch, length, 3, self.n_heads, self.head_size)
84
+ .permute(2, 0, 3, 1, 4)
85
+ .unbind(0)
86
+ )
87
+ cached_length = 0 if cache is None else cache[0].shape[-2]
88
+ query = self._apply_rope(query, cached_length)
89
+ key = self._apply_rope(key, cached_length)
90
+ if cache is not None:
91
+ if length != 1:
92
+ raise ValueError("cached attention accepts one new token at a time")
93
+ key = torch.cat((cache[0], key), dim=-2)
94
+ value = torch.cat((cache[1], value), dim=-2)
95
+ attended = F.scaled_dot_product_attention(
96
+ query,
97
+ key,
98
+ value,
99
+ is_causal=cache is None,
100
+ dropout_p=self.dropout if self.training else 0.0,
101
+ )
102
+ output = self.out(attended.transpose(1, 2).reshape(batch, length, width))
103
+ return output, (key, value)
104
+
105
+
106
+ class TransformerBlock(nn.Module):
107
+ def __init__(self, config: ModelConfig) -> None:
108
+ super().__init__()
109
+ self.attention_norm = nn.LayerNorm(config.d_model)
110
+ self.mlp_norm = nn.LayerNorm(config.d_model)
111
+ self.attention = CausalSelfAttention(config)
112
+ self.mlp = DenseMLP(config)
113
+ self.dropout = nn.Dropout(config.dropout)
114
+
115
+ def forward(
116
+ self,
117
+ x: torch.Tensor,
118
+ cache: tuple[torch.Tensor, torch.Tensor] | None = None,
119
+ ) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
120
+ attended, next_cache = self.attention(self.attention_norm(x), cache)
121
+ x = x + self.dropout(attended)
122
+ return x + self.dropout(self.mlp(self.mlp_norm(x))), next_cache
123
+
124
+
125
+ class DenseTransformer(nn.Module):
126
+ def __init__(self, config: ModelConfig) -> None:
127
+ super().__init__()
128
+ self.config = config
129
+ self.embedding = nn.Embedding(config.vocab_size, config.d_model)
130
+ self.dropout = nn.Dropout(config.dropout)
131
+ self.blocks = nn.ModuleList([TransformerBlock(config) for _ in range(config.n_layers)])
132
+ self.final_norm = nn.LayerNorm(config.d_model)
133
+ self.lm_head = nn.Linear(config.d_model, config.vocab_size, bias=False)
134
+ self.apply(self._initialize)
135
+ if config.tie_embeddings:
136
+ self.lm_head.weight = self.embedding.weight
137
+
138
+ @staticmethod
139
+ def _initialize(module: nn.Module) -> None:
140
+ if isinstance(module, (nn.Linear, nn.Embedding)):
141
+ nn.init.normal_(module.weight, mean=0.0, std=0.02)
142
+ if isinstance(module, nn.Linear) and module.bias is not None:
143
+ nn.init.zeros_(module.bias)
144
+
145
+ def forward(
146
+ self,
147
+ input_ids: torch.Tensor,
148
+ labels: torch.Tensor | None = None,
149
+ *,
150
+ cache: list[tuple[torch.Tensor, torch.Tensor]] | None = None,
151
+ use_cache: bool = False,
152
+ ) -> dict[str, object]:
153
+ if input_ids.ndim != 2:
154
+ raise ValueError("input_ids must have shape [batch, sequence]")
155
+ cached_length = 0 if cache is None else cache[0][0].shape[-2]
156
+ if cached_length + input_ids.shape[1] > self.config.max_sequence_length:
157
+ raise ValueError("input exceeds configured maximum sequence length")
158
+ if cache is not None and len(cache) != len(self.blocks):
159
+ raise ValueError("cache must contain one entry per Transformer block")
160
+ hidden = self.dropout(self.embedding(input_ids))
161
+ next_cache = []
162
+ for index, block in enumerate(self.blocks):
163
+ hidden, block_cache = block(hidden, None if cache is None else cache[index])
164
+ if use_cache:
165
+ next_cache.append(block_cache)
166
+ logits = self.lm_head(self.final_norm(hidden))
167
+ loss = None
168
+ if labels is not None:
169
+ if labels.shape != input_ids.shape:
170
+ raise ValueError("labels and input_ids must have the same shape")
171
+ loss = F.cross_entropy(
172
+ logits.reshape(-1, logits.shape[-1]).float(),
173
+ labels.reshape(-1),
174
+ ignore_index=-100,
175
+ )
176
+ return {"logits": logits, "loss": loss, "cache": next_cache if use_cache else None}
177
+
178
+ @torch.no_grad()
179
+ def greedy_generate(self, prompt: torch.Tensor, max_new_tokens: int) -> torch.Tensor:
180
+ """Generate with the model's forward pass and deterministic greedy decoding."""
181
+ if prompt.ndim != 2:
182
+ raise ValueError("prompt must have shape [batch, sequence]")
183
+ if prompt.shape[1] + max_new_tokens > self.config.max_sequence_length:
184
+ raise ValueError("prompt and continuation exceed the model context window")
185
+ generated = prompt
186
+ output = self(prompt, use_cache=True)
187
+ for step in range(max_new_tokens):
188
+ next_token = output["logits"][:, -1].argmax(dim=-1, keepdim=True)
189
+ generated = torch.cat((generated, next_token), dim=1)
190
+ if step + 1 < max_new_tokens:
191
+ output = self(next_token, cache=output["cache"], use_cache=True)
192
+ return generated
193
+
194
+
195
+ def parameter_count(model: nn.Module) -> int:
196
+ return sum(parameter.numel() for parameter in model.parameters())