cfahlgren1 HF Staff commited on
Commit
b4c1c55
·
verified ·
1 Parent(s): cfe9bcc

keep only the shipped model and remove earlier training runs

Browse files
train_realword.py ADDED
@@ -0,0 +1,506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # /// script
2
+ # requires-python = ">=3.11,<3.14"
3
+ # dependencies = [
4
+ # "torch>=2.6,<2.8",
5
+ # "datasets>=3.0",
6
+ # "numpy<3",
7
+ # "onnx>=1.17",
8
+ # "onnxruntime>=1.20",
9
+ # "huggingface_hub>=0.30",
10
+ # ]
11
+ # ///
12
+ """Train a small model that spots correctly spelled wrong words, like "don" typed for "do"."""
13
+
14
+ import argparse
15
+ import hashlib
16
+ import json
17
+ import os
18
+ import re
19
+ import time
20
+ import urllib.request
21
+ from collections import Counter, defaultdict
22
+ from pathlib import Path
23
+
24
+ import numpy as np
25
+ import onnxruntime as ort
26
+ import torch
27
+ import torch.nn as nn
28
+ import torch.nn.functional as F
29
+ from datasets import load_dataset
30
+ from huggingface_hub import HfApi
31
+ from onnxruntime.quantization import QuantType, quantize_dynamic
32
+
33
+ LEFT_WINDOW = 16
34
+ RIGHT_WINDOW = 4
35
+ MAX_NEIGHBORS = 8
36
+ CANDIDATES = MAX_NEIGHBORS + 1
37
+ MIN_TYPED_LENGTH = 3
38
+
39
+ PAD, UNK, NUMBER, START, NAME = 0, 1, 2, 3, 4
40
+ SPECIAL_TOKENS = ["<pad>", "<unk>", "<num>", "<s>", "<name>"]
41
+
42
+ REAL_MISTAKE_SHARE = 0.6
43
+ HOMOPHONE_WEIGHT = 20
44
+ MIN_REAL_MISTAKE_COUNT = 2
45
+ HOMOPHONES = [
46
+ ("their", "there", "they're"), ("your", "you're"), ("its", "it's"), ("too", "two"), ("then", "than"),
47
+ ("were", "where", "we're"), ("whose", "who's"), ("hear", "here"), ("buy", "bye"), ("weather", "whether"),
48
+ ("peace", "piece"), ("affect", "effect"), ("lose", "loose"), ("accept", "except"), ("advice", "advise"),
49
+ ("quiet", "quite"), ("through", "though", "thorough"), ("passed", "past"), ("principal", "principle"),
50
+ ("complement", "compliment"), ("brake", "break"), ("waist", "waste"), ("right", "write"), ("sight", "site", "cite"),
51
+ ("wear", "where"), ("led", "lead"), ("meet", "meat"), ("week", "weak"), ("wood", "would"), ("hole", "whole"),
52
+ ("male", "mail"), ("sale", "sell"), ("role", "roll"), ("aloud", "allowed"), ("board", "bored"), ("fair", "fare"),
53
+ ]
54
+ TYPO_PAIRS_DATASET = "chirunder/github_typo_corrections"
55
+
56
+ WORD_LIST_URL = "https://raw.githubusercontent.com/wolfgarbe/SymSpell/master/SymSpell.FrequencyDictionary/en-80k.txt"
57
+ TOKEN = re.compile(r"[A-Za-z]+(?:'[A-Za-z]+)?|\d+(?:[.,]\d+)*|[^\s\w]")
58
+ SENTENCE_OPENERS = {".", "!", "?", ":", '"'}
59
+ WORD = re.compile(r"^[a-z]+(?:'[a-z]+)?$")
60
+ DIGITS = re.compile(r"^\d")
61
+
62
+
63
+ def tokenize(text: str) -> list[str]:
64
+ """Lowercases words, except capitalized words mid-sentence, which become a single name token."""
65
+ tokens = []
66
+ for raw in TOKEN.findall(text.replace("’", "'")):
67
+ at_sentence_start = not tokens or tokens[-1] in SENTENCE_OPENERS
68
+ is_pronoun = raw == "I" or raw.startswith("I'")
69
+ tokens.append("<name>" if raw[0].isupper() and not at_sentence_start and not is_pronoun else raw.lower())
70
+ return tokens
71
+
72
+
73
+ def fineweb_documents():
74
+ stream = load_dataset("HuggingFaceFW/fineweb-edu", split="train", streaming=True).shuffle(seed=7, buffer_size=20000)
75
+ for row in stream:
76
+ yield row["text"]
77
+
78
+
79
+ def smoltalk_documents():
80
+ stream = load_dataset("HuggingFaceTB/smoltalk", "all", split="train", streaming=True).shuffle(seed=7, buffer_size=20000)
81
+ for row in stream:
82
+ yield "\n".join(message["content"] for message in row["messages"] if message["role"] != "system")
83
+
84
+
85
+ def open_assistant_documents():
86
+ for row in load_dataset("OpenAssistant/oasst1", split="train"):
87
+ if row["lang"] == "en":
88
+ yield row["text"]
89
+
90
+
91
+ def load_corpus(token_budgets: dict[str, int]) -> tuple[list[np.ndarray], dict[str, int]]:
92
+ sources = {"fineweb": fineweb_documents, "smoltalk": smoltalk_documents, "oasst": open_assistant_documents}
93
+ raw_ids = {"<s>": 0}
94
+ documents = []
95
+ for name, budget in token_budgets.items():
96
+ started, used = time.time(), 0
97
+ for text in sources[name]():
98
+ tokens = tokenize(text)
99
+ if len(tokens) < 8:
100
+ continue
101
+ documents.append(np.array([0] + [raw_ids.setdefault(token, len(raw_ids)) for token in tokens], dtype=np.int32))
102
+ used += len(tokens)
103
+ if used >= budget:
104
+ break
105
+ print(f"{name}: {used:,} tokens in {time.time() - started:.0f}s", flush=True)
106
+ return documents, raw_ids
107
+
108
+
109
+ def build_vocabulary(documents: list[np.ndarray], raw_ids: dict[str, int], size: int) -> tuple[list[str], np.ndarray]:
110
+ with urllib.request.urlopen(WORD_LIST_URL) as response:
111
+ dictionary = {line.split()[0] for line in response.read().decode().splitlines() if line.strip()}
112
+ counts = np.bincount(np.concatenate(documents), minlength=len(raw_ids))
113
+ allowed = [(token, identifier) for token, identifier in raw_ids.items() if (WORD.match(token) and token in dictionary) or (len(token) == 1 and not token.isalnum())]
114
+ allowed = [pair for pair in allowed if pair[0] != "<s>"]
115
+ allowed.sort(key=lambda pair: (-counts[pair[1]], pair[0]))
116
+ vocabulary = SPECIAL_TOKENS + [token for token, _ in allowed[: size - len(SPECIAL_TOKENS)]]
117
+
118
+ token_to_id = {token: index for index, token in enumerate(vocabulary)}
119
+ lookup = np.full(len(raw_ids), UNK, dtype=np.int32)
120
+ for token, identifier in raw_ids.items():
121
+ if token == "<s>":
122
+ lookup[identifier] = START
123
+ elif token == "<name>":
124
+ lookup[identifier] = NAME
125
+ elif DIGITS.match(token):
126
+ lookup[identifier] = NUMBER
127
+ elif token in token_to_id:
128
+ lookup[identifier] = token_to_id[token]
129
+ return vocabulary, lookup
130
+
131
+
132
+ def is_target_word(token: str) -> bool:
133
+ return len(token) >= 2 and token not in SPECIAL_TOKENS and WORD.match(token) is not None
134
+
135
+
136
+ def within_one_edit(first: str, second: str) -> bool:
137
+ if first == second or abs(len(first) - len(second)) > 1:
138
+ return False
139
+ if len(first) == len(second):
140
+ differences = [index for index, (a, b) in enumerate(zip(first, second)) if a != b]
141
+ if len(differences) == 1:
142
+ return True
143
+ return len(differences) == 2 and differences[1] == differences[0] + 1 and first[differences[0]] == second[differences[1]] and first[differences[1]] == second[differences[0]]
144
+ shorter, longer = sorted((first, second), key=len)
145
+ return any(longer[:index] + longer[index + 1 :] == shorter for index in range(len(longer)))
146
+
147
+
148
+ def strip_punctuation(token: str) -> str:
149
+ return token.strip("\"'()[]{}<>.,;:!?*_`#-=/\\")
150
+
151
+
152
+ def real_mistakes_for_training(vocabulary: set[str]) -> Counter:
153
+ """Counts real typed-for-expected word swaps, using only the half of the dev split that eval doesn't tune on."""
154
+ counts = Counter()
155
+ for row in load_dataset(TYPO_PAIRS_DATASET, split="train"):
156
+ typed_tokens, fixed_tokens = (row["text"] or "").split(), (row["correction"] or "").split()
157
+ if len(typed_tokens) != len(fixed_tokens):
158
+ continue
159
+ different = [index for index, (first, second) in enumerate(zip(typed_tokens, fixed_tokens)) if first != second]
160
+ if len(different) != 1:
161
+ continue
162
+ typed, expected = strip_punctuation(typed_tokens[different[0]]), strip_punctuation(fixed_tokens[different[0]])
163
+ digest = int(hashlib.sha1(f"{typed}|{expected}".lower().encode()).hexdigest(), 16)
164
+ if digest % 2 != 0 or (digest >> 1) % 2 != 0:
165
+ continue
166
+ typed, expected = typed.lower(), expected.lower()
167
+ if typed != expected and len(typed) >= MIN_TYPED_LENGTH and typed in vocabulary and expected in vocabulary and is_target_word(typed) and is_target_word(expected):
168
+ counts[(typed, expected)] += 1
169
+ return Counter({pair: count for pair, count in counts.items() if count >= MIN_REAL_MISTAKE_COUNT})
170
+
171
+
172
+ def build_confusions(vocabulary: list[str], use_real_mistakes: bool) -> dict[str, list[tuple[str, int]]]:
173
+ """Maps a typed word to words people really meant by it, most likely first."""
174
+ known = set(vocabulary)
175
+ counts = real_mistakes_for_training(known) if use_real_mistakes else Counter()
176
+ print(f"real mistake pairs={len(counts):,}", flush=True)
177
+ for group in HOMOPHONES:
178
+ for typed in group:
179
+ for expected in group:
180
+ if typed != expected and typed in known and expected in known and len(typed) >= MIN_TYPED_LENGTH:
181
+ counts[(typed, expected)] += HOMOPHONE_WEIGHT
182
+ confusions = defaultdict(list)
183
+ for (typed, expected), count in sorted(counts.items(), key=lambda item: (-item[1], item[0])):
184
+ confusions[typed].append((expected, count))
185
+ return {typed: options[:MAX_NEIGHBORS] for typed, options in confusions.items()}
186
+
187
+
188
+ def build_real_mistake_tables(vocabulary: list[str], confusions: dict[str, list[tuple[str, int]]]) -> tuple[np.ndarray, np.ndarray]:
189
+ """For each intended word, lists the words typed by mistake and how often, for sampling."""
190
+ token_to_id = {token: index for index, token in enumerate(vocabulary)}
191
+ mistakes = defaultdict(list)
192
+ for typed, options in confusions.items():
193
+ for expected, count in options:
194
+ mistakes[token_to_id[expected]].append((token_to_id[typed], count))
195
+ typed_table = np.zeros((len(vocabulary), MAX_NEIGHBORS), dtype=np.int32)
196
+ weights = np.zeros((len(vocabulary), MAX_NEIGHBORS), dtype=np.float32)
197
+ for expected, options in mistakes.items():
198
+ options = sorted(options, key=lambda option: -option[1])[:MAX_NEIGHBORS]
199
+ typed_table[expected, : len(options)] = [typed for typed, _ in options]
200
+ weights[expected, : len(options)] = [count**0.5 for _, count in options]
201
+ return typed_table, weights
202
+
203
+
204
+ def build_neighbors(vocabulary: list[str], confusions: dict[str, list[tuple[str, int]]]) -> np.ndarray:
205
+ """Lists known mix-ups first, then the most common words one edit away, the same order the browser uses."""
206
+ token_to_id = {token: index for index, token in enumerate(vocabulary)}
207
+ buckets = defaultdict(set)
208
+ for index, token in enumerate(vocabulary):
209
+ if not is_target_word(token):
210
+ continue
211
+ buckets[token].add(index)
212
+ for position in range(len(token)):
213
+ buckets[token[:position] + token[position + 1 :]].add(index)
214
+
215
+ table = np.zeros((len(vocabulary), MAX_NEIGHBORS), dtype=np.int32)
216
+ for index, token in enumerate(vocabulary):
217
+ if not is_target_word(token):
218
+ continue
219
+ nearby = set(buckets[token])
220
+ for position in range(len(token)):
221
+ nearby |= buckets[token[:position] + token[position + 1 :]]
222
+ one_edit = sorted(other for other in nearby if within_one_edit(token, vocabulary[other]))
223
+ known_mixups = [token_to_id[expected] for expected, _ in confusions.get(token, [])]
224
+ found = list(dict.fromkeys(known_mixups + one_edit))
225
+ table[index, : min(len(found), MAX_NEIGHBORS)] = found[:MAX_NEIGHBORS]
226
+ return table
227
+
228
+
229
+ class MatMulLinear(nn.Module):
230
+ """Linear layer that exports as MatMul so ONNX Runtime dynamic quantization applies."""
231
+
232
+ def __init__(self, inputs: int, outputs: int):
233
+ super().__init__()
234
+ self.weight = nn.Parameter(nn.init.xavier_uniform_(torch.empty(inputs, outputs)))
235
+ self.bias = nn.Parameter(torch.zeros(outputs))
236
+
237
+ def forward(self, values):
238
+ return values.matmul(self.weight) + self.bias
239
+
240
+
241
+ class Gru(nn.Module):
242
+ """GRU built from MatMul layers because ONNX Runtime cannot quantize its GRU operator."""
243
+
244
+ def __init__(self, inputs: int, hidden: int):
245
+ super().__init__()
246
+ self.hidden = hidden
247
+ self.reset_gate = MatMulLinear(inputs + hidden, hidden)
248
+ self.update_gate = MatMulLinear(inputs + hidden, hidden)
249
+ self.proposal_input = MatMulLinear(inputs, hidden)
250
+ self.proposal_state = MatMulLinear(hidden, hidden)
251
+
252
+ def forward(self, sequence):
253
+ state = sequence[:, 0, :].sum(-1, keepdim=True).mul(0).repeat(1, self.hidden)
254
+ for step in range(sequence.shape[1]):
255
+ current = sequence[:, step, :]
256
+ joined = torch.cat([current, state], dim=-1)
257
+ reset = torch.sigmoid(self.reset_gate(joined))
258
+ update = torch.sigmoid(self.update_gate(joined))
259
+ proposal = torch.tanh(self.proposal_input(current) + reset * self.proposal_state(state))
260
+ state = (1 - update) * proposal + update * state
261
+ return state
262
+
263
+
264
+ class WrongWordModel(nn.Module):
265
+ """Scores the typed word and its neighbors against the words on both sides."""
266
+
267
+ def __init__(self, vocabulary_size: int, embedding: int, hidden: int):
268
+ super().__init__()
269
+ self.embedding = nn.Embedding(vocabulary_size, embedding, padding_idx=PAD)
270
+ self.word_bias = nn.Embedding(vocabulary_size, 1, padding_idx=PAD)
271
+ self.left = Gru(embedding, hidden)
272
+ self.right = Gru(embedding, hidden)
273
+ self.mix = MatMulLinear(hidden * 2, hidden)
274
+ self.project = MatMulLinear(hidden, embedding)
275
+ self.typed_bonus = nn.Parameter(torch.tensor(1.0))
276
+ self.register_buffer("typed_position", F.one_hot(torch.tensor(0), CANDIDATES).float())
277
+
278
+ def forward(self, left, right, candidates):
279
+ context = torch.cat([self.left(self.embedding(left)), self.right(self.embedding(right))], dim=-1)
280
+ summary = self.project(torch.tanh(self.mix(context)))
281
+ scores = (self.embedding(candidates) * summary.unsqueeze(1)).sum(-1) + self.word_bias(candidates).squeeze(-1)
282
+ return scores + self.typed_bonus * self.typed_position
283
+
284
+
285
+ class Sampler:
286
+ """Draws training cases by swapping real words for nearby real words."""
287
+
288
+ def __init__(self, tokens: torch.Tensor, vocabulary: list[str], neighbors: np.ndarray, real_typed: np.ndarray, real_weights: np.ndarray, device: str):
289
+ self.tokens = tokens
290
+ self.device = device
291
+ self.vocabulary = vocabulary
292
+ self.neighbor_table = neighbors
293
+ self.real_typed_table = real_typed
294
+ self.real_weights_table = real_weights
295
+ self.real_typed = torch.from_numpy(real_typed).to(device).long()
296
+ self.real_weights = torch.from_numpy(real_weights).to(device)
297
+ self.has_real = self.real_weights.sum(1) > 0
298
+ self.neighbors = torch.from_numpy(neighbors).to(device).long()
299
+ self.neighbor_counts = (self.neighbors != PAD).sum(1)
300
+ self.lengths = torch.tensor([len(token) for token in vocabulary], device=device)
301
+ self.is_target = torch.tensor([is_target_word(token) for token in vocabulary], device=device)
302
+
303
+ def batch(self, size: int, corrupt_rate: float):
304
+ positions = torch.randint(LEFT_WINDOW + 1, len(self.tokens) - RIGHT_WINDOW - 1, (size,), device=self.device)
305
+ target = self.tokens[positions]
306
+ counts = self.neighbor_counts[target]
307
+ choice = (torch.rand(size, device=self.device) * counts.clamp(min=1)).long()
308
+ corrupted = self.neighbors[target, choice]
309
+ weights = self.real_weights[target]
310
+ weights = weights.where(self.has_real[target].unsqueeze(1), torch.ones_like(weights))
311
+ real_choice = torch.multinomial(weights, 1).squeeze(1)
312
+ uses_real = self.has_real[target] & (torch.rand(size, device=self.device) < REAL_MISTAKE_SHARE)
313
+ corrupted = torch.where(uses_real, self.real_typed[target, real_choice], corrupted)
314
+ counts = counts.where(~uses_real, torch.ones_like(counts))
315
+ is_corrupted = (torch.rand(size, device=self.device) < corrupt_rate) & (counts > 0)
316
+ typed = torch.where(is_corrupted, corrupted, target)
317
+ candidates = torch.cat([typed.unsqueeze(1), self.neighbors[typed]], dim=1)
318
+ matches = candidates == target.unsqueeze(1)
319
+ valid = self.is_target[target] & (self.lengths[typed] >= MIN_TYPED_LENGTH) & (self.neighbor_counts[typed] > 0) & matches.any(1)
320
+
321
+ positions, candidates, matches, is_corrupted = positions[valid], candidates[valid], matches[valid], is_corrupted[valid]
322
+ count = len(positions)
323
+ left_offsets = torch.arange(-LEFT_WINDOW, 0, device=self.device)
324
+ left = self.tokens[positions.unsqueeze(1) + left_offsets]
325
+ right = self.tokens[positions.unsqueeze(1) + torch.arange(1, RIGHT_WINDOW + 1, device=self.device)]
326
+
327
+ visible_right = torch.randint(0, RIGHT_WINDOW + 1, (count,), device=self.device).unsqueeze(1)
328
+ right = right.where(torch.arange(RIGHT_WINDOW, device=self.device).unsqueeze(0) < visible_right, torch.tensor(PAD, device=self.device)).flip(1)
329
+
330
+ is_short = torch.rand(count, device=self.device) < 0.2
331
+ kept = torch.randint(0, LEFT_WINDOW, (count,), device=self.device).unsqueeze(1)
332
+ distance_from_end = (-left_offsets).unsqueeze(0)
333
+ hidden_left = is_short.unsqueeze(1) & (distance_from_end > kept + 1)
334
+ marks_start = is_short.unsqueeze(1) & (distance_from_end == kept + 1)
335
+ left = left.where(~hidden_left, torch.tensor(PAD, device=self.device)).where(~marks_start, torch.tensor(START, device=self.device))
336
+ return left, right, candidates, matches.long().argmax(1), is_corrupted
337
+
338
+
339
+ def mask_empty(scores, candidates):
340
+ return scores.where(candidates != PAD, torch.tensor(-1e4, device=scores.device))
341
+
342
+
343
+ @torch.no_grad()
344
+ def evaluate(model, sampler, batches: int, batch_size: int) -> dict:
345
+ model.eval()
346
+ clean_margins, corrupted_margins, corrupted_right = [], [], []
347
+ for _ in range(batches):
348
+ left, right, candidates, label, is_corrupted = sampler.batch(batch_size, 0.5)
349
+ scores = mask_empty(model(left, right, candidates), candidates)
350
+ best = scores[:, 1:].max(1)
351
+ margin = best.values - scores[:, 0]
352
+ clean_margins.append(margin[~is_corrupted])
353
+ corrupted_margins.append(margin[is_corrupted])
354
+ corrupted_right.append(best.indices[is_corrupted] + 1 == label[is_corrupted])
355
+ model.train()
356
+ clean = torch.cat(clean_margins)
357
+ margin = torch.cat(corrupted_margins)
358
+ right = torch.cat(corrupted_right)
359
+ results = {"clean_cases": len(clean), "corrupted_cases": len(margin)}
360
+ for false_rate in (0.005, 0.001, 0.0005):
361
+ threshold = torch.quantile(clean[:200000].float(), 1 - false_rate).item()
362
+ results[f"caught_at_false_{false_rate}"] = round(((margin >= threshold) & right).float().mean().item(), 4)
363
+ results[f"threshold_at_false_{false_rate}"] = round(threshold, 2)
364
+ return results
365
+
366
+
367
+ def export_onnx(model: WrongWordModel, output: Path, sampler: Sampler) -> dict:
368
+ model = model.cpu().eval()
369
+ float_path = output / "model.onnx"
370
+ example = (torch.ones(2, LEFT_WINDOW, dtype=torch.long), torch.ones(2, RIGHT_WINDOW, dtype=torch.long), torch.ones(2, CANDIDATES, dtype=torch.long))
371
+ torch.onnx.export(
372
+ model,
373
+ example,
374
+ float_path,
375
+ input_names=["left", "right", "candidates"],
376
+ output_names=["scores"],
377
+ dynamic_axes={"left": {0: "batch"}, "right": {0: "batch"}, "candidates": {0: "batch"}, "scores": {0: "batch"}},
378
+ opset_version=17,
379
+ dynamo=False,
380
+ )
381
+ quantized = {
382
+ "model_quint8.onnx": ["MatMul", "Gather"],
383
+ "model_matmul_quint8.onnx": ["MatMul"],
384
+ }
385
+ for name, operators in quantized.items():
386
+ quantize_dynamic(float_path, output / name, weight_type=QuantType.QUInt8, op_types_to_quantize=operators)
387
+
388
+ sampler_cpu = Sampler(sampler.tokens.cpu(), sampler.vocabulary, sampler.neighbor_table, sampler.real_typed_table, sampler.real_weights_table, "cpu")
389
+ left, right, candidates, label, _ = sampler_cpu.batch(4096, 0.5)
390
+ inputs = {"left": left.numpy().astype(np.int64), "right": right.numpy().astype(np.int64), "candidates": candidates.numpy().astype(np.int64)}
391
+ with torch.no_grad():
392
+ reference = model(left, right, candidates).numpy()
393
+
394
+ def run(path: Path) -> np.ndarray:
395
+ return ort.InferenceSession(str(path), providers=["CPUExecutionProvider"]).run(None, inputs)[0]
396
+
397
+ def margins(scores: np.ndarray) -> np.ndarray:
398
+ scores = np.where(inputs["candidates"] != PAD, scores, -1e4)
399
+ return scores[:, 1:].max(1) - scores[:, 0]
400
+
401
+ report = {"float_vs_torch_max_difference": float(np.abs(run(float_path) - reference).max())}
402
+ report["float_mb"] = round(float_path.stat().st_size / 1e6, 2)
403
+ for name in quantized:
404
+ scores = run(output / name)
405
+ report[name] = {
406
+ "mb": round((output / name).stat().st_size / 1e6, 2),
407
+ "pick_agreement": round(float((scores.argmax(1) == reference.argmax(1)).mean()), 4),
408
+ "mean_margin_difference": round(float(np.abs(margins(scores) - margins(reference)).mean()), 3),
409
+ }
410
+ return report
411
+
412
+
413
+ def main():
414
+ parser = argparse.ArgumentParser()
415
+ parser.add_argument("--repo", default="cfahlgren1/tinyfix-realword")
416
+ parser.add_argument("--run-name", default="v4")
417
+ parser.add_argument("--real-mistakes", action="store_true", help="Also train on GitHub word swaps. Scored worse than homophones alone in v3.")
418
+ parser.add_argument("--fineweb-tokens", type=int, default=70_000_000)
419
+ parser.add_argument("--smoltalk-tokens", type=int, default=50_000_000)
420
+ parser.add_argument("--vocabulary", type=int, default=20_000)
421
+ parser.add_argument("--embedding", type=int, default=64)
422
+ parser.add_argument("--hidden", type=int, default=256)
423
+ parser.add_argument("--steps", type=int, default=60_000)
424
+ parser.add_argument("--batch", type=int, default=4096)
425
+ parser.add_argument("--learning-rate", type=float, default=2e-3)
426
+ parser.add_argument("--output", default="/tmp/tinyfix-realword")
427
+ parser.add_argument("--no-upload", action="store_true")
428
+ args = parser.parse_args()
429
+
430
+ device = "cuda" if torch.cuda.is_available() else "cpu"
431
+ output = Path(args.output)
432
+ output.mkdir(parents=True, exist_ok=True)
433
+ print(f"device={device} args={vars(args)}", flush=True)
434
+
435
+ documents, raw_ids = load_corpus({"fineweb": args.fineweb_tokens, "smoltalk": args.smoltalk_tokens, "oasst": 10**12})
436
+ vocabulary, lookup = build_vocabulary(documents, raw_ids, args.vocabulary)
437
+ print(f"documents={len(documents):,} raw_types={len(raw_ids):,} vocabulary={len(vocabulary):,}", flush=True)
438
+
439
+ order = np.random.default_rng(7).permutation(len(documents))
440
+ held_out = max(1, len(documents) // 20)
441
+ train_tokens = torch.from_numpy(lookup[np.concatenate([documents[index] for index in order[held_out:]])]).to(device).long()
442
+ validation_tokens = torch.from_numpy(lookup[np.concatenate([documents[index] for index in order[:held_out]])]).to(device).long()
443
+ print(f"train={len(train_tokens):,} validation={len(validation_tokens):,} unknown={(train_tokens == UNK).float().mean().item():.3f}", flush=True)
444
+ del documents
445
+
446
+ confusions = build_confusions(vocabulary, args.real_mistakes)
447
+ (output / "confusions.txt").write_text("".join(f"{typed} {' '.join(expected for expected, _ in options)}\n" for typed, options in confusions.items()))
448
+ neighbors = build_neighbors(vocabulary, confusions)
449
+ real_typed, real_weights = build_real_mistake_tables(vocabulary, confusions)
450
+ print(f"words with neighbors={(neighbors[:, 0] != PAD).sum():,}", flush=True)
451
+ (output / "vocab.txt").write_text("\n".join(vocabulary) + "\n")
452
+
453
+ train_sampler = Sampler(train_tokens, vocabulary, neighbors, real_typed, real_weights, device)
454
+ validation_sampler = Sampler(validation_tokens, vocabulary, neighbors, real_typed, real_weights, device)
455
+
456
+ model = WrongWordModel(len(vocabulary), args.embedding, args.hidden).to(device)
457
+ parameters = sum(parameter.numel() for parameter in model.parameters())
458
+ print(f"parameters={parameters:,}", flush=True)
459
+ optimizer = torch.optim.AdamW(model.parameters(), lr=args.learning_rate, weight_decay=1e-6)
460
+ schedule = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=args.learning_rate, total_steps=args.steps, pct_start=0.1)
461
+
462
+ started = time.time()
463
+ running_loss = 0.0
464
+ report_every = max(args.steps // 40, 1)
465
+ for step in range(1, args.steps + 1):
466
+ left, right, candidates, label, _ = train_sampler.batch(args.batch, 0.5)
467
+ loss = F.cross_entropy(mask_empty(model(left, right, candidates), candidates), label)
468
+ optimizer.zero_grad(set_to_none=True)
469
+ loss.backward()
470
+ torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
471
+ optimizer.step()
472
+ schedule.step()
473
+ running_loss += loss.item()
474
+ if step % report_every == 0:
475
+ print(f"step {step}/{args.steps} loss={running_loss / report_every:.4f} elapsed={time.time() - started:.0f}s", flush=True)
476
+ running_loss = 0.0
477
+ if step % (args.steps // 5 or 1) == 0:
478
+ print(f"validation step {step}: {evaluate(model, validation_sampler, 60, args.batch)}", flush=True)
479
+
480
+ validation = evaluate(model, validation_sampler, 200, args.batch)
481
+ print(f"final validation: {validation}", flush=True)
482
+ export_report = export_onnx(model, output, validation_sampler)
483
+ print(f"export: {export_report}", flush=True)
484
+
485
+ metrics = {
486
+ "args": vars(args),
487
+ "parameters": parameters,
488
+ "validation": validation,
489
+ "export": export_report,
490
+ "train_tokens": len(train_tokens),
491
+ "train_minutes": round((time.time() - started) / 60, 1),
492
+ }
493
+ (output / "metrics.json").write_text(json.dumps(metrics, indent=2) + "\n")
494
+ print(json.dumps(metrics, indent=2), flush=True)
495
+
496
+ if args.no_upload:
497
+ print(f"Skipping upload; artifacts in {output}", flush=True)
498
+ return
499
+ api = HfApi(token=os.environ["HF_TOKEN"])
500
+ api.create_repo(args.repo, repo_type="model", private=True, exist_ok=True)
501
+ api.upload_folder(folder_path=str(output), repo_id=args.repo, path_in_repo=args.run_name, repo_type="model")
502
+ print(f"Uploaded to {args.repo}/{args.run_name}", flush=True)
503
+
504
+
505
+ if __name__ == "__main__":
506
+ main()
v1/metrics.json DELETED
@@ -1,43 +0,0 @@
1
- {
2
- "args": {
3
- "repo": "cfahlgren1/tinyfix-realword",
4
- "run_name": "v1",
5
- "fineweb_tokens": 70000000,
6
- "smoltalk_tokens": 50000000,
7
- "vocabulary": 20000,
8
- "embedding": 64,
9
- "hidden": 256,
10
- "steps": 60000,
11
- "batch": 4096,
12
- "learning_rate": 0.002,
13
- "output": "/tmp/tinyfix-realword",
14
- "no_upload": false
15
- },
16
- "parameters": 1941345,
17
- "validation": {
18
- "clean_cases": 210578,
19
- "corrupted_cases": 210034,
20
- "caught_at_false_0.005": 0.7136,
21
- "threshold_at_false_0.005": 3.13,
22
- "caught_at_false_0.001": 0.5621,
23
- "threshold_at_false_0.001": 5.13,
24
- "caught_at_false_0.0005": 0.4977,
25
- "threshold_at_false_0.0005": 5.93
26
- },
27
- "export": {
28
- "float_vs_torch_max_difference": 5.7220458984375e-06,
29
- "float_mb": 7.81,
30
- "model_quint8.onnx": {
31
- "mb": 2.09,
32
- "pick_agreement": 0.9986,
33
- "mean_margin_difference": 0.104
34
- },
35
- "model_matmul_quint8.onnx": {
36
- "mb": 5.99,
37
- "pick_agreement": 0.9967,
38
- "mean_margin_difference": 0.092
39
- }
40
- },
41
- "train_tokens": 118291955,
42
- "train_minutes": 24.9
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v1/model.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:57f94203c18a32e6e0585ad0c7f8cfea4daf4fff175b8dd91afdc2f987034bd3
3
- size 7814671
 
 
 
 
v1/model_matmul_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:1b35513a64081c59bd612cb9088a3d4dadcb63bc4dbfd3075ceac6e0259ef454
3
- size 5991703
 
 
 
 
v1/model_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:563d98809074312be6ed156c516826c3f4b9a69764c5319c0aecc64dfbfdfb05
3
- size 2092690
 
 
 
 
v1/vocab.txt DELETED
The diff for this file is too large to render. See raw diff
 
v2/metrics.json DELETED
@@ -1,43 +0,0 @@
1
- {
2
- "args": {
3
- "repo": "cfahlgren1/tinyfix-realword",
4
- "run_name": "v2",
5
- "fineweb_tokens": 70000000,
6
- "smoltalk_tokens": 50000000,
7
- "vocabulary": 20000,
8
- "embedding": 64,
9
- "hidden": 256,
10
- "steps": 60000,
11
- "batch": 4096,
12
- "learning_rate": 0.002,
13
- "output": "/tmp/tinyfix-realword",
14
- "no_upload": false
15
- },
16
- "parameters": 1941345,
17
- "validation": {
18
- "clean_cases": 200005,
19
- "corrupted_cases": 201620,
20
- "caught_at_false_0.005": 0.7301,
21
- "threshold_at_false_0.005": 3.1,
22
- "caught_at_false_0.001": 0.5732,
23
- "threshold_at_false_0.001": 5.25,
24
- "caught_at_false_0.0005": 0.4914,
25
- "threshold_at_false_0.0005": 6.26
26
- },
27
- "export": {
28
- "float_vs_torch_max_difference": 5.7220458984375e-06,
29
- "float_mb": 7.81,
30
- "model_quint8.onnx": {
31
- "mb": 2.09,
32
- "pick_agreement": 0.998,
33
- "mean_margin_difference": 0.091
34
- },
35
- "model_matmul_quint8.onnx": {
36
- "mb": 5.99,
37
- "pick_agreement": 0.997,
38
- "mean_margin_difference": 0.081
39
- }
40
- },
41
- "train_tokens": 118291713,
42
- "train_minutes": 24.9
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v2/model.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:45a3d5d676a972801b6f9bd51d0f2e6439278694eace52aadb6a37725d7e3a51
3
- size 7814671
 
 
 
 
v2/model_matmul_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:7c7ba1c17231fb295c5c1b36b451f3e14d46c30bde139e9703d5115e475e4a95
3
- size 5991706
 
 
 
 
v3/confusions.txt DELETED
@@ -1,882 +0,0 @@
1
- it's its is their all invoke
2
- you your who if yo
3
- are is or and area at array of
4
- this these if that is thus
5
- return returns raise render output
6
- send sent sending
7
- you're your
8
- not note
9
- use used you
10
- simple simply
11
- weather whether
12
- your you're multiple our
13
- they the there you
14
- url file protocol
15
- filed field
16
- were where we're was
17
- test tests
18
- with will without within using about this we while
19
- know known
20
- off of error
21
- ran run
22
- create created creating update
23
- instance instances instant
24
- affect effect
25
- save safe same
26
- file files filed object
27
- expect except expected
28
- method methods message class
29
- provide provides providing
30
- value values null
31
- left right top
32
- change changed changing
33
- enable enabled
34
- has as must
35
- objects object
36
- using use uses with
37
- event even
38
- one once of first two
39
- through though thorough
40
- work works worked worker
41
- sent send
42
- advise advice
43
- built build
44
- instruction instructions
45
- make may means
46
- their they're there
47
- int in string into double
48
- javascript html object
49
- received receive
50
- right write left bottom top
51
- two too to
52
- weak week
53
- build builds
54
- ever every
55
- filter filters
56
- for of form four more are fork if
57
- now know new and
58
- values value
59
- what that which this why
60
- accept except
61
- advice advise
62
- allowed aloud
63
- aloud allowed
64
- board bored
65
- bored board
66
- brake break
67
- break brake
68
- cite sight site
69
- complement compliment
70
- compliment complement
71
- container containers contains pod
72
- effect affect
73
- except accept expect
74
- fair fare
75
- fare fair far
76
- hear here
77
- here hear
78
- hole whole
79
- its it's the
80
- lead led leaf
81
- led lead
82
- loose lose
83
- lose loose
84
- mail male
85
- male mail
86
- meat meet
87
- meet meat
88
- passed past
89
- past passed
90
- peace piece
91
- piece peace
92
- principal principle
93
- principle principal
94
- quiet quite
95
- quite quiet
96
- role roll
97
- roll role
98
- sale sell
99
- sell sale
100
- sight cite site
101
- site cite sight
102
- starts start starting
103
- than then
104
- then than
105
- there their they're they there's
106
- they're their there
107
- thorough though through
108
- though thorough through
109
- too two top
110
- waist waste
111
- waste waist
112
- we're were where
113
- wear where
114
- week weak
115
- where we're wear were
116
- whether weather
117
- who's whose
118
- whole hole
119
- whose who's
120
- wood would
121
- would wood could
122
- write right written writing
123
- changes change changed
124
- creates create
125
- generate generated generates remove
126
- mean means
127
- others other
128
- remove remote removes removing
129
- text test binary paragraph background
130
- uses used
131
- contain contains contained
132
- first last
133
- provided provide provides
134
- run runs ran
135
- ans and
136
- based base
137
- case cases cast
138
- determine determines determined
139
- ensure ensures
140
- extensions types policy
141
- get gets git getting be
142
- mayor major
143
- provides provide
144
- response request
145
- staring starting
146
- tag tags
147
- county count
148
- generated generate
149
- minimum maximum
150
- post port page
151
- reminder remainder
152
- director directory
153
- evaluate enable evaluated
154
- receive receives received
155
- that this of pace that's who
156
- after before by matched
157
- maybe may
158
- metrics metric
159
- mounting updating
160
- potential potentially
161
- show shown
162
- which with who
163
- above below
164
- dat data day
165
- find finds
166
- interface interfaces
167
- mount amount
168
- solution solutions
169
- stored store stores
170
- those these
171
- user used author
172
- controlled uncontrolled
173
- difference different differences
174
- err error
175
- image images imagine input
176
- request response
177
- suit suite
178
- welcome welcomed
179
- basics basic
180
- commands command
181
- constrain constraint
182
- dedicate dedicated
183
- driver drivers
184
- expression expressions condition
185
- generates generate
186
- last least latest
187
- module modules foo
188
- node nodes
189
- parent child
190
- peak peek
191
- power powerful
192
- specially especially
193
- sting string
194
- the its these for if of is their by
195
- var let
196
- consist consists
197
- covert convert
198
- dose does
199
- download install downloaded downloading
200
- fails fail
201
- flatten flattened
202
- frequent frequency
203
- gets get
204
- like look luck line
205
- looks look
206
- manor manner
207
- modify modifying create modified
208
- session sessions
209
- sockets tunnels
210
- target targets
211
- them the they
212
- tow two
213
- users uses
214
- variable variables option
215
- worse worst
216
- app apps
217
- cab can
218
- clients client
219
- creating created
220
- indicates indicate
221
- match matches march
222
- parse parser parsed
223
- produces produced producers
224
- property properly properties proper
225
- provider provided
226
- red read
227
- result results data
228
- slot slots
229
- strings string
230
- again against
231
- blow below
232
- buy by
233
- can cannot and be could
234
- cant can want
235
- class classes attribute module clash instance
236
- collection collections
237
- cpu gpu
238
- decorated decorate
239
- defined defines
240
- directly directory
241
- four five for
242
- functional function
243
- identify identity
244
- input inputs
245
- look looks
246
- manager manage
247
- new now the
248
- photo ad
249
- provision provisioning
250
- start starting started starter
251
- string strings strict number
252
- transforms transform
253
- tread thread
254
- versions version
255
- below belong
256
- close closed clone
257
- come comes some
258
- computes computed
259
- defines defined
260
- display displays displaying
261
- does is
262
- enabled disabled
263
- entire complete
264
- expressions expression
265
- inputs input outputs
266
- interesting interested
267
- key keys prefix value
268
- met me
269
- null false
270
- producer consumer
271
- record records
272
- represents represent
273
- row column span
274
- set get
275
- temporary temporarily
276
- thee the
277
- transform transforms
278
- translation translations
279
- very every
280
- and then for that given
281
- arm check
282
- array slice
283
- belongs belong
284
- button sensor
285
- commons common
286
- configuration configuring configure
287
- could would cannot
288
- div column li min
289
- document documentation
290
- easy easily
291
- fill will
292
- follows follow
293
- hat that
294
- hen when
295
- hold holds held
296
- how what
297
- innovation education
298
- ins is
299
- issued issues
300
- latter later first
301
- making make
302
- mix mixed
303
- more or
304
- part party
305
- paths files
306
- phase job
307
- que queue
308
- register registers
309
- returned return
310
- running run
311
- second third section
312
- sections section
313
- ten five
314
- theme them
315
- tutorial tutorials
316
- want what
317
- worker master web
318
- added add removed
319
- applies applied
320
- begging beginning
321
- being been
322
- black block
323
- both bother what
324
- bumps bump
325
- comment comments quote comet
326
- definition definitions
327
- deploying deploy
328
- fixed fixes variable closed
329
- following follow
330
- got get have
331
- handles handle
332
- happen happens
333
- identity identify
334
- import imports line
335
- install deploy build
336
- isn't aren't
337
- item items time
338
- label labels heading
339
- library libraries
340
- ones once one
341
- outputs output
342
- particular particularly
343
- passes pass
344
- password service
345
- patterns pattern
346
- projects project
347
- reference references refer
348
- rest reset
349
- side size
350
- sources source
351
- supported support possible
352
- term terms turn
353
- title pages body
354
- tokens token circles
355
- ton to
356
- when with where
357
- account accounts
358
- actually actual
359
- adapter adapted
360
- afterwards afterward
361
- all allow most the
362
- answer answers
363
- any ant one
364
- appearing appear
365
- assignments assignment
366
- author name
367
- backed baked
368
- became become
369
- calling called
370
- charts lines
371
- child children
372
- commit commits
373
- computation computations
374
- condition conditions
375
- consumer producer
376
- contained containing
377
- controls control
378
- convention conventional
379
- crates creates
380
- credit credits
381
- decided decide
382
- descriptions description
383
- dist pd
384
- distribute distributed
385
- don't do
386
- dot do
387
- easily easy
388
- elliptical elliptic
389
- epoch epochs
390
- extension extensions
391
- fir for
392
- flat flag
393
- float string
394
- format value
395
- fourth fifth
396
- happens happen
397
- hard soft
398
- having have
399
- hero player
400
- inherits inherited
401
- integrate integrates
402
- integrated integrate integrating
403
- introduces introduced
404
- involved involve
405
- issue issued
406
- just you
407
- large larger
408
- leak leaky
409
- leave leaf
410
- lightning lighting
411
- live life online
412
- logging monitoring
413
- manage manager
414
- model module mode
415
- name type description node
416
- notification notifications
417
- occurs occur
418
- offer offers
419
- parts part
420
- pass passes
421
- perform performed
422
- point pointer
423
- prepare prepared
424
- query mutation
425
- readers writers
426
- records record
427
- releases release
428
- removed remove
429
- reporting build
430
- selects select
431
- server application
432
- service file
433
- shot shoot
434
- size length
435
- specify specifies
436
- system snippets
437
- take taken
438
- terminate list resume
439
- thanks thank
440
- these which
441
- training train
442
- transactions transaction
443
- update upgrade
444
- validate valid
445
- verify validate
446
- vertices vertical
447
- wants want
448
- was is has
449
- width with
450
- xml java
451
- about amount
452
- adapting adopting
453
- allocate allocated
454
- analyses analyzes
455
- android ios
456
- approached approach
457
- aren't isn't
458
- assembly assemble
459
- await return
460
- axis axes
461
- back forward
462
- backup restore
463
- backwards backward
464
- bundles bundle
465
- caching cache
466
- calculates calculate
467
- calculation calculations
468
- cane can
469
- cause because
470
- colors color
471
- comments comment
472
- compatible compatibility
473
- compliments complements
474
- computer computers
475
- consequently sequentially
476
- containing contain contains
477
- contracts contract
478
- contributors contributor
479
- convert check conversion
480
- deliver delivery
481
- delivery automate
482
- demonstrates demonstrate
483
- dependencies steps modules
484
- detect detects
485
- did didn't
486
- discuss discussed
487
- docker singularity
488
- double float
489
- drop add
490
- dump dumb
491
- east each
492
- enrollment authentication
493
- entry property
494
- error exception
495
- executed execute executes
496
- exiting exciting
497
- explain explained
498
- explicit explicitly
499
- facilitate facilitates
500
- faction factor
501
- fail fails
502
- foo bar
503
- formats relations
504
- forward backward forwards
505
- generation generating
506
- gives give
507
- granting grant
508
- handful helpful
509
- handle handled
510
- handlers handles
511
- hash hashed hashes
512
- haven have
513
- header headers
514
- hers her
515
- incoming outgoing
516
- index behavior indexed
517
- initiatives initiates
518
- issues issued
519
- iterator iterate
520
- japan japanese
521
- job jobs
522
- less loss
523
- list least dict set
524
- load create
525
- locale local
526
- mine mind
527
- models model
528
- much many
529
- notifications notification
530
- number minute
531
- open lock
532
- oracle mysql
533
- participants participant
534
- permissions permission
535
- php apache
536
- pods pod
537
- process processor
538
- purposes purpose
539
- question questions
540
- rails backup
541
- raises raised
542
- relations relationships
543
- remainder reminder
544
- repository repositories
545
- retrieve retrieved retrieving remove
546
- returning return
547
- saves save
548
- score loss
549
- secrete secret
550
- seems seem
551
- sequence sequences
552
- sin in
553
- since sense
554
- slave replica
555
- statement query
556
- sue sure
557
- suppose supposed
558
- supposed supported
559
- sync window
560
- tailed tailored
561
- taken take
562
- task future
563
- thank thanks
564
- themes theme
565
- there's there find
566
- timer time
567
- top topic
568
- trigger size
569
- turns turn
570
- typical typically
571
- underline underlying
572
- understand understanding understands
573
- unsigned signed
574
- val unit
575
- valued values
576
- vector matrix
577
- wallet wallets hosting
578
- wand want and
579
- what's what
580
- while will
581
- will should
582
- words word works
583
- access read
584
- accounts account
585
- action msg
586
- actions sections
587
- activity activities
588
- add at
589
- address error
590
- admin instructor
591
- adopt adapt
592
- agents agent
593
- aggregate aggregated
594
- aim aims
595
- alternative alternatively
596
- anchor guideline
597
- angles directions
598
- apart part
599
- application container
600
- apply link
601
- aria area
602
- arrive arrived
603
- art are
604
- attempt attempting
605
- attributes arguments
606
- automatic automatically
607
- bank blank
608
- bash sh
609
- basic destroy
610
- batch batches
611
- batteries services
612
- become became
613
- believe belief
614
- between and
615
- big bit
616
- branches values
617
- bread breed
618
- breaking braking
619
- buffer buffers vector window
620
- bus bugs
621
- but where
622
- cable view
623
- cache mail
624
- calculating calculate
625
- card item
626
- cards form
627
- channel file guild
628
- chart operator
629
- check integration
630
- checked health
631
- checkout check
632
- checkpoint checkpoints
633
- chose chooses
634
- clicked click
635
- clone cloned
636
- cluster topic
637
- coat color
638
- collect collects
639
- comparable akin
640
- compute observe
641
- connections connection
642
- construction constructing
643
- contract contrast
644
- contribute contributed
645
- convenience inconvenience
646
- coping copying
647
- copy copied
648
- crashes crashed
649
- creation deletion
650
- custom customize
651
- cut copy create
652
- cycling cyclic
653
- dead died
654
- debug display log
655
- default black
656
- del de
657
- described describe
658
- designate designated
659
- detector detection
660
- diamond oval
661
- directed directly
662
- direction direct directory
663
- directions directories
664
- doe do
665
- down done
666
- dumping inspecting
667
- elements method
668
- end stop
669
- ended ends
670
- engine bind
671
- equations equation
672
- essential essentially
673
- exceptional exceptionally
674
- extensive extension
675
- false stop
676
- featured features
677
- fifth sixth
678
- fin find
679
- finding find
680
- finish release
681
- followed subscribe
682
- forgot forget
683
- form forum
684
- fragments fragment
685
- gateway gateways
686
- gather cache
687
- gem get
688
- getting obtaining
689
- gpu cpu
690
- graduate graduates
691
- graph session
692
- gray grey
693
- great greater
694
- guide guides
695
- have behave half
696
- hidden hide
697
- high highly
698
- host domain
699
- idea ideas
700
- ignites ignite
701
- implementing of
702
- imported import
703
- including includes
704
- incorporate incorporation
705
- indices indexes
706
- info into
707
- inheritance embedding
708
- installer install
709
- installing installation
710
- interactions interaction
711
- internal interval
712
- into from
713
- introduce import introduces
714
- introduced introduces
715
- inversions inversion
716
- iphone ios
717
- isolate isolated
718
- jan june
719
- john jane
720
- journal server
721
- junk chunks
722
- larger smaller
723
- layer tile
724
- legally formally
725
- light dark
726
- link datasets
727
- listed listen
728
- listen listening listens
729
- listener listeners
730
- listing listening
731
- lists listens
732
- loaded loader
733
- log logic
734
- long longer
735
- lookup looking
736
- loud cloud
737
- mainly may
738
- marker markup
739
- master latest
740
- matched match
741
- material geometry
742
- may can
743
- meeting meetings
744
- merchants merchant
745
- message massage
746
- middle toggle
747
- migration migrations
748
- minimal bash
749
- minute second
750
- mirrors mirror
751
- missing method
752
- monitoring monitor
753
- must should
754
- need have
755
- needed needing
756
- neg sum
757
- nil null
758
- nodules modules
759
- none non
760
- normal light
761
- notes detail
762
- occurrence occurrences
763
- offset duration
764
- old go
765
- omitted emitted
766
- only using
767
- opens open
768
- operation operator
769
- option operation
770
- orbit alert
771
- other or
772
- our own
773
- outlines outlined
774
- output download
775
- packaged native
776
- packages packaged
777
- palette pal
778
- panel plane
779
- pas par
780
- performing perform
781
- place placement
782
- policy policies runtime
783
- positive negative
784
- primitive primitives
785
- procedure procedures
786
- profile profiles
787
- program programs
788
- project module
789
- properties events
790
- proxies proxy
791
- python net
792
- quickly soon
793
- quotient remainder
794
- rates rate
795
- rations ratios
796
- rebuilt rebuild
797
- recognition it
798
- remember remembered
799
- removes replaces
800
- representation representations
801
- requirement requirements
802
- res research
803
- rescue rescued
804
- research resource
805
- residence resident
806
- roles role
807
- ruby python
808
- rule role
809
- same name safe
810
- sample custom sampled
811
- saved save
812
- say stay
813
- select selected
814
- selection selected
815
- sensitivity speed
816
- sensor operator
817
- separate single
818
- setting getting set
819
- shape shapes
820
- shared sharing
821
- shortest longest
822
- signal signals
823
- signals signal
824
- similarly similar
825
- simply just
826
- snapshot abs
827
- some more
828
- son so
829
- sort soft
830
- source destination
831
- spans span
832
- specific specified
833
- sports supports
834
- started necessary
835
- stat state
836
- state stated states
837
- stone code
838
- streams feeds
839
- style italics still
840
- subsets subset
841
- support suppose
842
- supporter supported
843
- synchronous asynchronous
844
- table schema tab
845
- testing caching
846
- tests testes
847
- thrown throw throws
848
- thy they
849
- time run timestamps
850
- toggle service
851
- tool id
852
- transition navigate transitions
853
- tree trees
854
- triggers triggered
855
- true debug
856
- turn turned
857
- typing type
858
- under in
859
- underlined underlying
860
- unknown na
861
- until in
862
- updated updates
863
- uploads files upload
864
- valid validate
865
- variant read
866
- version info release revision
867
- view few viewed
868
- visible visibility
869
- war directory
870
- watches watch
871
- way away method want
872
- whenever wherever
873
- why what which
874
- widows windows
875
- workspace volume
876
- world life
877
- wrap wraps
878
- writer reader
879
- writing serving
880
- yard yarn
881
- year years
882
- you'll you're
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v3/metrics.json DELETED
@@ -1,43 +0,0 @@
1
- {
2
- "args": {
3
- "repo": "cfahlgren1/tinyfix-realword",
4
- "run_name": "v3",
5
- "fineweb_tokens": 70000000,
6
- "smoltalk_tokens": 50000000,
7
- "vocabulary": 20000,
8
- "embedding": 64,
9
- "hidden": 256,
10
- "steps": 60000,
11
- "batch": 4096,
12
- "learning_rate": 0.002,
13
- "output": "/tmp/tinyfix-realword",
14
- "no_upload": false
15
- },
16
- "parameters": 1941345,
17
- "validation": {
18
- "clean_cases": 203358,
19
- "corrupted_cases": 212256,
20
- "caught_at_false_0.005": 0.6522,
21
- "threshold_at_false_0.005": 3.19,
22
- "caught_at_false_0.001": 0.4989,
23
- "threshold_at_false_0.001": 5.06,
24
- "caught_at_false_0.0005": 0.4239,
25
- "threshold_at_false_0.0005": 6.01
26
- },
27
- "export": {
28
- "float_vs_torch_max_difference": 6.198883056640625e-06,
29
- "float_mb": 7.81,
30
- "model_quint8.onnx": {
31
- "mb": 2.09,
32
- "pick_agreement": 0.9947,
33
- "mean_margin_difference": 0.099
34
- },
35
- "model_matmul_quint8.onnx": {
36
- "mb": 5.99,
37
- "pick_agreement": 0.9932,
38
- "mean_margin_difference": 0.082
39
- }
40
- },
41
- "train_tokens": 118291713,
42
- "train_minutes": 27.6
43
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v3/model.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:345a7272ad63a1ab801c7cd77a674004c52e1c81839b80714cd157abae223007
3
- size 7814671
 
 
 
 
v3/model_matmul_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:33dfd6c147803965f660e19da23b16f8b9a1e6678221a16ee3d2fa687cbc8561
3
- size 5991706
 
 
 
 
v3/model_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:17e2a33016de1f8aa503a466670c9edc8f78d83b2996f68bdbec7e8b082fa9d0
3
- size 2092693
 
 
 
 
v3/vocab.txt DELETED
The diff for this file is too large to render. See raw diff
 
v4/metrics.json DELETED
@@ -1,44 +0,0 @@
1
- {
2
- "args": {
3
- "repo": "cfahlgren1/tinyfix-realword",
4
- "run_name": "v4",
5
- "real_mistakes": false,
6
- "fineweb_tokens": 70000000,
7
- "smoltalk_tokens": 50000000,
8
- "vocabulary": 20000,
9
- "embedding": 96,
10
- "hidden": 512,
11
- "steps": 90000,
12
- "batch": 4096,
13
- "learning_rate": 0.002,
14
- "output": "/tmp/tinyfix-realword",
15
- "no_upload": false
16
- },
17
- "parameters": 4385921,
18
- "validation": {
19
- "clean_cases": 199439,
20
- "corrupted_cases": 202365,
21
- "caught_at_false_0.005": 0.7682,
22
- "threshold_at_false_0.005": 3.08,
23
- "caught_at_false_0.001": 0.6164,
24
- "threshold_at_false_0.001": 5.39,
25
- "caught_at_false_0.0005": 0.5517,
26
- "threshold_at_false_0.0005": 6.25
27
- },
28
- "export": {
29
- "float_vs_torch_max_difference": 1.71661376953125e-05,
30
- "float_mb": 17.59,
31
- "model_quint8.onnx": {
32
- "mb": 4.54,
33
- "pick_agreement": 0.9931,
34
- "mean_margin_difference": 0.223
35
- },
36
- "model_matmul_quint8.onnx": {
37
- "mb": 10.36,
38
- "pick_agreement": 0.9926,
39
- "mean_margin_difference": 0.215
40
- }
41
- },
42
- "train_tokens": 118291713,
43
- "train_minutes": 55.7
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
v4/model.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:3240885f048049bcce599956b9ef42d5f77a242f18284bb90ec5308967faa940
3
- size 17592977
 
 
 
 
v4/model_matmul_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:b391462ec853f0e4714aa913f42f42cebc735ac4e927715a4e300404bf3a36f2
3
- size 10363288
 
 
 
 
v4/model_quint8.onnx DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:05802e12d893e7e3d2246ad6e1ad2b0bebadc29754e4cf7771c69c28e1f5c242
3
- size 4544276
 
 
 
 
v4/vocab.txt DELETED
The diff for this file is too large to render. See raw diff
 
v4/confusions.txt → wrong-word-confusions.txt RENAMED
@@ -1,73 +1,74 @@
1
- accept except
2
- advice advise
3
- advise advice
4
- affect effect
5
- allowed aloud
6
- aloud allowed
7
- board bored
8
- bored board
9
- brake break
10
- break brake
11
- cite sight site
12
- complement compliment
13
- compliment complement
14
- effect affect
15
- except accept
16
- fair fare
17
- fare fair
18
  hear here
19
  here hear
20
- hole whole
21
- it's its
22
- its it's
23
- lead led
24
- led lead
25
- loose lose
26
  lose loose
27
- mail male
28
- male mail
29
- meat meet
30
- meet meat
 
 
 
 
 
 
31
  passed past
32
  past passed
33
- peace piece
34
- piece peace
35
  principal principle
36
  principle principal
37
- quiet quite
38
- quite quiet
39
- right write
40
- role roll
41
- roll role
42
- sale sell
43
- sell sale
44
- sight cite site
45
- site cite sight
46
- than then
47
- their there they're
48
- then than
49
- there their they're
50
- they're their there
51
- thorough though through
52
- though thorough through
53
- through thorough though
54
- too two
55
- two too
56
  waist waste
57
  waste waist
58
- we're were where
59
- weak week
 
 
 
60
  wear where
61
- weather whether
 
 
 
 
62
  week weak
63
- were we're where
64
- where we're wear were
65
- whether weather
66
- who's whose
67
- whole hole
68
- whose who's
69
  wood would
70
  would wood
71
- write right
72
- you're your
73
- your you're
 
 
 
 
 
 
 
 
 
 
 
 
1
+ their there they're
2
+ there their they're
3
+ they're their there
4
+ your you're
5
+ you're your
6
+ its it's
7
+ it's its
8
+ too two
9
+ two too
10
+ then than
11
+ than then
12
+ were where we're
13
+ where were we're
14
+ we're were where
15
+ whose who's
16
+ who's whose
 
17
  hear here
18
  here hear
19
+ weather whether
20
+ whether weather
21
+ peace piece
22
+ piece peace
23
+ affect effect
24
+ effect affect
25
  lose loose
26
+ loose lose
27
+ accept except
28
+ except accept
29
+ advice advise
30
+ advise advice
31
+ quiet quite
32
+ quite quiet
33
+ through though thorough
34
+ though through thorough
35
+ thorough through though
36
  passed past
37
  past passed
 
 
38
  principal principle
39
  principle principal
40
+ complement compliment
41
+ compliment complement
42
+ brake break
43
+ break brake
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  waist waste
45
  waste waist
46
+ right write
47
+ write right
48
+ sight site cite
49
+ site sight cite
50
+ cite sight site
51
  wear where
52
+ where wear
53
+ led lead
54
+ lead led
55
+ meet meat
56
+ meat meet
57
  week weak
58
+ weak week
 
 
 
 
 
59
  wood would
60
  would wood
61
+ hole whole
62
+ whole hole
63
+ male mail
64
+ mail male
65
+ sale sell
66
+ sell sale
67
+ role roll
68
+ roll role
69
+ aloud allowed
70
+ allowed aloud
71
+ board bored
72
+ bored board
73
+ fair fare
74
+ fare fair
v2/vocab.txt → wrong-word-vocab.txt RENAMED
File without changes
v2/model_quint8.onnx → wrong-word.onnx RENAMED
File without changes