Qarvexium commited on
Commit
320ca79
·
verified ·
1 Parent(s): 3c1b20a

Upload 6 files

Browse files
a.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from qwisp import Wisp
2
+
3
+ w = Wisp().load(device="cpu")
4
+
5
+ print(w.chat("Hi",temperature=0.7))
qwisp/__init__.py ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import json
3
+ import math
4
+ from pathlib import Path
5
+ from contextlib import nullcontext
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ import torch.nn.functional as F
10
+ import sentencepiece as spm
11
+
12
+ torch.set_num_threads(12)
13
+ torch.set_num_interop_threads(12)
14
+
15
+ # ---------------------------------------------------------------------------
16
+ # Model definition — must match the training script exactly, or the
17
+ # checkpoint's state_dict won't line up with the module structure.
18
+ # ---------------------------------------------------------------------------
19
+
20
+ class RMSNorm(nn.Module):
21
+ def __init__(self, dim, eps=1e-6):
22
+ super().__init__()
23
+ self.weight = nn.Parameter(torch.ones(dim))
24
+ self.eps = eps
25
+ def forward(self, x):
26
+ return x * torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps) * self.weight
27
+
28
+ def rope_cache(seq_len, head_dim, device, dtype):
29
+ inv_freq = 1.0 / (10000 ** (torch.arange(0, head_dim, 2, device=device, dtype=torch.float32) / head_dim))
30
+ pos = torch.arange(seq_len, device=device, dtype=torch.float32)
31
+ freqs = torch.outer(pos, inv_freq)
32
+ cos = freqs.cos().to(dtype=dtype)[None, None, :, :]
33
+ sin = freqs.sin().to(dtype=dtype)[None, None, :, :]
34
+ return cos, sin
35
+
36
+ def apply_rope(x, cos, sin):
37
+ x1 = x[..., ::2]
38
+ x2 = x[..., 1::2]
39
+ out = torch.empty_like(x)
40
+ out[..., ::2] = x1 * cos - x2 * sin
41
+ out[..., 1::2] = x1 * sin + x2 * cos
42
+ return out
43
+
44
+ class CausalSelfAttention(nn.Module):
45
+ def __init__(self, dim, n_head, dropout):
46
+ super().__init__()
47
+ assert dim % n_head == 0
48
+ self.n_head = n_head
49
+ self.head_dim = dim // n_head
50
+ assert self.head_dim % 2 == 0
51
+ self.qkv = nn.Linear(dim, 3 * dim)
52
+ self.proj = nn.Linear(dim, dim)
53
+ self.dropout = dropout
54
+ def forward(self, x):
55
+ B, T, C = x.shape
56
+ q, k, v = self.qkv(x).chunk(3, dim=-1)
57
+ q = q.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
58
+ k = k.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
59
+ v = v.view(B, T, self.n_head, self.head_dim).transpose(1, 2)
60
+ cos, sin = rope_cache(T, self.head_dim, x.device, x.dtype)
61
+ q = apply_rope(q, cos, sin)
62
+ k = apply_rope(k, cos, sin)
63
+ if hasattr(F, "scaled_dot_product_attention"):
64
+ a = F.scaled_dot_product_attention(q, k, v, dropout_p=0.0, is_causal=True)
65
+ else:
66
+ att = (q @ k.transpose(-2, -1)) / math.sqrt(self.head_dim)
67
+ mask = torch.triu(torch.ones(T, T, device=x.device, dtype=torch.bool), diagonal=1)
68
+ att = att.masked_fill(mask, float("-inf"))
69
+ att = F.softmax(att, dim=-1)
70
+ a = att @ v
71
+ a = a.transpose(1, 2).contiguous().view(B, T, C)
72
+ return self.proj(a)
73
+
74
+ class SwiGLU(nn.Module):
75
+ def __init__(self, dim, dropout):
76
+ super().__init__()
77
+ hidden = 4 * dim
78
+ self.fc = nn.Linear(dim, hidden * 2)
79
+ self.proj = nn.Linear(hidden, dim)
80
+ self.drop = nn.Dropout(dropout)
81
+ def forward(self, x):
82
+ x1, x2 = self.fc(x).chunk(2, dim=-1)
83
+ return self.drop(self.proj(F.silu(x1) * x2))
84
+
85
+ class Block(nn.Module):
86
+ def __init__(self, dim, n_head, dropout):
87
+ super().__init__()
88
+ self.n1 = RMSNorm(dim)
89
+ self.attn = CausalSelfAttention(dim, n_head, dropout)
90
+ self.n2 = RMSNorm(dim)
91
+ self.mlp = SwiGLU(dim, dropout)
92
+ def forward(self, x):
93
+ x = x + self.attn(self.n1(x))
94
+ x = x + self.mlp(self.n2(x))
95
+ return x
96
+
97
+ class GPT(nn.Module):
98
+ def __init__(self, vocab_size, block_size, n_layer, n_head, n_embd, dropout=0.0):
99
+ super().__init__()
100
+ self.block_size = block_size
101
+ self.tok_emb = nn.Embedding(vocab_size, n_embd)
102
+ self.drop = nn.Dropout(dropout)
103
+ self.blocks = nn.ModuleList([Block(n_embd, n_head, dropout) for _ in range(n_layer)])
104
+ self.norm_f = RMSNorm(n_embd)
105
+ self.lm_head = nn.Linear(n_embd, vocab_size, bias=False)
106
+ self.lm_head.weight = self.tok_emb.weight
107
+ def forward(self, idx):
108
+ B, T = idx.shape
109
+ if T > self.block_size:
110
+ idx = idx[:, -self.block_size:]
111
+ x = self.tok_emb(idx)
112
+ x = self.drop(x)
113
+ for block in self.blocks:
114
+ x = block(x)
115
+ x = self.norm_f(x)
116
+ logits = self.lm_head(x)
117
+ return logits
118
+
119
+ def get_stop_ids(sp):
120
+ ids = set()
121
+ for piece in ("<|user|>", "<|system|>"):
122
+ pid = sp.piece_to_id(piece)
123
+ if pid != sp.unk_id():
124
+ ids.add(pid)
125
+ return ids
126
+
127
+ DEFAULT_CONFIG = {
128
+ "vocab_size": 32000,
129
+ "block_size": 512,
130
+ "n_layer": 10,
131
+ "n_head": 8,
132
+ "n_embd": 576,
133
+ }
134
+
135
+
136
+ def pick_device():
137
+ if torch.cuda.is_available():
138
+ return torch.device("cuda")
139
+ if torch.backends.mps.is_available():
140
+ return torch.device("mps")
141
+ return torch.device("cpu")
142
+
143
+ _MODULE_DIR = Path(__file__).resolve().parent
144
+
145
+ DEFAULT_CKPT = _MODULE_DIR / "qWisp-base-v1.pt"
146
+ DEFAULT_TOKENIZER = _MODULE_DIR / "qWisp.model"
147
+
148
+ class Wisp:
149
+ def __init__(self):
150
+ self.device = pick_device()
151
+ self.model = None
152
+ self.tokenizer = None
153
+ self.stop_ids = None
154
+ self.config = DEFAULT_CONFIG.copy()
155
+
156
+ def load(
157
+ self,
158
+ ckpt=str(DEFAULT_CKPT),
159
+ tokenizer=str(DEFAULT_TOKENIZER),
160
+ device=None,
161
+ ):
162
+ if device is not None:
163
+ self.device = torch.device(device)
164
+
165
+ self.tokenizer = spm.SentencePieceProcessor()
166
+ self.tokenizer.load(tokenizer)
167
+
168
+ self.model = GPT(
169
+ vocab_size=self.config["vocab_size"],
170
+ block_size=self.config["block_size"],
171
+ n_layer=self.config["n_layer"],
172
+ n_head=self.config["n_head"],
173
+ n_embd=self.config["n_embd"],
174
+ dropout=0.0,
175
+ )
176
+
177
+ obj = torch.load(ckpt, map_location=self.device)
178
+
179
+ state_dict = obj["model"] if isinstance(obj, dict) and "model" in obj else obj
180
+
181
+ self.model.load_state_dict(state_dict, strict=True)
182
+ self.model.to(self.device)
183
+ self.model.eval()
184
+
185
+ self.stop_ids = get_stop_ids(self.tokenizer)
186
+
187
+ return self
188
+
189
+ def unload(self):
190
+ self.model = None
191
+ self.tokenizer = None
192
+ self.stop_ids = None
193
+
194
+ if torch.cuda.is_available():
195
+ torch.cuda.empty_cache()
196
+
197
+ def encode(self, text):
198
+ if self.tokenizer is None:
199
+ raise RuntimeError("Model not loaded.")
200
+ return self.tokenizer.encode(text, out_type=int)
201
+
202
+ def decode(self, ids):
203
+ if self.tokenizer is None:
204
+ raise RuntimeError("Model not loaded.")
205
+ return self.tokenizer.decode(ids)
206
+
207
+ @torch.no_grad()
208
+ def generate(
209
+ self,
210
+ prompt,
211
+ max_new_tokens=200,
212
+ temperature=0.8,
213
+ top_k=50,
214
+ ):
215
+ if self.model is None:
216
+ raise RuntimeError("Model not loaded.")
217
+
218
+ ids = self.tokenizer.encode(prompt, out_type=int)
219
+
220
+ if len(ids) == 0:
221
+ ids = [self.tokenizer.bos_id()]
222
+
223
+ x = torch.tensor([ids], dtype=torch.long, device=self.device)
224
+
225
+ self.model.eval()
226
+
227
+ for _ in range(max_new_tokens):
228
+ x_cond = x[:, -self.model.block_size :]
229
+ logits = self.model(x_cond)
230
+ logits = logits[:, -1] / max(temperature, 1e-6)
231
+
232
+ if top_k is not None and top_k > 0:
233
+ values, _ = torch.topk(logits, min(top_k, logits.size(-1)))
234
+ logits = torch.where(
235
+ logits < values[:, [-1]],
236
+ torch.full_like(logits, float("-inf")),
237
+ logits,
238
+ )
239
+
240
+ probs = F.softmax(logits, dim=-1)
241
+
242
+ next_token = torch.multinomial(probs, 1)
243
+ token = int(next_token.item())
244
+
245
+ if token == self.tokenizer.eos_id() or token in self.stop_ids:
246
+ break
247
+
248
+ x = torch.cat((x, next_token), dim=1)
249
+
250
+ return self.tokenizer.decode(x[0].tolist())
251
+
252
+ def chat(
253
+ self,
254
+ message,
255
+ max_new_tokens=200,
256
+ temperature=0.8,
257
+ top_k=50,
258
+ syspr="Answer to what user have said."
259
+ ):
260
+ prompt = f"<|system|> {syspr}\n<|user|> {message}\n<|assistant|>"
261
+ return self.generate(
262
+ prompt,
263
+ max_new_tokens=max_new_tokens,
264
+ temperature=temperature,
265
+ top_k=top_k,
266
+ )
267
+
268
+ def __call__(
269
+ self,
270
+ message,
271
+ max_new_tokens=200,
272
+ temperature=0.8,
273
+ top_k=50,
274
+ ):
275
+ return self.chat(
276
+ message,
277
+ max_new_tokens=max_new_tokens,
278
+ temperature=temperature,
279
+ top_k=top_k,
280
+ )
281
+
282
+ def __repr__(self):
283
+ loaded = self.model is not None
284
+ return (
285
+ f"Wisp("
286
+ f"loaded={loaded}, "
287
+ f"device='{self.device}', "
288
+ f"layers={self.config['n_layer']}, "
289
+ f"hidden={self.config['n_embd']}, "
290
+ f"vocab={self.config['vocab_size']}"
291
+ f")"
292
+ )
qwisp/__pycache__/__init__.cpython-313.pyc ADDED
Binary file (16.8 kB). View file
 
qwisp/qWisp-base-v1.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:478b9f78c6c210aa9bcf765135adc414d84ceec32f0b3ce5644024e221a3cf4f
3
+ size 286450027
qwisp/qWisp.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:777da9dd588e01e213044aa2382a078996cfd0c03aa2fa34e219a27af87f9986
3
+ size 768897
qwisp/qWisp.vocab ADDED
The diff for this file is too large to render. See raw diff