samcheng0 commited on
Commit
29515cd
·
verified ·
1 Parent(s): 1fb02d0

Upload model_tiny.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. model_tiny.py +220 -0
model_tiny.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.nn.functional as F
5
+
6
+
7
+ def get_alibi_slopes(num_heads: int) -> torch.Tensor:
8
+ n = 2 ** math.ceil(math.log2(num_heads))
9
+ m = torch.tensor([2 ** (-(i + 1)) for i in range(n)])
10
+ m = m[:num_heads]
11
+ return m
12
+
13
+
14
+ def build_alibi_bias(num_heads: int, seq_len: int, device: torch.device, dtype: torch.dtype) -> torch.Tensor:
15
+ slopes = get_alibi_slopes(num_heads).to(device=device, dtype=dtype)
16
+ pos = torch.arange(seq_len, device=device, dtype=dtype)
17
+ mask = pos.view(1, seq_len) - pos.view(seq_len, 1)
18
+ mask = mask.abs().neg().unsqueeze(0).unsqueeze(0)
19
+ bias = mask * slopes.view(-1, 1, 1)
20
+ return bias
21
+
22
+
23
+ class ALiBiAttention(nn.Module):
24
+ def __init__(self, hidden: int, num_heads: int, num_kv_heads: int):
25
+ super().__init__()
26
+ self.hidden = hidden
27
+ self.num_heads = num_heads
28
+ self.num_kv_heads = num_kv_heads
29
+ self.head_dim = hidden // num_heads
30
+ self.num_groups = num_heads // num_kv_heads
31
+
32
+ self.q_proj = nn.Linear(hidden, hidden, bias=False)
33
+ self.k_proj = nn.Linear(hidden, num_kv_heads * self.head_dim, bias=False)
34
+ self.v_proj = nn.Linear(hidden, num_kv_heads * self.head_dim, bias=False)
35
+ self.o_proj = nn.Linear(hidden, hidden, bias=False)
36
+ self._alibi_bias = None
37
+ self._alibi_seq_len = 0
38
+
39
+ def _get_alibi(self, seq_len: int, device: torch.device, dtype: torch.dtype) -> torch.Tensor:
40
+ if self._alibi_bias is None or seq_len > self._alibi_seq_len:
41
+ bias = build_alibi_bias(self.num_heads, seq_len, device, dtype)
42
+ causal = torch.triu(torch.full((seq_len, seq_len), float('-inf'), device=device, dtype=dtype), diagonal=1)
43
+ self._alibi_bias = bias + causal
44
+ self._alibi_seq_len = seq_len
45
+ return self._alibi_bias[:, :, :seq_len, :seq_len]
46
+
47
+ def forward(self, x):
48
+ B, T, _ = x.shape
49
+ q = self.q_proj(x).view(B, T, self.num_heads, self.head_dim).transpose(1, 2)
50
+ k = self.k_proj(x).view(B, T, self.num_kv_heads, self.head_dim).transpose(1, 2)
51
+ v = self.v_proj(x).view(B, T, self.num_kv_heads, self.head_dim).transpose(1, 2)
52
+
53
+ if self.num_groups > 1:
54
+ k = k.repeat_interleave(self.num_groups, dim=1)
55
+ v = v.repeat_interleave(self.num_groups, dim=1)
56
+
57
+ scores = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
58
+ scores = scores + self._get_alibi(T, x.device, scores.dtype)
59
+
60
+ attn = F.softmax(scores, dim=-1, dtype=torch.float32).to(x.dtype)
61
+ out = (attn @ v).transpose(1, 2).contiguous().view(B, T, self.hidden)
62
+ return self.o_proj(out)
63
+
64
+
65
+ class MLP(nn.Module):
66
+ def __init__(self, hidden: int, intermediate: int):
67
+ super().__init__()
68
+ self.gate = nn.Linear(hidden, intermediate, bias=False)
69
+ self.up = nn.Linear(hidden, intermediate, bias=False)
70
+ self.down = nn.Linear(intermediate, hidden, bias=False)
71
+
72
+ def forward(self, x):
73
+ return self.down(F.gelu(self.gate(x)) * self.up(x))
74
+
75
+
76
+ class TransformerBlock(nn.Module):
77
+ def __init__(self, hidden: int, intermediate: int, num_heads: int, num_kv_heads: int):
78
+ super().__init__()
79
+ self.ln1 = nn.LayerNorm(hidden)
80
+ self.attn = ALiBiAttention(hidden, num_heads, num_kv_heads)
81
+ self.ln2 = nn.LayerNorm(hidden)
82
+ self.mlp = MLP(hidden, intermediate)
83
+
84
+ def forward(self, x):
85
+ x = x + self.attn(self.ln1(x))
86
+ x = x + self.mlp(self.ln2(x))
87
+ return x
88
+
89
+
90
+ class TinyModel(nn.Module):
91
+ def __init__(self, vocab_size=4096, hidden=128, intermediate=512,
92
+ num_layers=2, num_heads=8, num_kv_heads=4, max_seq_len=2048,
93
+ tie_weights=True):
94
+ super().__init__()
95
+ self.hidden = hidden
96
+ self.max_seq_len = max_seq_len
97
+ self.token_embed = nn.Embedding(vocab_size, hidden)
98
+ self.blocks = nn.ModuleList([
99
+ TransformerBlock(hidden, intermediate, num_heads, num_kv_heads)
100
+ for _ in range(num_layers)
101
+ ])
102
+ self.ln_f = nn.LayerNorm(hidden)
103
+ self.lm_head = nn.Linear(hidden, vocab_size, bias=False)
104
+ if tie_weights:
105
+ self.lm_head.weight = self.token_embed.weight
106
+
107
+ def forward(self, input_ids, labels=None):
108
+ x = self.token_embed(input_ids)
109
+ for block in self.blocks:
110
+ x = block(x)
111
+ x = self.ln_f(x)
112
+ logits = self.lm_head(x)
113
+
114
+ loss = None
115
+ if labels is not None:
116
+ shift_logits = logits[..., :-1, :].contiguous()
117
+ shift_labels = labels[..., 1:].contiguous()
118
+ loss = F.cross_entropy(
119
+ shift_logits.view(-1, shift_logits.size(-1)),
120
+ shift_labels.view(-1),
121
+ ignore_index=-100,
122
+ )
123
+ return logits, loss
124
+
125
+ def generate(self, input_ids, max_new_tokens=128, temperature=0.7, top_p=0.9):
126
+ self.eval()
127
+ for _ in range(max_new_tokens):
128
+ seq_len = input_ids.size(1)
129
+ if seq_len > self.max_seq_len:
130
+ input_ids = input_ids[:, -self.max_seq_len:]
131
+ with torch.no_grad():
132
+ logits, _ = self.forward(input_ids)
133
+ logits = logits[:, -1, :] / temperature
134
+
135
+ if top_p < 1.0:
136
+ sorted_logits, sorted_idx = logits.sort(dim=-1, descending=True)
137
+ cum_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1)
138
+ cutoff = cum_probs > top_p
139
+ cutoff[..., 1:] = cutoff[..., :-1].clone()
140
+ cutoff[..., 0] = False
141
+ logits[~cutoff] = float('-inf')
142
+
143
+ probs = F.softmax(logits, dim=-1)
144
+ next_token = torch.multinomial(probs, num_samples=1)
145
+ input_ids = torch.cat([input_ids, next_token], dim=1)
146
+
147
+ if next_token.item() == 2:
148
+ break
149
+ return input_ids
150
+
151
+
152
+ class LoRALinear(nn.Module):
153
+ def __init__(self, original: nn.Linear, r: int = 8, alpha: float = 16, dropout: float = 0.0):
154
+ super().__init__()
155
+ self.linear = original
156
+ self.r = r
157
+ self.alpha = alpha
158
+ self.scaling = alpha / r
159
+ self.dropout = nn.Dropout(dropout) if dropout > 0 else nn.Identity()
160
+ in_dim, out_dim = original.in_features, original.out_features
161
+ self.lora_A = nn.Parameter(torch.zeros(r, in_dim))
162
+ self.lora_B = nn.Parameter(torch.zeros(out_dim, r))
163
+ nn.init.kaiming_uniform_(self.lora_A, a=math.sqrt(5))
164
+ self.linear.weight.requires_grad = False
165
+ if self.linear.bias is not None:
166
+ self.linear.bias.requires_grad = False
167
+
168
+ def forward(self, x):
169
+ return self.linear(x) + self.dropout(x) @ self.lora_A.T @ self.lora_B.T * self.scaling
170
+
171
+
172
+ def apply_lora(model, target_modules=None, r=8, alpha=16, dropout=0.0):
173
+ if target_modules is None:
174
+ target_modules = ["q_proj", "k_proj", "v_proj", "o_proj", "gate", "up", "down"]
175
+ lora_params = 0
176
+ for name, module in model.named_modules():
177
+ if not isinstance(module, nn.Linear):
178
+ continue
179
+ key = name.split(".")[-1]
180
+ if key not in target_modules:
181
+ continue
182
+ parent = model
183
+ parts = name.split(".")
184
+ for p in parts[:-1]:
185
+ parent = getattr(parent, p)
186
+ lora = LoRALinear(module, r=r, alpha=alpha, dropout=dropout)
187
+ setattr(parent, parts[-1], lora)
188
+ lora_params += 2 * r * module.in_features + module.out_features * r
189
+ n = sum(p.numel() for p in model.parameters() if p.requires_grad)
190
+ print(f"LoRA applied: {lora_params:,} trainable params (total trainable: {n:,})")
191
+ return model
192
+
193
+
194
+ def count_params(model):
195
+ return sum(p.numel() for p in model.parameters())
196
+
197
+
198
+ def create_model():
199
+ model = TinyModel(
200
+ vocab_size=4096, hidden=128, intermediate=512,
201
+ num_layers=2, num_heads=8, num_kv_heads=4,
202
+ max_seq_len=2048, tie_weights=True,
203
+ )
204
+ n = count_params(model)
205
+ print(f"TinyModel: {n:,} params ({n/1e6:.2f}M)")
206
+ return model
207
+
208
+
209
+ if __name__ == "__main__":
210
+ m = create_model()
211
+ x = torch.randint(0, 100, (1, 16))
212
+ logits, loss = m(x, labels=x)
213
+ print(f"Forward OK: logits {logits.shape}, loss {loss.item():.4f}")
214
+ gen = m.generate(x, max_new_tokens=10)
215
+ print(f"Generate OK: {gen.shape}")
216
+ m2 = create_model()
217
+ apply_lora(m2)
218
+ x2 = torch.randint(0, 100, (1, 16))
219
+ logits2, _ = m2(x2)
220
+ print(f"LoRA forward OK: {logits2.shape}")