Spaces:
Running
Running
Murali Chandran commited on
Commit ·
dd2fdf7
1
Parent(s): ea24b46
Add exact vocab.json (95 tokens); align model param names; add guard
Browse files- bot_model.py +24 -24
- export_vocab.py +137 -0
bot_model.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
|
|
| 1 |
import math
|
| 2 |
import torch
|
| 3 |
import torch.nn as nn
|
|
@@ -9,51 +10,50 @@ class CausalSelfAttention(nn.Module):
|
|
| 9 |
assert d_model % num_heads == 0
|
| 10 |
self.num_heads = num_heads
|
| 11 |
self.d_k = d_model // num_heads
|
| 12 |
-
|
| 13 |
-
self.
|
| 14 |
-
self.
|
| 15 |
-
self.
|
| 16 |
-
self.
|
|
|
|
| 17 |
|
| 18 |
def forward(self, x):
|
| 19 |
B, T, C = x.size()
|
| 20 |
-
q = self.
|
| 21 |
-
k = self.
|
| 22 |
-
v = self.
|
| 23 |
-
att = (q @ k.transpose(-2,-1)) / math.sqrt(self.d_k)
|
| 24 |
mask = torch.tril(torch.ones(T, T, device=x.device))
|
| 25 |
-
att = att.masked_fill(mask==0, float('-inf'))
|
| 26 |
att = F.softmax(att, dim=-1)
|
| 27 |
-
att = self.
|
| 28 |
y = att @ v
|
| 29 |
-
y = y.transpose(1,2).contiguous().view(B, T, C)
|
| 30 |
-
return self.
|
| 31 |
|
| 32 |
class GPTBlock(nn.Module):
|
| 33 |
-
def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
|
| 34 |
super().__init__()
|
| 35 |
self.ln1 = nn.LayerNorm(d_model)
|
| 36 |
self.attn = CausalSelfAttention(d_model, num_heads, dropout)
|
| 37 |
self.ln2 = nn.LayerNorm(d_model)
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
nn.ReLU(),
|
| 41 |
-
nn.Linear(d_ff, d_model),
|
| 42 |
-
nn.Dropout(dropout)
|
| 43 |
)
|
| 44 |
def forward(self, x):
|
| 45 |
x = x + self.attn(self.ln1(x))
|
| 46 |
-
x = x + self.
|
| 47 |
return x
|
| 48 |
|
| 49 |
class GPT(nn.Module):
|
| 50 |
def __init__(self, vocab_size, d_model=192, num_heads=6, num_layers=4, max_len=320, dropout=0.1):
|
| 51 |
super().__init__()
|
| 52 |
self.token_emb = nn.Embedding(vocab_size, d_model)
|
| 53 |
-
self.pos_emb
|
| 54 |
-
self.blocks
|
| 55 |
-
self.ln_f
|
| 56 |
-
self.head
|
| 57 |
self.cfg = dict(vocab_size=vocab_size, d_model=d_model, num_heads=num_heads, num_layers=num_layers, max_len=max_len, dropout=dropout)
|
| 58 |
|
| 59 |
def forward(self, idx):
|
|
|
|
| 1 |
+
# bot_model.py
|
| 2 |
import math
|
| 3 |
import torch
|
| 4 |
import torch.nn as nn
|
|
|
|
| 10 |
assert d_model % num_heads == 0
|
| 11 |
self.num_heads = num_heads
|
| 12 |
self.d_k = d_model // num_heads
|
| 13 |
+
# NOTE: match checkpoint names exactly
|
| 14 |
+
self.W_q = nn.Linear(d_model, d_model)
|
| 15 |
+
self.W_k = nn.Linear(d_model, d_model)
|
| 16 |
+
self.W_v = nn.Linear(d_model, d_model)
|
| 17 |
+
self.W_o = nn.Linear(d_model, d_model)
|
| 18 |
+
self.dropout = nn.Dropout(dropout)
|
| 19 |
|
| 20 |
def forward(self, x):
|
| 21 |
B, T, C = x.size()
|
| 22 |
+
q = self.W_q(x).view(B, T, self.num_heads, C//self.num_heads).transpose(1, 2)
|
| 23 |
+
k = self.W_k(x).view(B, T, self.num_heads, C//self.num_heads).transpose(1, 2)
|
| 24 |
+
v = self.W_v(x).view(B, T, self.num_heads, C//self.num_heads).transpose(1, 2)
|
| 25 |
+
att = (q @ k.transpose(-2, -1)) / math.sqrt(self.d_k)
|
| 26 |
mask = torch.tril(torch.ones(T, T, device=x.device))
|
| 27 |
+
att = att.masked_fill(mask == 0, float('-inf'))
|
| 28 |
att = F.softmax(att, dim=-1)
|
| 29 |
+
att = self.dropout(att)
|
| 30 |
y = att @ v
|
| 31 |
+
y = y.transpose(1, 2).contiguous().view(B, T, C)
|
| 32 |
+
return self.W_o(y)
|
| 33 |
|
| 34 |
class GPTBlock(nn.Module):
|
| 35 |
+
def __init__(self, d_model, num_heads, d_ff=768, dropout=0.1):
|
| 36 |
super().__init__()
|
| 37 |
self.ln1 = nn.LayerNorm(d_model)
|
| 38 |
self.attn = CausalSelfAttention(d_model, num_heads, dropout)
|
| 39 |
self.ln2 = nn.LayerNorm(d_model)
|
| 40 |
+
# NOTE: match checkpoint module name "ffn"
|
| 41 |
+
self.ffn = nn.Sequential(
|
| 42 |
+
nn.Linear(d_model, d_ff), nn.ReLU(), nn.Linear(d_ff, d_model), nn.Dropout(dropout)
|
|
|
|
|
|
|
| 43 |
)
|
| 44 |
def forward(self, x):
|
| 45 |
x = x + self.attn(self.ln1(x))
|
| 46 |
+
x = x + self.ffn(self.ln2(x))
|
| 47 |
return x
|
| 48 |
|
| 49 |
class GPT(nn.Module):
|
| 50 |
def __init__(self, vocab_size, d_model=192, num_heads=6, num_layers=4, max_len=320, dropout=0.1):
|
| 51 |
super().__init__()
|
| 52 |
self.token_emb = nn.Embedding(vocab_size, d_model)
|
| 53 |
+
self.pos_emb = nn.Embedding(max_len, d_model)
|
| 54 |
+
self.blocks = nn.ModuleList([GPTBlock(d_model, num_heads, 4*d_model, dropout) for _ in range(num_layers)])
|
| 55 |
+
self.ln_f = nn.LayerNorm(d_model)
|
| 56 |
+
self.head = nn.Linear(d_model, vocab_size, bias=False)
|
| 57 |
self.cfg = dict(vocab_size=vocab_size, d_model=d_model, num_heads=num_heads, num_layers=num_layers, max_len=max_len, dropout=dropout)
|
| 58 |
|
| 59 |
def forward(self, idx):
|
export_vocab.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# export_vocab.py
|
| 2 |
+
import json, random
|
| 3 |
+
|
| 4 |
+
# ---- Gen config (must mirror your training script that produced this checkpoint) ----
|
| 5 |
+
EXTRA_CHARSET = (
|
| 6 |
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
| 7 |
+
"abcdefghijklmnopqrstuvwxyz"
|
| 8 |
+
"0123456789"
|
| 9 |
+
" +-*/=?:.,'\"()[]"
|
| 10 |
+
"$£€₹¥₩₦"
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
ITEMS = ["apple","mango","banana","orange","pear","kiwi","pen","notebook","ticket","cookie","product"]
|
| 14 |
+
ASKS = [
|
| 15 |
+
"how much is {n} {item_plural}?",
|
| 16 |
+
"what's the cost of {n} {item_plural}?",
|
| 17 |
+
"price for {n} {item_plural}?",
|
| 18 |
+
"how much would {n} {item_plural} cost?",
|
| 19 |
+
"what do I pay for {n} {item_plural}?",
|
| 20 |
+
"total price of {n} {item_plural}?",
|
| 21 |
+
"what's {n} {item_plural} going to cost?"
|
| 22 |
+
]
|
| 23 |
+
COPULA = ["is", "costs", "priced at", "= ", "comes to", "sells for"]
|
| 24 |
+
|
| 25 |
+
def s(x, w): return w if x == 1 else (w + "s")
|
| 26 |
+
|
| 27 |
+
def money(v: float) -> str:
|
| 28 |
+
return str(int(round(v))) if abs(v - round(v)) < 1e-9 else f"{v:.2f}"
|
| 29 |
+
|
| 30 |
+
CURRENCIES = [
|
| 31 |
+
{"prefix":"$", "name_sing":"dollar", "name_plur":"dollars"},
|
| 32 |
+
{"prefix":"£", "name_sing":"pound", "name_plur":"pounds"},
|
| 33 |
+
{"prefix":"€", "name_sing":"euro", "name_plur":"euros"},
|
| 34 |
+
{"prefix":"₹", "name_sing":"rupee", "name_plur":"rupees"},
|
| 35 |
+
{"prefix":"¥", "name_sing":"yen", "name_plur":"yen"},
|
| 36 |
+
{"prefix":"₩", "name_sing":"won", "name_plur":"won"},
|
| 37 |
+
{"prefix":"₦", "name_sing":"naira", "name_plur":"naira"},
|
| 38 |
+
{"prefix":"A$", "name_sing":"dollar", "name_plur":"dollars"},
|
| 39 |
+
{"prefix":"C$", "name_sing":"dollar", "name_plur":"dollars"},
|
| 40 |
+
{"prefix":"CHF","name_sing":"franc", "name_plur":"francs"},
|
| 41 |
+
{"prefix":"د.إ","name_sing":"dirham", "name_plur":"dirhams"},
|
| 42 |
+
{"prefix":"", "name_sing":"dollar", "name_plur":"dollars"},
|
| 43 |
+
{"prefix":"", "name_sing":"pound", "name_plur":"pounds"},
|
| 44 |
+
{"prefix":"", "name_sing":"rupee", "name_plur":"rupees"},
|
| 45 |
+
{"prefix":"", "name_sing":"euro", "name_plur":"euros"}
|
| 46 |
+
]
|
| 47 |
+
EXTRA_CURRENCY_WORDS = [
|
| 48 |
+
("peso","pesos"), ("dinar","dinars"), ("dirham","dirhams"), ("riyal","riyals"),
|
| 49 |
+
("rial","rials"), ("krona","kronor"), ("krone","kroner"), ("koruna","koruny"),
|
| 50 |
+
("rand","rand"), ("shekel","shekels"), ("lira","lire"), ("ruble","rubles"),
|
| 51 |
+
("rouble","roubles"), ("yuan","yuan"), ("renminbi","renminbi"), ("ringgit","ringgit"),
|
| 52 |
+
("baht","baht"), ("dong","dong"), ("taka","taka"), ("rupiah","rupiah"),
|
| 53 |
+
("shilling","shillings"), ("kuna","kuna"), ("zloty","zlotys"), ("forint","forints"),
|
| 54 |
+
("leu","lei"), ("riel","riel"), ("kyat","kyat"), ("quetzal","quetzales"),
|
| 55 |
+
("bolivar","bolivares"), ("colon","colones"), ("sol","soles")
|
| 56 |
+
]
|
| 57 |
+
SYNTHETIC_CURRENCY_WORDS = [
|
| 58 |
+
("credit","credits"), ("token","tokens"), ("coin","coins"), ("unit","units"),
|
| 59 |
+
("galactic credit","galactic credits"), ("space buck","space bucks")
|
| 60 |
+
]
|
| 61 |
+
WORD_POOL = [{"prefix":"", "name_sing":a, "name_plur":b} for (a,b) in (EXTRA_CURRENCY_WORDS + SYNTHETIC_CURRENCY_WORDS)]
|
| 62 |
+
|
| 63 |
+
# We only need enough samples to surface all characters that occurred in training text
|
| 64 |
+
def cur_str(cur: dict, v: float) -> str:
|
| 65 |
+
if cur["prefix"]:
|
| 66 |
+
return f"{cur['prefix']}{money(v)}"
|
| 67 |
+
name = cur["name_sing"] if abs(v - 1.0) < 1e-9 else cur["name_plur"]
|
| 68 |
+
return f"{money(v)} {name}"
|
| 69 |
+
|
| 70 |
+
def make_addition():
|
| 71 |
+
k = random.randint(2, 6)
|
| 72 |
+
nums = [random.randint(0, 200) for _ in range(k)]
|
| 73 |
+
expr = " + ".join(map(str, nums))
|
| 74 |
+
s_ = sum(nums)
|
| 75 |
+
tail = random.choice(["", " = ?", " = ", "?"])
|
| 76 |
+
return f"q: {expr}{tail} a: step 1: take {nums[0]}. step 2: add {nums[1]}. step 3: {expr} = {s_}. final answer: {s_} <EOS>"
|
| 77 |
+
|
| 78 |
+
def make_subtraction():
|
| 79 |
+
a = random.randint(0,200); b = random.randint(0,a)
|
| 80 |
+
s_ = a - b
|
| 81 |
+
tail = random.choice(["", " = ?", " = ", "?"])
|
| 82 |
+
return f"q: {a} - {b}{tail} a: step 1: take {a}. step 2: subtract {b}. step 3: {a} - {b} = {s_}. final answer: {s_} <EOS>"
|
| 83 |
+
|
| 84 |
+
def make_multiplication():
|
| 85 |
+
a = random.randint(0,50); b = random.randint(0,20)
|
| 86 |
+
s_ = a*b
|
| 87 |
+
tail = random.choice(["", " = ?", " = ", "?"])
|
| 88 |
+
return f"q: {a} × {b}{tail} a: step 1: take {a}. step 2: multiply by {b}. step 3: {a} × {b} = {s_}. final answer: {s_} <EOS>"
|
| 89 |
+
|
| 90 |
+
def make_division():
|
| 91 |
+
b = random.randint(1, 20); qv = random.randint(0, 50); a = b*qv
|
| 92 |
+
tail = random.choice(["", " = ?", " = ", "?"])
|
| 93 |
+
return f"q: {a} ÷ {b}{tail} a: step 1: take {a}. step 2: divide by {b}. step 3: {a} ÷ {b} = {qv}. final answer: {qv} <EOS>"
|
| 94 |
+
|
| 95 |
+
def make_unit_price():
|
| 96 |
+
item = random.choice(ITEMS); qty = random.randint(1, 15)
|
| 97 |
+
unit_price = random.choice([0.39,0.5,0.75,1.2,1.5,2.25,3.4,4.99]) if (random.random()<0.5) else random.randint(1,30)
|
| 98 |
+
cost = unit_price * qty; target = random.randint(1, 30)
|
| 99 |
+
cur = random.choice(CURRENCIES) if random.random() < 0.7 else random.choice(WORD_POOL)
|
| 100 |
+
cop = random.choice(COPULA); ask = random.choice(ASKS)
|
| 101 |
+
if random.random() < 0.5:
|
| 102 |
+
q = f"{qty} {s(qty,item)} {cop} {cur_str(cur,cost)}, {ask.format(n=target, item_plural=s(target,item))}"
|
| 103 |
+
else:
|
| 104 |
+
q = f"{qty} {s(qty,item)} cost {cur_str(cur,cost)}. {ask.format(n=target, item_plural=s(target,item))}"
|
| 105 |
+
unit = cost/qty; total = unit*target
|
| 106 |
+
return f"q: {q} a: step 1: find unit price: {cur_str(cur,cost)} / {qty} = {cur_str(cur,unit)} per {item}. step 2: multiply by {target}: {cur_str(cur,unit)} × {target} = {cur_str(cur,total)}. final answer: {cur_str(cur,total)} <EOS>"
|
| 107 |
+
|
| 108 |
+
def make_group_price():
|
| 109 |
+
item = random.choice(ITEMS); group_qty = random.randint(2, 20)
|
| 110 |
+
price = random.choice([9.0,10.0,12.5,7.2,15.75,19.99,3.3,4.5,21.95]) if (random.random()<0.7) else float(random.randint(2,60))
|
| 111 |
+
target = random.randint(1,40); cur = random.choice(CURRENCIES)
|
| 112 |
+
q = f"{group_qty} {s(group_qty,item)} for {cur_str(cur,price)}, what's the price for {target} {s(target,item)}?"
|
| 113 |
+
unit = price/group_qty; total = unit*target
|
| 114 |
+
return f"q: {q} a: step 1: unit price = {cur_str(cur,price)} / {group_qty} = {cur_str(cur,unit)} per {item}. step 2: total = {cur_str(cur,unit)} × {target} = {cur_str(cur,total)}. final answer: {cur_str(cur,total)} <EOS>"
|
| 115 |
+
|
| 116 |
+
def build_seed_pool():
|
| 117 |
+
pool = []
|
| 118 |
+
for _ in range(200): pool.append(make_addition())
|
| 119 |
+
for _ in range(150): pool.append(make_subtraction())
|
| 120 |
+
for _ in range(150): pool.append(make_multiplication())
|
| 121 |
+
for _ in range(150): pool.append(make_division())
|
| 122 |
+
for _ in range(150): pool.append(make_unit_price())
|
| 123 |
+
for _ in range(100): pool.append(make_group_price())
|
| 124 |
+
random.shuffle(pool)
|
| 125 |
+
return pool
|
| 126 |
+
|
| 127 |
+
if __name__ == "__main__":
|
| 128 |
+
SEED_POOL = build_seed_pool()
|
| 129 |
+
seed_text = "\n".join(SEED_POOL)
|
| 130 |
+
base_chars = sorted(set(seed_text) | set(EXTRA_CHARSET))
|
| 131 |
+
# IMPORTANT: the older checkpoint DID NOT include <EOS> in the vocab
|
| 132 |
+
SPECIAL = ["<PAD>", "<UNK>"]
|
| 133 |
+
itos_list = SPECIAL + base_chars
|
| 134 |
+
print("len(itos) =", len(itos_list))
|
| 135 |
+
with open("vocab.json", "w", encoding="utf-8") as f:
|
| 136 |
+
json.dump({"itos": itos_list}, f, ensure_ascii=False, indent=2)
|
| 137 |
+
print("Wrote vocab.json")
|