tinynext-v2-nofim: 12.5M params, 28 min on GPU
Browse files- v2/experiments/tinynext-v2-nofim/config.json +16 -0
- v2/experiments/tinynext-v2-nofim/eval.py +499 -0
- v2/experiments/tinynext-v2-nofim/eval_set.json +0 -0
- v2/experiments/tinynext-v2-nofim/metrics/tinynext-v2-nofim.json +363 -0
- v2/experiments/tinynext-v2-nofim/model.onnx +3 -0
- v2/experiments/tinynext-v2-nofim/model.safetensors +3 -0
- v2/experiments/tinynext-v2-nofim/model_int8.onnx +3 -0
- v2/experiments/tinynext-v2-nofim/report.json +1239 -0
- v2/experiments/tinynext-v2-nofim/tokenizer.json +0 -0
- v2/experiments/tinynext-v2-nofim/train.py +691 -0
v2/experiments/tinynext-v2-nofim/config.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"vocab": 8192,
|
| 3 |
+
"dim": 320,
|
| 4 |
+
"layers": 8,
|
| 5 |
+
"heads": 5,
|
| 6 |
+
"ffn": 864,
|
| 7 |
+
"parameters": 12539200,
|
| 8 |
+
"seq": 512,
|
| 9 |
+
"special_tokens": {
|
| 10 |
+
"<|endoftext|>": 0,
|
| 11 |
+
"<|pre|>": 1,
|
| 12 |
+
"<|suf|>": 2,
|
| 13 |
+
"<|mid|>": 3
|
| 14 |
+
},
|
| 15 |
+
"prompt": "No text after the cursor: the text before it. Otherwise: <|suf|> after <|pre|> before <|mid|>."
|
| 16 |
+
}
|
v2/experiments/tinynext-v2-nofim/eval.py
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# "onnxruntime>=1.20",
|
| 8 |
+
# "transformers>=4.46",
|
| 9 |
+
# "tokenizers>=0.20",
|
| 10 |
+
# ]
|
| 11 |
+
# ///
|
| 12 |
+
"""Scores autocomplete models the way people use them: type real text, pause, and see if the gray suggestion is right.
|
| 13 |
+
|
| 14 |
+
Every model sees the same pauses in the same text and is decoded with the same rule as offline.page:
|
| 15 |
+
follow the model's top pick while the running product of probabilities stays above a cutoff, and show
|
| 16 |
+
the text up to the last finished word. A suggestion is right when the text really continues that way.
|
| 17 |
+
|
| 18 |
+
Two scenarios:
|
| 19 |
+
typing the cursor is at the end of what's written so far.
|
| 20 |
+
editing the cursor is mid-sentence and real text follows a gap of 2-6 words. Only fill-in-the-middle
|
| 21 |
+
models are given that text; the rest see only what's before the cursor.
|
| 22 |
+
|
| 23 |
+
Usage:
|
| 24 |
+
uv run eval.py --model tinynext-v1 --onnx model_quint8.onnx
|
| 25 |
+
uv run eval.py --model smollm2-135m --hf HuggingFaceTB/SmolLM2-135M
|
| 26 |
+
uv run eval.py --table # compare every metrics/*.json
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
import argparse
|
| 30 |
+
import hashlib
|
| 31 |
+
import json
|
| 32 |
+
import random
|
| 33 |
+
import re
|
| 34 |
+
import statistics
|
| 35 |
+
import time
|
| 36 |
+
from collections.abc import Callable
|
| 37 |
+
from dataclasses import dataclass, field
|
| 38 |
+
from pathlib import Path
|
| 39 |
+
|
| 40 |
+
import numpy as np
|
| 41 |
+
|
| 42 |
+
HERE = Path(__file__).parent
|
| 43 |
+
EVAL_SET = HERE / "eval_set.json"
|
| 44 |
+
METRICS = HERE / "metrics"
|
| 45 |
+
|
| 46 |
+
CUTOFFS = (0.3, 0.4, 0.5, 0.6, 0.7)
|
| 47 |
+
MAIN_CUTOFF = 0.5 # what offline.page uses
|
| 48 |
+
PAUSE_EVERY = 12 # characters between pauses
|
| 49 |
+
MIN_SHOWN_CHARS = 4 # offline.page hides shorter suggestions
|
| 50 |
+
MAX_WORDS = 6
|
| 51 |
+
MAX_CHARS = 48
|
| 52 |
+
DOMAINS = ("articles", "messages", "email")
|
| 53 |
+
SCENARIOS = ("typing", "editing")
|
| 54 |
+
PUNCTUATION = ".,!?;:"
|
| 55 |
+
|
| 56 |
+
# ---- Eval text -------------------------------------------------------------------------------------------------
|
| 57 |
+
# Kept apart from training: Wikipedia isn't in either model's data, OpenAssistant validation isn't in SmolTalk's
|
| 58 |
+
# training split, and the emails come from the senders the original enron-autocomplete held out for its test set.
|
| 59 |
+
|
| 60 |
+
CUT_REPLY = re.compile(
|
| 61 |
+
r"(?im)^\s*(?:-+\s*original message|-+\s*forwarded by|-+\s*inline attachment|from:\s|to:\s|sent:\s"
|
| 62 |
+
r"|subject:\s|cc:\s|.*\bwrote:\s*$|_{5,}|-{5,}|={5,}|\*{5,}|\d{1,2}/\d{1,2}/\d{2,4}\s+\d{1,2}:\d{2})"
|
| 63 |
+
)
|
| 64 |
+
SENSITIVE = re.compile(r"(?i)https?://|www\.|\S+@\S+|\(?\b\d{3}\)?[-. ]\d{3}[-. ]\d{4}\b|\b\d{3}-\d{2}-\d{4}\b")
|
| 65 |
+
BULK_SENDER = re.compile(r"(?i)announce|newsletter|mailer|outlook\.team|^all[._]|general\.|chairman|enron\.(?:on|net)")
|
| 66 |
+
SMART_CHARS = str.maketrans({"‘": "'", "’": "'", "“": '"', "”": '"', "–": "-", "—": "-", "\t": " "})
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def clean_email(body: str) -> list[str]:
|
| 70 |
+
"""The same cleaning enron-autocomplete was trained with."""
|
| 71 |
+
text = body.replace("\r\n", "\n").replace("=20", " ").replace("=\n", "").translate(SMART_CHARS)
|
| 72 |
+
text = "\n".join(line for line in text.split("\n") if not line.lstrip().startswith(">"))
|
| 73 |
+
cut = CUT_REPLY.search(text)
|
| 74 |
+
if cut:
|
| 75 |
+
text = text[: cut.start()]
|
| 76 |
+
text = re.sub(r"(?m)^-- *\n[\s\S]*", "", text)
|
| 77 |
+
paragraphs = []
|
| 78 |
+
for block in re.split(r"\n\s*\n", text):
|
| 79 |
+
lines = [re.sub(r" +", " ", line).strip() for line in block.split("\n") if line.strip()]
|
| 80 |
+
if not lines:
|
| 81 |
+
continue
|
| 82 |
+
joined = lines[0]
|
| 83 |
+
for previous, line in zip(lines, lines[1:]):
|
| 84 |
+
joined += (" " if len(previous) >= 50 else "\n") + line
|
| 85 |
+
if SENSITIVE.search(joined) or sum(c.isalpha() for c in joined) < 0.6 * len(joined):
|
| 86 |
+
continue
|
| 87 |
+
paragraphs.append(joined)
|
| 88 |
+
return paragraphs
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def is_held_out_sender(sender: str) -> bool:
|
| 92 |
+
"""enron-autocomplete put senders whose hash bucket is under 5 in its test split."""
|
| 93 |
+
sender = sender.lower()
|
| 94 |
+
if "@enron.com" not in sender or BULK_SENDER.search(sender):
|
| 95 |
+
return False
|
| 96 |
+
return int(hashlib.sha1(sender.encode()).hexdigest(), 16) % 100 < 5
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def ascii_paragraphs(text: str, min_chars: int = 40) -> list[str]:
|
| 100 |
+
text = text.translate(SMART_CHARS).encode("ascii", "ignore").decode()
|
| 101 |
+
return [p.strip() for p in re.split(r"\n\s*\n|\n", text) if len(p.strip()) >= min_chars]
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def build_eval_set(docs_per_domain: int = 80) -> dict[str, list[list[str]]]:
|
| 105 |
+
from datasets import load_dataset
|
| 106 |
+
|
| 107 |
+
sets: dict[str, list[list[str]]] = {domain: [] for domain in DOMAINS}
|
| 108 |
+
wiki = load_dataset(
|
| 109 |
+
"wikimedia/wikipedia", data_files="20231101.en/train-00040-of-00041.parquet", split="train", streaming=True
|
| 110 |
+
)
|
| 111 |
+
for row in wiki:
|
| 112 |
+
paragraphs = [p for p in ascii_paragraphs(row["text"], 80) if not p.endswith(":")][:6]
|
| 113 |
+
if len(paragraphs) >= 3:
|
| 114 |
+
sets["articles"].append(paragraphs)
|
| 115 |
+
if len(sets["articles"]) >= docs_per_domain:
|
| 116 |
+
break
|
| 117 |
+
|
| 118 |
+
for row in load_dataset("OpenAssistant/oasst1", split="validation"):
|
| 119 |
+
if row["lang"] == "en" and "```" not in row["text"]:
|
| 120 |
+
paragraphs = ascii_paragraphs(row["text"])[:6]
|
| 121 |
+
if paragraphs:
|
| 122 |
+
sets["messages"].append(paragraphs)
|
| 123 |
+
if len(sets["messages"]) >= docs_per_domain:
|
| 124 |
+
break
|
| 125 |
+
|
| 126 |
+
for row in load_dataset("corbt/enron-emails", split="train", streaming=True):
|
| 127 |
+
if is_held_out_sender(row["from"] or ""):
|
| 128 |
+
paragraphs = [p for p in clean_email(row["body"] or "") if len(p) >= 40][:6]
|
| 129 |
+
if paragraphs:
|
| 130 |
+
sets["email"].append(paragraphs)
|
| 131 |
+
if len(sets["email"]) >= docs_per_domain:
|
| 132 |
+
break
|
| 133 |
+
return sets
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
def load_eval_set() -> dict[str, list[list[str]]]:
|
| 137 |
+
if not EVAL_SET.exists():
|
| 138 |
+
EVAL_SET.write_text(json.dumps(build_eval_set(), indent=1))
|
| 139 |
+
return json.loads(EVAL_SET.read_text())
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
@dataclass
|
| 143 |
+
class Pause:
|
| 144 |
+
domain: str
|
| 145 |
+
scenario: str
|
| 146 |
+
before: str # the document up to the cursor
|
| 147 |
+
after: str # text after the cursor that a model may see (empty when typing)
|
| 148 |
+
truth: str # what the person actually typed next
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def pauses(eval_set: dict[str, list[list[str]]], max_per_domain: int) -> list[Pause]:
|
| 152 |
+
rng = random.Random(0)
|
| 153 |
+
found: list[Pause] = []
|
| 154 |
+
for domain in DOMAINS:
|
| 155 |
+
in_domain: list[Pause] = []
|
| 156 |
+
for paragraphs in eval_set[domain]:
|
| 157 |
+
for index, paragraph in enumerate(paragraphs):
|
| 158 |
+
earlier = "\n".join(paragraphs[:index])
|
| 159 |
+
for at in range(PAUSE_EVERY, len(paragraph) - 8, PAUSE_EVERY):
|
| 160 |
+
before = (earlier + "\n" if earlier else "") + paragraph[:at]
|
| 161 |
+
truth = paragraph[at:]
|
| 162 |
+
in_domain.append(Pause(domain, "typing", before, "", truth))
|
| 163 |
+
# Editing: a gap of 2-6 words, then the rest of the paragraph as it was written.
|
| 164 |
+
gap_words = rng.randint(2, 6)
|
| 165 |
+
gap = re.match(r"(\S*\s+){%d}" % gap_words, truth)
|
| 166 |
+
if gap and len(truth) > gap.end() + 10:
|
| 167 |
+
in_domain.append(Pause(domain, "editing", before, truth[gap.end():], truth))
|
| 168 |
+
rng.shuffle(in_domain)
|
| 169 |
+
found += [p for p in in_domain if p.scenario == "typing"][:max_per_domain]
|
| 170 |
+
found += [p for p in in_domain if p.scenario == "editing"][:max_per_domain]
|
| 171 |
+
return found
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
# ---- Decoding -------------------------------------------------------------------------------------------------
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
@dataclass
|
| 178 |
+
class Trajectory:
|
| 179 |
+
"""Suggestions that end at a word boundary, with the model's confidence in each. Greedy decoding gives the
|
| 180 |
+
same path for every cutoff, so one decode answers all of them."""
|
| 181 |
+
|
| 182 |
+
candidates: list[tuple[str, float]] = field(default_factory=list)
|
| 183 |
+
milliseconds: float = 0.0
|
| 184 |
+
|
| 185 |
+
def at(self, cutoff: float) -> str:
|
| 186 |
+
best = ""
|
| 187 |
+
for text, confidence in self.candidates:
|
| 188 |
+
if confidence >= cutoff:
|
| 189 |
+
best = text
|
| 190 |
+
return best.rstrip()
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
class Model:
|
| 194 |
+
name: str
|
| 195 |
+
sees_after: bool = False
|
| 196 |
+
|
| 197 |
+
def suggest(self, before: str, after: str) -> Trajectory:
|
| 198 |
+
raise NotImplementedError
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
class CharGRU(Model):
|
| 202 |
+
"""enron-autocomplete / tinynext v1: one character per step, reading only the current paragraph."""
|
| 203 |
+
|
| 204 |
+
HIDDEN, END, NEWLINE, FIRST, OFFSET = 512, 1, 2, 3, 29
|
| 205 |
+
|
| 206 |
+
def __init__(self, name: str, onnx_path: str):
|
| 207 |
+
import onnxruntime as ort
|
| 208 |
+
|
| 209 |
+
self.name = name
|
| 210 |
+
self.session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"])
|
| 211 |
+
self.read_text: str | None = None
|
| 212 |
+
self.reading = None
|
| 213 |
+
|
| 214 |
+
def step(self, char_id: int, state):
|
| 215 |
+
logits, state = self.session.run(None, {"input_id": np.array([char_id], np.int64), "state": state})
|
| 216 |
+
return logits[0], state
|
| 217 |
+
|
| 218 |
+
def encode(self, char: str) -> int | None:
|
| 219 |
+
if char == "\n":
|
| 220 |
+
return self.NEWLINE
|
| 221 |
+
code = ord(char)
|
| 222 |
+
return code - self.OFFSET if 32 <= code <= 126 else None
|
| 223 |
+
|
| 224 |
+
def read(self, text: str):
|
| 225 |
+
if self.read_text is None or not text.startswith(self.read_text):
|
| 226 |
+
self.reading = self.step(self.END, np.zeros((1, self.HIDDEN), np.float32))
|
| 227 |
+
self.read_text = ""
|
| 228 |
+
for char in text[len(self.read_text):]:
|
| 229 |
+
char_id = self.encode(char)
|
| 230 |
+
if char_id is not None:
|
| 231 |
+
self.reading = self.step(char_id, self.reading[1])
|
| 232 |
+
self.read_text = text
|
| 233 |
+
return self.reading
|
| 234 |
+
|
| 235 |
+
def suggest(self, before: str, after: str) -> Trajectory:
|
| 236 |
+
began = time.perf_counter()
|
| 237 |
+
logits, state = self.read(before.split("\n")[-1])
|
| 238 |
+
trajectory, run, confidence, words = Trajectory(), "", 1.0, 0
|
| 239 |
+
while len(run) < MAX_CHARS and confidence >= min(CUTOFFS):
|
| 240 |
+
probabilities = np.exp(logits - logits.max())
|
| 241 |
+
probabilities /= probabilities.sum()
|
| 242 |
+
char_id = int(probabilities.argmax())
|
| 243 |
+
if char_id < self.FIRST:
|
| 244 |
+
if run:
|
| 245 |
+
trajectory.candidates.append((run, confidence))
|
| 246 |
+
break
|
| 247 |
+
char = chr(char_id + self.OFFSET)
|
| 248 |
+
if char == " ":
|
| 249 |
+
trajectory.candidates.append((run, confidence))
|
| 250 |
+
words += 1
|
| 251 |
+
if words >= MAX_WORDS:
|
| 252 |
+
break
|
| 253 |
+
confidence *= float(probabilities[char_id])
|
| 254 |
+
run += char
|
| 255 |
+
if char in PUNCTUATION:
|
| 256 |
+
trajectory.candidates.append((run, confidence))
|
| 257 |
+
logits, state = self.step(char_id, state)
|
| 258 |
+
trajectory.milliseconds = (time.perf_counter() - began) * 1000
|
| 259 |
+
return trajectory
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
class TokenLM(Model):
|
| 263 |
+
"""A word-piece model. `next_logits(ids, cache)` runs one forward pass and returns (last logits, cache).
|
| 264 |
+
|
| 265 |
+
The word being typed is "healed": the prompt stops before it, and the first generated pieces must spell it
|
| 266 |
+
out, so a half-typed word like "resig" can still become "resignation" in one piece.
|
| 267 |
+
"""
|
| 268 |
+
|
| 269 |
+
def __init__(self, name: str, next_logits: Callable, encode: Callable[[str], list[int]], token_texts: list[str],
|
| 270 |
+
stop_ids: set[int], prompt: Callable[[list[int], list[int]], list[int]] | None = None,
|
| 271 |
+
context_chars: int = 1500, suffix_chars: int = 300):
|
| 272 |
+
self.name = name
|
| 273 |
+
self.next_logits = next_logits
|
| 274 |
+
self.encode = encode
|
| 275 |
+
self.token_texts = token_texts
|
| 276 |
+
self.stop_ids = stop_ids
|
| 277 |
+
self.prompt = prompt
|
| 278 |
+
self.sees_after = prompt is not None
|
| 279 |
+
self.context_chars = context_chars
|
| 280 |
+
self.suffix_chars = suffix_chars
|
| 281 |
+
lengths = np.array([len(t) for t in token_texts])
|
| 282 |
+
self.nonempty = lengths > 0
|
| 283 |
+
|
| 284 |
+
def allowed(self, need: str) -> np.ndarray:
|
| 285 |
+
"""Pieces consistent with the rest of the half-typed word."""
|
| 286 |
+
return np.array([bool(t) and (need.startswith(t) or t.startswith(need)) for t in self.token_texts])
|
| 287 |
+
|
| 288 |
+
def suggest(self, before: str, after: str) -> Trajectory:
|
| 289 |
+
began = time.perf_counter()
|
| 290 |
+
before = before[-self.context_chars:]
|
| 291 |
+
# The half-typed word keeps its leading space, since word pieces start with one. A line break stays in the prompt.
|
| 292 |
+
space, newline = before.rfind(" "), before.rfind("\n")
|
| 293 |
+
if space > newline:
|
| 294 |
+
stem, need = before[:space], before[space:]
|
| 295 |
+
else:
|
| 296 |
+
stem, need = before[: newline + 1], before[newline + 1:]
|
| 297 |
+
prefix_ids = self.encode(stem)
|
| 298 |
+
if self.prompt:
|
| 299 |
+
ids = self.prompt(prefix_ids, self.encode(after[: self.suffix_chars]) if after else [])
|
| 300 |
+
else:
|
| 301 |
+
ids = prefix_ids
|
| 302 |
+
logits, cache = self.next_logits(ids, None)
|
| 303 |
+
|
| 304 |
+
trajectory, generated, confidence = Trajectory(), "", 1.0
|
| 305 |
+
for _ in range(16):
|
| 306 |
+
logits = logits.astype(np.float64)
|
| 307 |
+
if need:
|
| 308 |
+
mask = self.allowed(need)
|
| 309 |
+
if not mask.any():
|
| 310 |
+
break
|
| 311 |
+
logits = np.where(mask, logits, -np.inf)
|
| 312 |
+
probabilities = np.exp(logits - logits.max())
|
| 313 |
+
probabilities /= probabilities.sum()
|
| 314 |
+
token = int(probabilities.argmax())
|
| 315 |
+
text = self.token_texts[token]
|
| 316 |
+
if token in self.stop_ids or "\n" in text:
|
| 317 |
+
if generated:
|
| 318 |
+
trajectory.candidates.append((generated, confidence))
|
| 319 |
+
break
|
| 320 |
+
if need:
|
| 321 |
+
consumed = min(len(need), len(text))
|
| 322 |
+
text, need = text[consumed:], need[consumed:]
|
| 323 |
+
if text[:1].isspace() and generated:
|
| 324 |
+
trajectory.candidates.append((generated, confidence))
|
| 325 |
+
confidence *= float(probabilities[token])
|
| 326 |
+
generated += text
|
| 327 |
+
if generated.rstrip()[-1:] in PUNCTUATION and generated.strip():
|
| 328 |
+
trajectory.candidates.append((generated, confidence))
|
| 329 |
+
if confidence < min(CUTOFFS) or len(generated) > MAX_CHARS or len(generated.split()) > MAX_WORDS:
|
| 330 |
+
break
|
| 331 |
+
logits, cache = self.next_logits([token], cache)
|
| 332 |
+
trajectory.milliseconds = (time.perf_counter() - began) * 1000
|
| 333 |
+
return trajectory
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
def hf_causal_lm(name: str, repo: str) -> TokenLM:
|
| 337 |
+
import torch
|
| 338 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 339 |
+
|
| 340 |
+
device = "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu"
|
| 341 |
+
tokenizer = AutoTokenizer.from_pretrained(repo)
|
| 342 |
+
model = AutoModelForCausalLM.from_pretrained(repo, torch_dtype=torch.float32).to(device).eval()
|
| 343 |
+
|
| 344 |
+
@torch.no_grad()
|
| 345 |
+
def next_logits(ids, cache):
|
| 346 |
+
out = model(torch.tensor([ids], device=device), past_key_values=cache, use_cache=True)
|
| 347 |
+
return out.logits[0, -1].float().cpu().numpy(), out.past_key_values
|
| 348 |
+
|
| 349 |
+
texts = [tokenizer.decode([i]) for i in range(len(tokenizer))]
|
| 350 |
+
stops = {tokenizer.eos_token_id} if tokenizer.eos_token_id is not None else set()
|
| 351 |
+
encode = lambda text: tokenizer.encode(text, add_special_tokens=False) or [tokenizer.eos_token_id]
|
| 352 |
+
return TokenLM(name, next_logits, encode, texts, stops)
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def onnx_token_lm(name: str, folder: str, fim: bool) -> TokenLM:
|
| 356 |
+
"""A tinynext v2 export: graph.onnx + weights.f32 (compressed, expanded) or model.onnx, plus tokenizer.json."""
|
| 357 |
+
import onnxruntime as ort
|
| 358 |
+
from tokenizers import Tokenizer
|
| 359 |
+
|
| 360 |
+
folder = Path(folder)
|
| 361 |
+
graph = folder / "graph.onnx" if (folder / "graph.onnx").exists() else folder / "model.onnx"
|
| 362 |
+
session = ort.InferenceSession(str(graph), providers=["CPUExecutionProvider"])
|
| 363 |
+
config = json.loads((folder / "config.json").read_text())
|
| 364 |
+
tokenizer = Tokenizer.from_file(str(folder / "tokenizer.json"))
|
| 365 |
+
empty = np.zeros((config["layers"], 1, config["heads"], 0, config["dim"] // config["heads"]), np.float32)
|
| 366 |
+
|
| 367 |
+
def next_logits(ids, cache):
|
| 368 |
+
past_k, past_v = cache if cache else (empty, empty)
|
| 369 |
+
logits, k, v = session.run(None, {"input_ids": np.array([ids], np.int64), "past_k": past_k, "past_v": past_v})
|
| 370 |
+
return logits[0], (k, v)
|
| 371 |
+
|
| 372 |
+
special = len(config["special_tokens"])
|
| 373 |
+
texts = [tokenizer.decode([i], skip_special_tokens=False) if i >= special else "" for i in range(config["vocab"])]
|
| 374 |
+
encode = lambda text: tokenizer.encode(text).ids or [0]
|
| 375 |
+
prompt = (lambda prefix, suffix: prefix if not suffix else [2, *suffix, 1, *prefix, 3]) if fim else None
|
| 376 |
+
return TokenLM(name, next_logits, encode, texts, set(range(special)), prompt=prompt)
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
# ---- Scoring ---------------------------------------------------------------------------------------------------
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
def word_by_word(suggestion: str, truth: str) -> int:
|
| 383 |
+
"""Characters you'd keep accepting a word at a time until a word is wrong."""
|
| 384 |
+
kept = 0
|
| 385 |
+
for match in re.finditer(r"\s*\S+", suggestion):
|
| 386 |
+
if truth.startswith(suggestion[: match.end()]):
|
| 387 |
+
kept = match.end()
|
| 388 |
+
else:
|
| 389 |
+
break
|
| 390 |
+
return kept
|
| 391 |
+
|
| 392 |
+
|
| 393 |
+
def score(model: Model, all_pauses: list[Pause]) -> dict:
|
| 394 |
+
results: dict = {"model": model.name, "sees_after": model.sees_after, "cutoffs": {}, "examples": [], "latency_ms": {}}
|
| 395 |
+
latencies: list[float] = []
|
| 396 |
+
raw = []
|
| 397 |
+
for index, pause in enumerate(all_pauses):
|
| 398 |
+
trajectory = model.suggest(pause.before, pause.after if model.sees_after else "")
|
| 399 |
+
latencies.append(trajectory.milliseconds)
|
| 400 |
+
raw.append((pause, trajectory))
|
| 401 |
+
if index % 500 == 0:
|
| 402 |
+
print(f" {model.name}: {index}/{len(all_pauses)} pauses, median {statistics.median(latencies):.1f} ms", flush=True)
|
| 403 |
+
|
| 404 |
+
for cutoff in CUTOFFS:
|
| 405 |
+
table: dict = {}
|
| 406 |
+
for domain in DOMAINS:
|
| 407 |
+
for scenario in SCENARIOS:
|
| 408 |
+
rows = [(p, t.at(cutoff)) for p, t in raw if p.domain == domain and p.scenario == scenario]
|
| 409 |
+
if not rows:
|
| 410 |
+
continue
|
| 411 |
+
shown = [(p, s) for p, s in rows if len(s) >= MIN_SHOWN_CHARS]
|
| 412 |
+
right = [(p, s) for p, s in shown if p.truth.startswith(s)]
|
| 413 |
+
multi = [(p, s) for p, s in shown if len(s.split()) >= 2]
|
| 414 |
+
multi_right = [(p, s) for p, s in multi if p.truth.startswith(s)]
|
| 415 |
+
typed = len(rows) * PAUSE_EVERY
|
| 416 |
+
table[f"{domain}/{scenario}"] = {
|
| 417 |
+
"pauses": len(rows),
|
| 418 |
+
"shown": round(len(shown) / len(rows), 4),
|
| 419 |
+
"right": round(len(right) / max(1, len(shown)), 4),
|
| 420 |
+
"avg_right_chars": round(sum(len(s) for _, s in right) / max(1, len(right)), 2),
|
| 421 |
+
"multiword_shown": round(len(multi) / len(rows), 4),
|
| 422 |
+
"multiword_right": round(len(multi_right) / max(1, len(multi)), 4),
|
| 423 |
+
"saved_with_tab": round(sum(len(s) for _, s in right) / typed, 4),
|
| 424 |
+
"saved_word_by_word": round(sum(word_by_word(s, p.truth) for p, s in shown) / typed, 4),
|
| 425 |
+
}
|
| 426 |
+
results["cutoffs"][str(cutoff)] = table
|
| 427 |
+
|
| 428 |
+
for pause, trajectory in raw[:: max(1, len(raw) // 60)]:
|
| 429 |
+
suggestion = trajectory.at(MAIN_CUTOFF)
|
| 430 |
+
if len(suggestion) >= MIN_SHOWN_CHARS:
|
| 431 |
+
results["examples"].append({
|
| 432 |
+
"domain": pause.domain, "scenario": pause.scenario, "before": pause.before[-60:],
|
| 433 |
+
"suggestion": suggestion, "truth": pause.truth[: len(suggestion) + 12], "right": pause.truth.startswith(suggestion),
|
| 434 |
+
})
|
| 435 |
+
results["latency_ms"] = {
|
| 436 |
+
"p50": round(statistics.median(latencies), 2),
|
| 437 |
+
"p95": round(float(np.percentile(latencies, 95)), 2),
|
| 438 |
+
"note": "Measured in this eval process, not in a browser.",
|
| 439 |
+
}
|
| 440 |
+
return results
|
| 441 |
+
|
| 442 |
+
|
| 443 |
+
# ---- Report ----------------------------------------------------------------------------------------------------
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def table(paths: list[Path]) -> str:
|
| 447 |
+
runs = [json.loads(p.read_text()) for p in paths]
|
| 448 |
+
lines = []
|
| 449 |
+
for scenario in SCENARIOS:
|
| 450 |
+
lines.append(f"\n### {scenario.capitalize()}, {int(MAIN_CUTOFF * 100)}% cutoff, suggestions of {MIN_SHOWN_CHARS}+ characters\n")
|
| 451 |
+
lines.append("| Model | Domain | Shown | Right | Avg right | 2+ words shown | 2+ words right | Saved (Tab) | Saved (word by word) |")
|
| 452 |
+
lines.append("|---|---|---|---|---|---|---|---|---|")
|
| 453 |
+
for run in runs:
|
| 454 |
+
for domain in DOMAINS:
|
| 455 |
+
m = run["cutoffs"][str(MAIN_CUTOFF)].get(f"{domain}/{scenario}")
|
| 456 |
+
if not m:
|
| 457 |
+
continue
|
| 458 |
+
lines.append(
|
| 459 |
+
f"| {run['model']} | {domain} | {m['shown']:.0%} | {m['right']:.0%} | {m['avg_right_chars']:.1f} ch "
|
| 460 |
+
f"| {m['multiword_shown']:.0%} | {m['multiword_right']:.0%} | {m['saved_with_tab']:.1%} | {m['saved_word_by_word']:.1%} |"
|
| 461 |
+
)
|
| 462 |
+
lines.append("\n| Model | Latency p50 | p95 |\n|---|---|---|")
|
| 463 |
+
for run in runs:
|
| 464 |
+
lines.append(f"| {run['model']} | {run['latency_ms']['p50']} ms | {run['latency_ms']['p95']} ms |")
|
| 465 |
+
return "\n".join(lines)
|
| 466 |
+
|
| 467 |
+
|
| 468 |
+
def main():
|
| 469 |
+
parser = argparse.ArgumentParser()
|
| 470 |
+
parser.add_argument("--model", help="Name for the metrics file")
|
| 471 |
+
parser.add_argument("--onnx", help="A character-level GRU exported like enron-autocomplete")
|
| 472 |
+
parser.add_argument("--hf", help="A Hugging Face causal LM to evaluate, e.g. HuggingFaceTB/SmolLM2-135M")
|
| 473 |
+
parser.add_argument("--onnx-lm", help="Folder with a tinynext v2 ONNX export, config.json and tokenizer.json")
|
| 474 |
+
parser.add_argument("--no-fim", action="store_true", help="With --onnx-lm: the model wasn't trained to fill in the middle")
|
| 475 |
+
parser.add_argument("--max-pauses", type=int, default=1000, help="Per domain and scenario")
|
| 476 |
+
parser.add_argument("--table", action="store_true", help="Print a comparison of every metrics/*.json")
|
| 477 |
+
args = parser.parse_args()
|
| 478 |
+
|
| 479 |
+
if args.table:
|
| 480 |
+
print(table(sorted(METRICS.glob("*.json"))))
|
| 481 |
+
return
|
| 482 |
+
if args.onnx:
|
| 483 |
+
model: Model = CharGRU(args.model, args.onnx)
|
| 484 |
+
elif args.hf:
|
| 485 |
+
model = hf_causal_lm(args.model, args.hf)
|
| 486 |
+
elif args.onnx_lm:
|
| 487 |
+
model = onnx_token_lm(args.model, args.onnx_lm, fim=not args.no_fim)
|
| 488 |
+
else:
|
| 489 |
+
parser.error("Pass --onnx, --hf or --table. train.py evaluates its own model through score().")
|
| 490 |
+
all_pauses = pauses(load_eval_set(), args.max_pauses)
|
| 491 |
+
print(f"{len(all_pauses)} pauses", flush=True)
|
| 492 |
+
results = score(model, all_pauses)
|
| 493 |
+
METRICS.mkdir(exist_ok=True)
|
| 494 |
+
(METRICS / f"{args.model}.json").write_text(json.dumps(results, indent=1))
|
| 495 |
+
print(table([METRICS / f"{args.model}.json"]))
|
| 496 |
+
|
| 497 |
+
|
| 498 |
+
if __name__ == "__main__":
|
| 499 |
+
main()
|
v2/experiments/tinynext-v2-nofim/eval_set.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
v2/experiments/tinynext-v2-nofim/metrics/tinynext-v2-nofim.json
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model": "tinynext-v2-nofim",
|
| 3 |
+
"sees_after": false,
|
| 4 |
+
"cutoffs": {
|
| 5 |
+
"0.3": {
|
| 6 |
+
"articles/typing": {
|
| 7 |
+
"pauses": 1000,
|
| 8 |
+
"shown": 0.191,
|
| 9 |
+
"right": 0.5969,
|
| 10 |
+
"avg_right_chars": 5.94,
|
| 11 |
+
"multiword_shown": 0.069,
|
| 12 |
+
"multiword_right": 0.5217,
|
| 13 |
+
"saved_with_tab": 0.0564,
|
| 14 |
+
"saved_word_by_word": 0.064
|
| 15 |
+
},
|
| 16 |
+
"articles/editing": {
|
| 17 |
+
"pauses": 1000,
|
| 18 |
+
"shown": 0.163,
|
| 19 |
+
"right": 0.6074,
|
| 20 |
+
"avg_right_chars": 6.13,
|
| 21 |
+
"multiword_shown": 0.07,
|
| 22 |
+
"multiword_right": 0.6,
|
| 23 |
+
"saved_with_tab": 0.0506,
|
| 24 |
+
"saved_word_by_word": 0.0554
|
| 25 |
+
},
|
| 26 |
+
"messages/typing": {
|
| 27 |
+
"pauses": 1000,
|
| 28 |
+
"shown": 0.3,
|
| 29 |
+
"right": 0.58,
|
| 30 |
+
"avg_right_chars": 7.48,
|
| 31 |
+
"multiword_shown": 0.18,
|
| 32 |
+
"multiword_right": 0.5611,
|
| 33 |
+
"saved_with_tab": 0.1084,
|
| 34 |
+
"saved_word_by_word": 0.1323
|
| 35 |
+
},
|
| 36 |
+
"messages/editing": {
|
| 37 |
+
"pauses": 1000,
|
| 38 |
+
"shown": 0.3,
|
| 39 |
+
"right": 0.5767,
|
| 40 |
+
"avg_right_chars": 7.34,
|
| 41 |
+
"multiword_shown": 0.182,
|
| 42 |
+
"multiword_right": 0.5275,
|
| 43 |
+
"saved_with_tab": 0.1057,
|
| 44 |
+
"saved_word_by_word": 0.1288
|
| 45 |
+
},
|
| 46 |
+
"email/typing": {
|
| 47 |
+
"pauses": 1000,
|
| 48 |
+
"shown": 0.24,
|
| 49 |
+
"right": 0.5292,
|
| 50 |
+
"avg_right_chars": 6.03,
|
| 51 |
+
"multiword_shown": 0.08,
|
| 52 |
+
"multiword_right": 0.45,
|
| 53 |
+
"saved_with_tab": 0.0638,
|
| 54 |
+
"saved_word_by_word": 0.0718
|
| 55 |
+
},
|
| 56 |
+
"email/editing": {
|
| 57 |
+
"pauses": 1000,
|
| 58 |
+
"shown": 0.237,
|
| 59 |
+
"right": 0.557,
|
| 60 |
+
"avg_right_chars": 5.95,
|
| 61 |
+
"multiword_shown": 0.091,
|
| 62 |
+
"multiword_right": 0.5385,
|
| 63 |
+
"saved_with_tab": 0.0655,
|
| 64 |
+
"saved_word_by_word": 0.0717
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
"0.4": {
|
| 68 |
+
"articles/typing": {
|
| 69 |
+
"pauses": 1000,
|
| 70 |
+
"shown": 0.133,
|
| 71 |
+
"right": 0.7293,
|
| 72 |
+
"avg_right_chars": 5.86,
|
| 73 |
+
"multiword_shown": 0.043,
|
| 74 |
+
"multiword_right": 0.7209,
|
| 75 |
+
"saved_with_tab": 0.0473,
|
| 76 |
+
"saved_word_by_word": 0.0497
|
| 77 |
+
},
|
| 78 |
+
"articles/editing": {
|
| 79 |
+
"pauses": 1000,
|
| 80 |
+
"shown": 0.114,
|
| 81 |
+
"right": 0.7281,
|
| 82 |
+
"avg_right_chars": 5.9,
|
| 83 |
+
"multiword_shown": 0.042,
|
| 84 |
+
"multiword_right": 0.7143,
|
| 85 |
+
"saved_with_tab": 0.0408,
|
| 86 |
+
"saved_word_by_word": 0.0436
|
| 87 |
+
},
|
| 88 |
+
"messages/typing": {
|
| 89 |
+
"pauses": 1000,
|
| 90 |
+
"shown": 0.239,
|
| 91 |
+
"right": 0.7071,
|
| 92 |
+
"avg_right_chars": 7.33,
|
| 93 |
+
"multiword_shown": 0.125,
|
| 94 |
+
"multiword_right": 0.712,
|
| 95 |
+
"saved_with_tab": 0.1032,
|
| 96 |
+
"saved_word_by_word": 0.111
|
| 97 |
+
},
|
| 98 |
+
"messages/editing": {
|
| 99 |
+
"pauses": 1000,
|
| 100 |
+
"shown": 0.233,
|
| 101 |
+
"right": 0.6567,
|
| 102 |
+
"avg_right_chars": 7.03,
|
| 103 |
+
"multiword_shown": 0.126,
|
| 104 |
+
"multiword_right": 0.6032,
|
| 105 |
+
"saved_with_tab": 0.0896,
|
| 106 |
+
"saved_word_by_word": 0.1005
|
| 107 |
+
},
|
| 108 |
+
"email/typing": {
|
| 109 |
+
"pauses": 1000,
|
| 110 |
+
"shown": 0.158,
|
| 111 |
+
"right": 0.6392,
|
| 112 |
+
"avg_right_chars": 6.06,
|
| 113 |
+
"multiword_shown": 0.043,
|
| 114 |
+
"multiword_right": 0.5581,
|
| 115 |
+
"saved_with_tab": 0.051,
|
| 116 |
+
"saved_word_by_word": 0.0548
|
| 117 |
+
},
|
| 118 |
+
"email/editing": {
|
| 119 |
+
"pauses": 1000,
|
| 120 |
+
"shown": 0.166,
|
| 121 |
+
"right": 0.6807,
|
| 122 |
+
"avg_right_chars": 5.77,
|
| 123 |
+
"multiword_shown": 0.046,
|
| 124 |
+
"multiword_right": 0.6957,
|
| 125 |
+
"saved_with_tab": 0.0543,
|
| 126 |
+
"saved_word_by_word": 0.0568
|
| 127 |
+
}
|
| 128 |
+
},
|
| 129 |
+
"0.5": {
|
| 130 |
+
"articles/typing": {
|
| 131 |
+
"pauses": 1000,
|
| 132 |
+
"shown": 0.1,
|
| 133 |
+
"right": 0.81,
|
| 134 |
+
"avg_right_chars": 5.74,
|
| 135 |
+
"multiword_shown": 0.03,
|
| 136 |
+
"multiword_right": 0.7667,
|
| 137 |
+
"saved_with_tab": 0.0387,
|
| 138 |
+
"saved_word_by_word": 0.0402
|
| 139 |
+
},
|
| 140 |
+
"articles/editing": {
|
| 141 |
+
"pauses": 1000,
|
| 142 |
+
"shown": 0.084,
|
| 143 |
+
"right": 0.7738,
|
| 144 |
+
"avg_right_chars": 5.6,
|
| 145 |
+
"multiword_shown": 0.028,
|
| 146 |
+
"multiword_right": 0.7143,
|
| 147 |
+
"saved_with_tab": 0.0303,
|
| 148 |
+
"saved_word_by_word": 0.0322
|
| 149 |
+
},
|
| 150 |
+
"messages/typing": {
|
| 151 |
+
"pauses": 1000,
|
| 152 |
+
"shown": 0.182,
|
| 153 |
+
"right": 0.8022,
|
| 154 |
+
"avg_right_chars": 7.25,
|
| 155 |
+
"multiword_shown": 0.084,
|
| 156 |
+
"multiword_right": 0.7976,
|
| 157 |
+
"saved_with_tab": 0.0882,
|
| 158 |
+
"saved_word_by_word": 0.0916
|
| 159 |
+
},
|
| 160 |
+
"messages/editing": {
|
| 161 |
+
"pauses": 1000,
|
| 162 |
+
"shown": 0.17,
|
| 163 |
+
"right": 0.7176,
|
| 164 |
+
"avg_right_chars": 6.76,
|
| 165 |
+
"multiword_shown": 0.088,
|
| 166 |
+
"multiword_right": 0.6364,
|
| 167 |
+
"saved_with_tab": 0.0688,
|
| 168 |
+
"saved_word_by_word": 0.0759
|
| 169 |
+
},
|
| 170 |
+
"email/typing": {
|
| 171 |
+
"pauses": 1000,
|
| 172 |
+
"shown": 0.111,
|
| 173 |
+
"right": 0.7658,
|
| 174 |
+
"avg_right_chars": 5.88,
|
| 175 |
+
"multiword_shown": 0.03,
|
| 176 |
+
"multiword_right": 0.6667,
|
| 177 |
+
"saved_with_tab": 0.0417,
|
| 178 |
+
"saved_word_by_word": 0.0435
|
| 179 |
+
},
|
| 180 |
+
"email/editing": {
|
| 181 |
+
"pauses": 1000,
|
| 182 |
+
"shown": 0.108,
|
| 183 |
+
"right": 0.7963,
|
| 184 |
+
"avg_right_chars": 5.72,
|
| 185 |
+
"multiword_shown": 0.028,
|
| 186 |
+
"multiword_right": 0.75,
|
| 187 |
+
"saved_with_tab": 0.041,
|
| 188 |
+
"saved_word_by_word": 0.0418
|
| 189 |
+
}
|
| 190 |
+
},
|
| 191 |
+
"0.6": {
|
| 192 |
+
"articles/typing": {
|
| 193 |
+
"pauses": 1000,
|
| 194 |
+
"shown": 0.073,
|
| 195 |
+
"right": 0.9041,
|
| 196 |
+
"avg_right_chars": 5.55,
|
| 197 |
+
"multiword_shown": 0.019,
|
| 198 |
+
"multiword_right": 0.8947,
|
| 199 |
+
"saved_with_tab": 0.0305,
|
| 200 |
+
"saved_word_by_word": 0.0308
|
| 201 |
+
},
|
| 202 |
+
"articles/editing": {
|
| 203 |
+
"pauses": 1000,
|
| 204 |
+
"shown": 0.061,
|
| 205 |
+
"right": 0.8525,
|
| 206 |
+
"avg_right_chars": 5.35,
|
| 207 |
+
"multiword_shown": 0.016,
|
| 208 |
+
"multiword_right": 0.75,
|
| 209 |
+
"saved_with_tab": 0.0232,
|
| 210 |
+
"saved_word_by_word": 0.0238
|
| 211 |
+
},
|
| 212 |
+
"messages/typing": {
|
| 213 |
+
"pauses": 1000,
|
| 214 |
+
"shown": 0.139,
|
| 215 |
+
"right": 0.8849,
|
| 216 |
+
"avg_right_chars": 6.95,
|
| 217 |
+
"multiword_shown": 0.057,
|
| 218 |
+
"multiword_right": 0.8947,
|
| 219 |
+
"saved_with_tab": 0.0712,
|
| 220 |
+
"saved_word_by_word": 0.0724
|
| 221 |
+
},
|
| 222 |
+
"messages/editing": {
|
| 223 |
+
"pauses": 1000,
|
| 224 |
+
"shown": 0.124,
|
| 225 |
+
"right": 0.7823,
|
| 226 |
+
"avg_right_chars": 6.55,
|
| 227 |
+
"multiword_shown": 0.062,
|
| 228 |
+
"multiword_right": 0.7258,
|
| 229 |
+
"saved_with_tab": 0.0529,
|
| 230 |
+
"saved_word_by_word": 0.0567
|
| 231 |
+
},
|
| 232 |
+
"email/typing": {
|
| 233 |
+
"pauses": 1000,
|
| 234 |
+
"shown": 0.084,
|
| 235 |
+
"right": 0.8571,
|
| 236 |
+
"avg_right_chars": 5.64,
|
| 237 |
+
"multiword_shown": 0.018,
|
| 238 |
+
"multiword_right": 0.7222,
|
| 239 |
+
"saved_with_tab": 0.0338,
|
| 240 |
+
"saved_word_by_word": 0.0346
|
| 241 |
+
},
|
| 242 |
+
"email/editing": {
|
| 243 |
+
"pauses": 1000,
|
| 244 |
+
"shown": 0.082,
|
| 245 |
+
"right": 0.8659,
|
| 246 |
+
"avg_right_chars": 5.72,
|
| 247 |
+
"multiword_shown": 0.02,
|
| 248 |
+
"multiword_right": 0.75,
|
| 249 |
+
"saved_with_tab": 0.0338,
|
| 250 |
+
"saved_word_by_word": 0.0343
|
| 251 |
+
}
|
| 252 |
+
},
|
| 253 |
+
"0.7": {
|
| 254 |
+
"articles/typing": {
|
| 255 |
+
"pauses": 1000,
|
| 256 |
+
"shown": 0.06,
|
| 257 |
+
"right": 0.9167,
|
| 258 |
+
"avg_right_chars": 5.53,
|
| 259 |
+
"multiword_shown": 0.014,
|
| 260 |
+
"multiword_right": 0.8571,
|
| 261 |
+
"saved_with_tab": 0.0253,
|
| 262 |
+
"saved_word_by_word": 0.0257
|
| 263 |
+
},
|
| 264 |
+
"articles/editing": {
|
| 265 |
+
"pauses": 1000,
|
| 266 |
+
"shown": 0.043,
|
| 267 |
+
"right": 0.907,
|
| 268 |
+
"avg_right_chars": 5.26,
|
| 269 |
+
"multiword_shown": 0.008,
|
| 270 |
+
"multiword_right": 1.0,
|
| 271 |
+
"saved_with_tab": 0.0171,
|
| 272 |
+
"saved_word_by_word": 0.0171
|
| 273 |
+
},
|
| 274 |
+
"messages/typing": {
|
| 275 |
+
"pauses": 1000,
|
| 276 |
+
"shown": 0.104,
|
| 277 |
+
"right": 0.9135,
|
| 278 |
+
"avg_right_chars": 6.86,
|
| 279 |
+
"multiword_shown": 0.042,
|
| 280 |
+
"multiword_right": 0.9048,
|
| 281 |
+
"saved_with_tab": 0.0543,
|
| 282 |
+
"saved_word_by_word": 0.0554
|
| 283 |
+
},
|
| 284 |
+
"messages/editing": {
|
| 285 |
+
"pauses": 1000,
|
| 286 |
+
"shown": 0.096,
|
| 287 |
+
"right": 0.8542,
|
| 288 |
+
"avg_right_chars": 6.28,
|
| 289 |
+
"multiword_shown": 0.042,
|
| 290 |
+
"multiword_right": 0.7857,
|
| 291 |
+
"saved_with_tab": 0.0429,
|
| 292 |
+
"saved_word_by_word": 0.0457
|
| 293 |
+
},
|
| 294 |
+
"email/typing": {
|
| 295 |
+
"pauses": 1000,
|
| 296 |
+
"shown": 0.06,
|
| 297 |
+
"right": 0.85,
|
| 298 |
+
"avg_right_chars": 5.37,
|
| 299 |
+
"multiword_shown": 0.007,
|
| 300 |
+
"multiword_right": 0.5714,
|
| 301 |
+
"saved_with_tab": 0.0228,
|
| 302 |
+
"saved_word_by_word": 0.0229
|
| 303 |
+
},
|
| 304 |
+
"email/editing": {
|
| 305 |
+
"pauses": 1000,
|
| 306 |
+
"shown": 0.062,
|
| 307 |
+
"right": 0.871,
|
| 308 |
+
"avg_right_chars": 5.26,
|
| 309 |
+
"multiword_shown": 0.011,
|
| 310 |
+
"multiword_right": 0.7273,
|
| 311 |
+
"saved_with_tab": 0.0237,
|
| 312 |
+
"saved_word_by_word": 0.0237
|
| 313 |
+
}
|
| 314 |
+
}
|
| 315 |
+
},
|
| 316 |
+
"examples": [
|
| 317 |
+
{
|
| 318 |
+
"domain": "articles",
|
| 319 |
+
"scenario": "editing",
|
| 320 |
+
"before": " the Spaghetti Western film genre) and Hate Boat, were publi",
|
| 321 |
+
"suggestion": "shed",
|
| 322 |
+
"truth": "shed by Comico C",
|
| 323 |
+
"right": true
|
| 324 |
+
},
|
| 325 |
+
{
|
| 326 |
+
"domain": "messages",
|
| 327 |
+
"scenario": "typing",
|
| 328 |
+
"before": "onsidered new. Those decisions make the graphs as neat as po",
|
| 329 |
+
"suggestion": "ssible.",
|
| 330 |
+
"truth": "ssible, and it is t",
|
| 331 |
+
"right": false
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"domain": "messages",
|
| 335 |
+
"scenario": "editing",
|
| 336 |
+
"before": "e optimal level of production and pricing for businesses. L'",
|
| 337 |
+
"suggestion": "Hpital's Rule",
|
| 338 |
+
"truth": "Hpital's Rule can help an",
|
| 339 |
+
"right": true
|
| 340 |
+
},
|
| 341 |
+
{
|
| 342 |
+
"domain": "messages",
|
| 343 |
+
"scenario": "editing",
|
| 344 |
+
"before": "noise tolerance, etc. Games usually provide their minimum an",
|
| 345 |
+
"suggestion": "d maximum",
|
| 346 |
+
"truth": "d recommended CPU, GP",
|
| 347 |
+
"right": false
|
| 348 |
+
},
|
| 349 |
+
{
|
| 350 |
+
"domain": "email",
|
| 351 |
+
"scenario": "editing",
|
| 352 |
+
"before": "ured products and marketing of electricity for the United St",
|
| 353 |
+
"suggestion": "ates",
|
| 354 |
+
"truth": "ates ? Actively ",
|
| 355 |
+
"right": true
|
| 356 |
+
}
|
| 357 |
+
],
|
| 358 |
+
"latency_ms": {
|
| 359 |
+
"p50": 17.29,
|
| 360 |
+
"p95": 47.23,
|
| 361 |
+
"note": "Measured in this eval process, not in a browser."
|
| 362 |
+
}
|
| 363 |
+
}
|
v2/experiments/tinynext-v2-nofim/model.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:18d0779c2fc27062aa39df221e7bcb6514e623a223325c8369f51644c394dcf2
|
| 3 |
+
size 60813561
|
v2/experiments/tinynext-v2-nofim/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:02c5fe5958a6a99de158bf8d3e0b9568b0336572433bda8f4c56e070185e3e57
|
| 3 |
+
size 50161328
|
v2/experiments/tinynext-v2-nofim/model_int8.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:33562588d18f6b26a095fe8c450ea9a954dde454592eed8e5e5f14c623cf5745
|
| 3 |
+
size 15638871
|
v2/experiments/tinynext-v2-nofim/report.json
ADDED
|
@@ -0,0 +1,1239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"args": {
|
| 3 |
+
"vocab": 8192,
|
| 4 |
+
"dim": 320,
|
| 5 |
+
"layers": 8,
|
| 6 |
+
"heads": 5,
|
| 7 |
+
"ffn": 864,
|
| 8 |
+
"seq": 512,
|
| 9 |
+
"tokens": 1500000000.0,
|
| 10 |
+
"val_tokens": 4000000.0,
|
| 11 |
+
"epochs": 1.0,
|
| 12 |
+
"batch": 512,
|
| 13 |
+
"lr": 0.003,
|
| 14 |
+
"fim_rate": 0.0,
|
| 15 |
+
"mix": "fineweb=0.6,smoltalk=0.3,enron=0.1",
|
| 16 |
+
"fineweb_files": 2,
|
| 17 |
+
"smoltalk_files": 9,
|
| 18 |
+
"tokenizer_docs": 200000,
|
| 19 |
+
"eval_pauses": 1000,
|
| 20 |
+
"log_every": 50,
|
| 21 |
+
"repo": "cfahlgren1/tinynext",
|
| 22 |
+
"folder": "v2/experiments/tinynext-v2-nofim",
|
| 23 |
+
"eval_folder": "v2",
|
| 24 |
+
"name": "tinynext-v2-nofim",
|
| 25 |
+
"trackio_space": "cfahlgren1/tinynext-trackio",
|
| 26 |
+
"stage": "train",
|
| 27 |
+
"data_repo": "cfahlgren1/tinynext-data",
|
| 28 |
+
"smoke": false,
|
| 29 |
+
"no_push": false
|
| 30 |
+
},
|
| 31 |
+
"parameters": 12539200,
|
| 32 |
+
"data": {
|
| 33 |
+
"fineweb": {
|
| 34 |
+
"docs": 1062484,
|
| 35 |
+
"train_tokens": 900000000
|
| 36 |
+
},
|
| 37 |
+
"smoltalk": {
|
| 38 |
+
"docs": 671427,
|
| 39 |
+
"train_tokens": 450000000
|
| 40 |
+
},
|
| 41 |
+
"enron": {
|
| 42 |
+
"docs": 268120,
|
| 43 |
+
"train_tokens": 150000000
|
| 44 |
+
}
|
| 45 |
+
},
|
| 46 |
+
"data_minutes": 0.2,
|
| 47 |
+
"train_minutes": 28.1,
|
| 48 |
+
"history": [
|
| 49 |
+
{
|
| 50 |
+
"step": 0,
|
| 51 |
+
"train_loss": 9.066,
|
| 52 |
+
"lr": 2.6e-05,
|
| 53 |
+
"tokens_per_second": 13050,
|
| 54 |
+
"minutes": 0.33,
|
| 55 |
+
"mfu_percent": 0.3,
|
| 56 |
+
"gpu_util_percent": 97,
|
| 57 |
+
"gpu_memory_gb": 70.5,
|
| 58 |
+
"val_loss": 9.0674
|
| 59 |
+
},
|
| 60 |
+
{
|
| 61 |
+
"step": 50,
|
| 62 |
+
"train_loss": 7.0033,
|
| 63 |
+
"lr": 0.001342,
|
| 64 |
+
"tokens_per_second": 933112,
|
| 65 |
+
"minutes": 0.62,
|
| 66 |
+
"mfu_percent": 22.5,
|
| 67 |
+
"gpu_util_percent": 100,
|
| 68 |
+
"gpu_memory_gb": 79.1
|
| 69 |
+
},
|
| 70 |
+
{
|
| 71 |
+
"step": 100,
|
| 72 |
+
"train_loss": 6.1098,
|
| 73 |
+
"lr": 0.002656,
|
| 74 |
+
"tokens_per_second": 926865,
|
| 75 |
+
"minutes": 0.85,
|
| 76 |
+
"mfu_percent": 22.4,
|
| 77 |
+
"gpu_util_percent": 100,
|
| 78 |
+
"gpu_memory_gb": 79.1
|
| 79 |
+
},
|
| 80 |
+
{
|
| 81 |
+
"step": 150,
|
| 82 |
+
"train_loss": 5.5684,
|
| 83 |
+
"lr": 0.002995,
|
| 84 |
+
"tokens_per_second": 926389,
|
| 85 |
+
"minutes": 1.09,
|
| 86 |
+
"mfu_percent": 22.3,
|
| 87 |
+
"gpu_util_percent": 100,
|
| 88 |
+
"gpu_memory_gb": 79.1
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
"step": 200,
|
| 92 |
+
"train_loss": 5.0866,
|
| 93 |
+
"lr": 0.002992,
|
| 94 |
+
"tokens_per_second": 925033,
|
| 95 |
+
"minutes": 1.33,
|
| 96 |
+
"mfu_percent": 22.3,
|
| 97 |
+
"gpu_util_percent": 100,
|
| 98 |
+
"gpu_memory_gb": 79.1
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"step": 250,
|
| 102 |
+
"train_loss": 4.6613,
|
| 103 |
+
"lr": 0.002987,
|
| 104 |
+
"tokens_per_second": 925563,
|
| 105 |
+
"minutes": 1.56,
|
| 106 |
+
"mfu_percent": 22.3,
|
| 107 |
+
"gpu_util_percent": 100,
|
| 108 |
+
"gpu_memory_gb": 79.1
|
| 109 |
+
},
|
| 110 |
+
{
|
| 111 |
+
"step": 300,
|
| 112 |
+
"train_loss": 4.2932,
|
| 113 |
+
"lr": 0.002982,
|
| 114 |
+
"tokens_per_second": 923984,
|
| 115 |
+
"minutes": 1.8,
|
| 116 |
+
"mfu_percent": 22.3,
|
| 117 |
+
"gpu_util_percent": 100,
|
| 118 |
+
"gpu_memory_gb": 79.1
|
| 119 |
+
},
|
| 120 |
+
{
|
| 121 |
+
"step": 350,
|
| 122 |
+
"train_loss": 4.0354,
|
| 123 |
+
"lr": 0.002975,
|
| 124 |
+
"tokens_per_second": 923469,
|
| 125 |
+
"minutes": 2.03,
|
| 126 |
+
"mfu_percent": 22.3,
|
| 127 |
+
"gpu_util_percent": 100,
|
| 128 |
+
"gpu_memory_gb": 79.1
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
"step": 400,
|
| 132 |
+
"train_loss": 3.901,
|
| 133 |
+
"lr": 0.002967,
|
| 134 |
+
"tokens_per_second": 922950,
|
| 135 |
+
"minutes": 2.27,
|
| 136 |
+
"mfu_percent": 22.3,
|
| 137 |
+
"gpu_util_percent": 100,
|
| 138 |
+
"gpu_memory_gb": 79.1
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"step": 450,
|
| 142 |
+
"train_loss": 3.7236,
|
| 143 |
+
"lr": 0.002959,
|
| 144 |
+
"tokens_per_second": 922140,
|
| 145 |
+
"minutes": 2.51,
|
| 146 |
+
"mfu_percent": 22.2,
|
| 147 |
+
"gpu_util_percent": 100,
|
| 148 |
+
"gpu_memory_gb": 79.1
|
| 149 |
+
},
|
| 150 |
+
{
|
| 151 |
+
"step": 500,
|
| 152 |
+
"train_loss": 3.6749,
|
| 153 |
+
"lr": 0.002949,
|
| 154 |
+
"tokens_per_second": 921720,
|
| 155 |
+
"minutes": 2.74,
|
| 156 |
+
"mfu_percent": 22.2,
|
| 157 |
+
"gpu_util_percent": 100,
|
| 158 |
+
"gpu_memory_gb": 79.1,
|
| 159 |
+
"val_loss": 3.6931
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"step": 550,
|
| 163 |
+
"train_loss": 3.6001,
|
| 164 |
+
"lr": 0.002938,
|
| 165 |
+
"tokens_per_second": 921925,
|
| 166 |
+
"minutes": 3.03,
|
| 167 |
+
"mfu_percent": 22.2,
|
| 168 |
+
"gpu_util_percent": 100,
|
| 169 |
+
"gpu_memory_gb": 79.1
|
| 170 |
+
},
|
| 171 |
+
{
|
| 172 |
+
"step": 600,
|
| 173 |
+
"train_loss": 3.5615,
|
| 174 |
+
"lr": 0.002927,
|
| 175 |
+
"tokens_per_second": 922017,
|
| 176 |
+
"minutes": 3.27,
|
| 177 |
+
"mfu_percent": 22.2,
|
| 178 |
+
"gpu_util_percent": 100,
|
| 179 |
+
"gpu_memory_gb": 79.1
|
| 180 |
+
},
|
| 181 |
+
{
|
| 182 |
+
"step": 650,
|
| 183 |
+
"train_loss": 3.5618,
|
| 184 |
+
"lr": 0.002914,
|
| 185 |
+
"tokens_per_second": 922210,
|
| 186 |
+
"minutes": 3.5,
|
| 187 |
+
"mfu_percent": 22.2,
|
| 188 |
+
"gpu_util_percent": 100,
|
| 189 |
+
"gpu_memory_gb": 79.1
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"step": 700,
|
| 193 |
+
"train_loss": 3.453,
|
| 194 |
+
"lr": 0.002901,
|
| 195 |
+
"tokens_per_second": 922179,
|
| 196 |
+
"minutes": 3.74,
|
| 197 |
+
"mfu_percent": 22.2,
|
| 198 |
+
"gpu_util_percent": 100,
|
| 199 |
+
"gpu_memory_gb": 79.1
|
| 200 |
+
},
|
| 201 |
+
{
|
| 202 |
+
"step": 750,
|
| 203 |
+
"train_loss": 3.4649,
|
| 204 |
+
"lr": 0.002886,
|
| 205 |
+
"tokens_per_second": 922152,
|
| 206 |
+
"minutes": 3.98,
|
| 207 |
+
"mfu_percent": 22.2,
|
| 208 |
+
"gpu_util_percent": 100,
|
| 209 |
+
"gpu_memory_gb": 79.1
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"step": 800,
|
| 213 |
+
"train_loss": 3.3789,
|
| 214 |
+
"lr": 0.002871,
|
| 215 |
+
"tokens_per_second": 921856,
|
| 216 |
+
"minutes": 4.21,
|
| 217 |
+
"mfu_percent": 22.2,
|
| 218 |
+
"gpu_util_percent": 100,
|
| 219 |
+
"gpu_memory_gb": 79.1
|
| 220 |
+
},
|
| 221 |
+
{
|
| 222 |
+
"step": 850,
|
| 223 |
+
"train_loss": 3.4502,
|
| 224 |
+
"lr": 0.002855,
|
| 225 |
+
"tokens_per_second": 922127,
|
| 226 |
+
"minutes": 4.45,
|
| 227 |
+
"mfu_percent": 22.2,
|
| 228 |
+
"gpu_util_percent": 100,
|
| 229 |
+
"gpu_memory_gb": 79.1
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"step": 900,
|
| 233 |
+
"train_loss": 3.361,
|
| 234 |
+
"lr": 0.002837,
|
| 235 |
+
"tokens_per_second": 921952,
|
| 236 |
+
"minutes": 4.69,
|
| 237 |
+
"mfu_percent": 22.2,
|
| 238 |
+
"gpu_util_percent": 100,
|
| 239 |
+
"gpu_memory_gb": 79.1
|
| 240 |
+
},
|
| 241 |
+
{
|
| 242 |
+
"step": 950,
|
| 243 |
+
"train_loss": 3.398,
|
| 244 |
+
"lr": 0.002819,
|
| 245 |
+
"tokens_per_second": 922148,
|
| 246 |
+
"minutes": 4.92,
|
| 247 |
+
"mfu_percent": 22.2,
|
| 248 |
+
"gpu_util_percent": 100,
|
| 249 |
+
"gpu_memory_gb": 79.1
|
| 250 |
+
},
|
| 251 |
+
{
|
| 252 |
+
"step": 1000,
|
| 253 |
+
"train_loss": 3.3632,
|
| 254 |
+
"lr": 0.0028,
|
| 255 |
+
"tokens_per_second": 922256,
|
| 256 |
+
"minutes": 5.16,
|
| 257 |
+
"mfu_percent": 22.2,
|
| 258 |
+
"gpu_util_percent": 100,
|
| 259 |
+
"gpu_memory_gb": 79.1,
|
| 260 |
+
"val_loss": 3.3573
|
| 261 |
+
},
|
| 262 |
+
{
|
| 263 |
+
"step": 1050,
|
| 264 |
+
"train_loss": 3.276,
|
| 265 |
+
"lr": 0.002781,
|
| 266 |
+
"tokens_per_second": 923002,
|
| 267 |
+
"minutes": 5.44,
|
| 268 |
+
"mfu_percent": 22.3,
|
| 269 |
+
"gpu_util_percent": 100,
|
| 270 |
+
"gpu_memory_gb": 79.1
|
| 271 |
+
},
|
| 272 |
+
{
|
| 273 |
+
"step": 1100,
|
| 274 |
+
"train_loss": 3.2999,
|
| 275 |
+
"lr": 0.00276,
|
| 276 |
+
"tokens_per_second": 923065,
|
| 277 |
+
"minutes": 5.68,
|
| 278 |
+
"mfu_percent": 22.3,
|
| 279 |
+
"gpu_util_percent": 100,
|
| 280 |
+
"gpu_memory_gb": 79.1
|
| 281 |
+
},
|
| 282 |
+
{
|
| 283 |
+
"step": 1150,
|
| 284 |
+
"train_loss": 3.346,
|
| 285 |
+
"lr": 0.002738,
|
| 286 |
+
"tokens_per_second": 923089,
|
| 287 |
+
"minutes": 5.92,
|
| 288 |
+
"mfu_percent": 22.3,
|
| 289 |
+
"gpu_util_percent": 100,
|
| 290 |
+
"gpu_memory_gb": 79.1
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"step": 1200,
|
| 294 |
+
"train_loss": 3.2729,
|
| 295 |
+
"lr": 0.002716,
|
| 296 |
+
"tokens_per_second": 922983,
|
| 297 |
+
"minutes": 6.15,
|
| 298 |
+
"mfu_percent": 22.3,
|
| 299 |
+
"gpu_util_percent": 100,
|
| 300 |
+
"gpu_memory_gb": 79.1
|
| 301 |
+
},
|
| 302 |
+
{
|
| 303 |
+
"step": 1250,
|
| 304 |
+
"train_loss": 3.2381,
|
| 305 |
+
"lr": 0.002693,
|
| 306 |
+
"tokens_per_second": 922842,
|
| 307 |
+
"minutes": 6.39,
|
| 308 |
+
"mfu_percent": 22.3,
|
| 309 |
+
"gpu_util_percent": 100,
|
| 310 |
+
"gpu_memory_gb": 79.1
|
| 311 |
+
},
|
| 312 |
+
{
|
| 313 |
+
"step": 1300,
|
| 314 |
+
"train_loss": 3.2686,
|
| 315 |
+
"lr": 0.002669,
|
| 316 |
+
"tokens_per_second": 922738,
|
| 317 |
+
"minutes": 6.63,
|
| 318 |
+
"mfu_percent": 22.3,
|
| 319 |
+
"gpu_util_percent": 100,
|
| 320 |
+
"gpu_memory_gb": 79.1
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"step": 1350,
|
| 324 |
+
"train_loss": 3.2762,
|
| 325 |
+
"lr": 0.002644,
|
| 326 |
+
"tokens_per_second": 922862,
|
| 327 |
+
"minutes": 6.86,
|
| 328 |
+
"mfu_percent": 22.3,
|
| 329 |
+
"gpu_util_percent": 100,
|
| 330 |
+
"gpu_memory_gb": 79.1
|
| 331 |
+
},
|
| 332 |
+
{
|
| 333 |
+
"step": 1400,
|
| 334 |
+
"train_loss": 3.2013,
|
| 335 |
+
"lr": 0.002618,
|
| 336 |
+
"tokens_per_second": 922796,
|
| 337 |
+
"minutes": 7.1,
|
| 338 |
+
"mfu_percent": 22.3,
|
| 339 |
+
"gpu_util_percent": 100,
|
| 340 |
+
"gpu_memory_gb": 79.1
|
| 341 |
+
},
|
| 342 |
+
{
|
| 343 |
+
"step": 1450,
|
| 344 |
+
"train_loss": 3.1987,
|
| 345 |
+
"lr": 0.002592,
|
| 346 |
+
"tokens_per_second": 923059,
|
| 347 |
+
"minutes": 7.34,
|
| 348 |
+
"mfu_percent": 22.3,
|
| 349 |
+
"gpu_util_percent": 100,
|
| 350 |
+
"gpu_memory_gb": 79.1
|
| 351 |
+
},
|
| 352 |
+
{
|
| 353 |
+
"step": 1500,
|
| 354 |
+
"train_loss": 3.2144,
|
| 355 |
+
"lr": 0.002565,
|
| 356 |
+
"tokens_per_second": 922750,
|
| 357 |
+
"minutes": 7.57,
|
| 358 |
+
"mfu_percent": 22.3,
|
| 359 |
+
"gpu_util_percent": 100,
|
| 360 |
+
"gpu_memory_gb": 79.1,
|
| 361 |
+
"val_loss": 3.2337
|
| 362 |
+
},
|
| 363 |
+
{
|
| 364 |
+
"step": 1550,
|
| 365 |
+
"train_loss": 3.1748,
|
| 366 |
+
"lr": 0.002538,
|
| 367 |
+
"tokens_per_second": 922943,
|
| 368 |
+
"minutes": 7.86,
|
| 369 |
+
"mfu_percent": 22.3,
|
| 370 |
+
"gpu_util_percent": 100,
|
| 371 |
+
"gpu_memory_gb": 79.1
|
| 372 |
+
},
|
| 373 |
+
{
|
| 374 |
+
"step": 1600,
|
| 375 |
+
"train_loss": 3.2102,
|
| 376 |
+
"lr": 0.002509,
|
| 377 |
+
"tokens_per_second": 922876,
|
| 378 |
+
"minutes": 8.1,
|
| 379 |
+
"mfu_percent": 22.3,
|
| 380 |
+
"gpu_util_percent": 100,
|
| 381 |
+
"gpu_memory_gb": 79.1
|
| 382 |
+
},
|
| 383 |
+
{
|
| 384 |
+
"step": 1650,
|
| 385 |
+
"train_loss": 3.1717,
|
| 386 |
+
"lr": 0.00248,
|
| 387 |
+
"tokens_per_second": 923021,
|
| 388 |
+
"minutes": 8.33,
|
| 389 |
+
"mfu_percent": 22.3,
|
| 390 |
+
"gpu_util_percent": 100,
|
| 391 |
+
"gpu_memory_gb": 79.1
|
| 392 |
+
},
|
| 393 |
+
{
|
| 394 |
+
"step": 1700,
|
| 395 |
+
"train_loss": 3.215,
|
| 396 |
+
"lr": 0.002451,
|
| 397 |
+
"tokens_per_second": 922818,
|
| 398 |
+
"minutes": 8.57,
|
| 399 |
+
"mfu_percent": 22.3,
|
| 400 |
+
"gpu_util_percent": 100,
|
| 401 |
+
"gpu_memory_gb": 79.1
|
| 402 |
+
},
|
| 403 |
+
{
|
| 404 |
+
"step": 1750,
|
| 405 |
+
"train_loss": 3.2434,
|
| 406 |
+
"lr": 0.002421,
|
| 407 |
+
"tokens_per_second": 923028,
|
| 408 |
+
"minutes": 8.81,
|
| 409 |
+
"mfu_percent": 22.3,
|
| 410 |
+
"gpu_util_percent": 100,
|
| 411 |
+
"gpu_memory_gb": 79.1
|
| 412 |
+
},
|
| 413 |
+
{
|
| 414 |
+
"step": 1800,
|
| 415 |
+
"train_loss": 3.1329,
|
| 416 |
+
"lr": 0.00239,
|
| 417 |
+
"tokens_per_second": 922698,
|
| 418 |
+
"minutes": 9.04,
|
| 419 |
+
"mfu_percent": 22.2,
|
| 420 |
+
"gpu_util_percent": 100,
|
| 421 |
+
"gpu_memory_gb": 79.1
|
| 422 |
+
},
|
| 423 |
+
{
|
| 424 |
+
"step": 1850,
|
| 425 |
+
"train_loss": 3.1663,
|
| 426 |
+
"lr": 0.002358,
|
| 427 |
+
"tokens_per_second": 922517,
|
| 428 |
+
"minutes": 9.28,
|
| 429 |
+
"mfu_percent": 22.2,
|
| 430 |
+
"gpu_util_percent": 100,
|
| 431 |
+
"gpu_memory_gb": 79.1
|
| 432 |
+
},
|
| 433 |
+
{
|
| 434 |
+
"step": 1900,
|
| 435 |
+
"train_loss": 3.1417,
|
| 436 |
+
"lr": 0.002327,
|
| 437 |
+
"tokens_per_second": 922580,
|
| 438 |
+
"minutes": 9.52,
|
| 439 |
+
"mfu_percent": 22.2,
|
| 440 |
+
"gpu_util_percent": 100,
|
| 441 |
+
"gpu_memory_gb": 79.1
|
| 442 |
+
},
|
| 443 |
+
{
|
| 444 |
+
"step": 1950,
|
| 445 |
+
"train_loss": 3.1055,
|
| 446 |
+
"lr": 0.002294,
|
| 447 |
+
"tokens_per_second": 922863,
|
| 448 |
+
"minutes": 9.75,
|
| 449 |
+
"mfu_percent": 22.3,
|
| 450 |
+
"gpu_util_percent": 100,
|
| 451 |
+
"gpu_memory_gb": 79.1
|
| 452 |
+
},
|
| 453 |
+
{
|
| 454 |
+
"step": 2000,
|
| 455 |
+
"train_loss": 3.1488,
|
| 456 |
+
"lr": 0.002261,
|
| 457 |
+
"tokens_per_second": 922511,
|
| 458 |
+
"minutes": 9.99,
|
| 459 |
+
"mfu_percent": 22.2,
|
| 460 |
+
"gpu_util_percent": 100,
|
| 461 |
+
"gpu_memory_gb": 79.1,
|
| 462 |
+
"val_loss": 3.1599
|
| 463 |
+
},
|
| 464 |
+
{
|
| 465 |
+
"step": 2050,
|
| 466 |
+
"train_loss": 3.0741,
|
| 467 |
+
"lr": 0.002228,
|
| 468 |
+
"tokens_per_second": 922742,
|
| 469 |
+
"minutes": 10.27,
|
| 470 |
+
"mfu_percent": 22.3,
|
| 471 |
+
"gpu_util_percent": 100,
|
| 472 |
+
"gpu_memory_gb": 79.1
|
| 473 |
+
},
|
| 474 |
+
{
|
| 475 |
+
"step": 2100,
|
| 476 |
+
"train_loss": 3.1161,
|
| 477 |
+
"lr": 0.002194,
|
| 478 |
+
"tokens_per_second": 922930,
|
| 479 |
+
"minutes": 10.51,
|
| 480 |
+
"mfu_percent": 22.3,
|
| 481 |
+
"gpu_util_percent": 100,
|
| 482 |
+
"gpu_memory_gb": 79.1
|
| 483 |
+
},
|
| 484 |
+
{
|
| 485 |
+
"step": 2150,
|
| 486 |
+
"train_loss": 3.1425,
|
| 487 |
+
"lr": 0.00216,
|
| 488 |
+
"tokens_per_second": 922993,
|
| 489 |
+
"minutes": 10.75,
|
| 490 |
+
"mfu_percent": 22.3,
|
| 491 |
+
"gpu_util_percent": 100,
|
| 492 |
+
"gpu_memory_gb": 79.1
|
| 493 |
+
},
|
| 494 |
+
{
|
| 495 |
+
"step": 2200,
|
| 496 |
+
"train_loss": 3.1001,
|
| 497 |
+
"lr": 0.002125,
|
| 498 |
+
"tokens_per_second": 922882,
|
| 499 |
+
"minutes": 10.98,
|
| 500 |
+
"mfu_percent": 22.3,
|
| 501 |
+
"gpu_util_percent": 100,
|
| 502 |
+
"gpu_memory_gb": 79.1
|
| 503 |
+
},
|
| 504 |
+
{
|
| 505 |
+
"step": 2250,
|
| 506 |
+
"train_loss": 3.1289,
|
| 507 |
+
"lr": 0.00209,
|
| 508 |
+
"tokens_per_second": 922732,
|
| 509 |
+
"minutes": 11.22,
|
| 510 |
+
"mfu_percent": 22.3,
|
| 511 |
+
"gpu_util_percent": 100,
|
| 512 |
+
"gpu_memory_gb": 79.1
|
| 513 |
+
},
|
| 514 |
+
{
|
| 515 |
+
"step": 2300,
|
| 516 |
+
"train_loss": 3.1166,
|
| 517 |
+
"lr": 0.002055,
|
| 518 |
+
"tokens_per_second": 922818,
|
| 519 |
+
"minutes": 11.46,
|
| 520 |
+
"mfu_percent": 22.3,
|
| 521 |
+
"gpu_util_percent": 100,
|
| 522 |
+
"gpu_memory_gb": 79.1
|
| 523 |
+
},
|
| 524 |
+
{
|
| 525 |
+
"step": 2350,
|
| 526 |
+
"train_loss": 3.0936,
|
| 527 |
+
"lr": 0.00202,
|
| 528 |
+
"tokens_per_second": 923024,
|
| 529 |
+
"minutes": 11.69,
|
| 530 |
+
"mfu_percent": 22.3,
|
| 531 |
+
"gpu_util_percent": 100,
|
| 532 |
+
"gpu_memory_gb": 79.1
|
| 533 |
+
},
|
| 534 |
+
{
|
| 535 |
+
"step": 2400,
|
| 536 |
+
"train_loss": 3.1052,
|
| 537 |
+
"lr": 0.001984,
|
| 538 |
+
"tokens_per_second": 922709,
|
| 539 |
+
"minutes": 11.93,
|
| 540 |
+
"mfu_percent": 22.3,
|
| 541 |
+
"gpu_util_percent": 100,
|
| 542 |
+
"gpu_memory_gb": 79.1
|
| 543 |
+
},
|
| 544 |
+
{
|
| 545 |
+
"step": 2450,
|
| 546 |
+
"train_loss": 3.0901,
|
| 547 |
+
"lr": 0.001948,
|
| 548 |
+
"tokens_per_second": 922648,
|
| 549 |
+
"minutes": 12.17,
|
| 550 |
+
"mfu_percent": 22.2,
|
| 551 |
+
"gpu_util_percent": 100,
|
| 552 |
+
"gpu_memory_gb": 79.1
|
| 553 |
+
},
|
| 554 |
+
{
|
| 555 |
+
"step": 2500,
|
| 556 |
+
"train_loss": 3.094,
|
| 557 |
+
"lr": 0.001911,
|
| 558 |
+
"tokens_per_second": 922464,
|
| 559 |
+
"minutes": 12.4,
|
| 560 |
+
"mfu_percent": 22.2,
|
| 561 |
+
"gpu_util_percent": 100,
|
| 562 |
+
"gpu_memory_gb": 79.1,
|
| 563 |
+
"val_loss": 3.1067
|
| 564 |
+
},
|
| 565 |
+
{
|
| 566 |
+
"step": 2550,
|
| 567 |
+
"train_loss": 3.1594,
|
| 568 |
+
"lr": 0.001875,
|
| 569 |
+
"tokens_per_second": 922698,
|
| 570 |
+
"minutes": 12.69,
|
| 571 |
+
"mfu_percent": 22.2,
|
| 572 |
+
"gpu_util_percent": 100,
|
| 573 |
+
"gpu_memory_gb": 79.1
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"step": 2600,
|
| 577 |
+
"train_loss": 3.1005,
|
| 578 |
+
"lr": 0.001838,
|
| 579 |
+
"tokens_per_second": 922773,
|
| 580 |
+
"minutes": 12.92,
|
| 581 |
+
"mfu_percent": 22.3,
|
| 582 |
+
"gpu_util_percent": 100,
|
| 583 |
+
"gpu_memory_gb": 79.1
|
| 584 |
+
},
|
| 585 |
+
{
|
| 586 |
+
"step": 2650,
|
| 587 |
+
"train_loss": 3.0486,
|
| 588 |
+
"lr": 0.001801,
|
| 589 |
+
"tokens_per_second": 922597,
|
| 590 |
+
"minutes": 13.16,
|
| 591 |
+
"mfu_percent": 22.2,
|
| 592 |
+
"gpu_util_percent": 100,
|
| 593 |
+
"gpu_memory_gb": 79.1
|
| 594 |
+
},
|
| 595 |
+
{
|
| 596 |
+
"step": 2700,
|
| 597 |
+
"train_loss": 3.045,
|
| 598 |
+
"lr": 0.001764,
|
| 599 |
+
"tokens_per_second": 922925,
|
| 600 |
+
"minutes": 13.4,
|
| 601 |
+
"mfu_percent": 22.3,
|
| 602 |
+
"gpu_util_percent": 100,
|
| 603 |
+
"gpu_memory_gb": 79.1
|
| 604 |
+
},
|
| 605 |
+
{
|
| 606 |
+
"step": 2750,
|
| 607 |
+
"train_loss": 3.0978,
|
| 608 |
+
"lr": 0.001727,
|
| 609 |
+
"tokens_per_second": 922957,
|
| 610 |
+
"minutes": 13.63,
|
| 611 |
+
"mfu_percent": 22.3,
|
| 612 |
+
"gpu_util_percent": 100,
|
| 613 |
+
"gpu_memory_gb": 79.1
|
| 614 |
+
},
|
| 615 |
+
{
|
| 616 |
+
"step": 2800,
|
| 617 |
+
"train_loss": 3.0068,
|
| 618 |
+
"lr": 0.00169,
|
| 619 |
+
"tokens_per_second": 922829,
|
| 620 |
+
"minutes": 13.87,
|
| 621 |
+
"mfu_percent": 22.3,
|
| 622 |
+
"gpu_util_percent": 100,
|
| 623 |
+
"gpu_memory_gb": 79.1
|
| 624 |
+
},
|
| 625 |
+
{
|
| 626 |
+
"step": 2850,
|
| 627 |
+
"train_loss": 2.999,
|
| 628 |
+
"lr": 0.001653,
|
| 629 |
+
"tokens_per_second": 922756,
|
| 630 |
+
"minutes": 14.11,
|
| 631 |
+
"mfu_percent": 22.3,
|
| 632 |
+
"gpu_util_percent": 100,
|
| 633 |
+
"gpu_memory_gb": 79.1
|
| 634 |
+
},
|
| 635 |
+
{
|
| 636 |
+
"step": 2900,
|
| 637 |
+
"train_loss": 3.0705,
|
| 638 |
+
"lr": 0.001616,
|
| 639 |
+
"tokens_per_second": 922667,
|
| 640 |
+
"minutes": 14.34,
|
| 641 |
+
"mfu_percent": 22.2,
|
| 642 |
+
"gpu_util_percent": 100,
|
| 643 |
+
"gpu_memory_gb": 79.1
|
| 644 |
+
},
|
| 645 |
+
{
|
| 646 |
+
"step": 2950,
|
| 647 |
+
"train_loss": 3.0176,
|
| 648 |
+
"lr": 0.001579,
|
| 649 |
+
"tokens_per_second": 922610,
|
| 650 |
+
"minutes": 14.58,
|
| 651 |
+
"mfu_percent": 22.2,
|
| 652 |
+
"gpu_util_percent": 100,
|
| 653 |
+
"gpu_memory_gb": 79.1
|
| 654 |
+
},
|
| 655 |
+
{
|
| 656 |
+
"step": 3000,
|
| 657 |
+
"train_loss": 3.015,
|
| 658 |
+
"lr": 0.001542,
|
| 659 |
+
"tokens_per_second": 922714,
|
| 660 |
+
"minutes": 14.82,
|
| 661 |
+
"mfu_percent": 22.3,
|
| 662 |
+
"gpu_util_percent": 100,
|
| 663 |
+
"gpu_memory_gb": 79.1,
|
| 664 |
+
"val_loss": 3.0619
|
| 665 |
+
},
|
| 666 |
+
{
|
| 667 |
+
"step": 3050,
|
| 668 |
+
"train_loss": 3.0686,
|
| 669 |
+
"lr": 0.001505,
|
| 670 |
+
"tokens_per_second": 922937,
|
| 671 |
+
"minutes": 15.1,
|
| 672 |
+
"mfu_percent": 22.3,
|
| 673 |
+
"gpu_util_percent": 100,
|
| 674 |
+
"gpu_memory_gb": 79.1
|
| 675 |
+
},
|
| 676 |
+
{
|
| 677 |
+
"step": 3100,
|
| 678 |
+
"train_loss": 3.0109,
|
| 679 |
+
"lr": 0.001468,
|
| 680 |
+
"tokens_per_second": 922847,
|
| 681 |
+
"minutes": 15.34,
|
| 682 |
+
"mfu_percent": 22.3,
|
| 683 |
+
"gpu_util_percent": 100,
|
| 684 |
+
"gpu_memory_gb": 79.1
|
| 685 |
+
},
|
| 686 |
+
{
|
| 687 |
+
"step": 3150,
|
| 688 |
+
"train_loss": 2.9785,
|
| 689 |
+
"lr": 0.001431,
|
| 690 |
+
"tokens_per_second": 922659,
|
| 691 |
+
"minutes": 15.58,
|
| 692 |
+
"mfu_percent": 22.2,
|
| 693 |
+
"gpu_util_percent": 100,
|
| 694 |
+
"gpu_memory_gb": 79.1
|
| 695 |
+
},
|
| 696 |
+
{
|
| 697 |
+
"step": 3200,
|
| 698 |
+
"train_loss": 3.0064,
|
| 699 |
+
"lr": 0.001395,
|
| 700 |
+
"tokens_per_second": 922762,
|
| 701 |
+
"minutes": 15.81,
|
| 702 |
+
"mfu_percent": 22.3,
|
| 703 |
+
"gpu_util_percent": 100,
|
| 704 |
+
"gpu_memory_gb": 79.1
|
| 705 |
+
},
|
| 706 |
+
{
|
| 707 |
+
"step": 3250,
|
| 708 |
+
"train_loss": 3.0779,
|
| 709 |
+
"lr": 0.001358,
|
| 710 |
+
"tokens_per_second": 923029,
|
| 711 |
+
"minutes": 16.05,
|
| 712 |
+
"mfu_percent": 22.3,
|
| 713 |
+
"gpu_util_percent": 100,
|
| 714 |
+
"gpu_memory_gb": 79.1
|
| 715 |
+
},
|
| 716 |
+
{
|
| 717 |
+
"step": 3300,
|
| 718 |
+
"train_loss": 3.0103,
|
| 719 |
+
"lr": 0.001322,
|
| 720 |
+
"tokens_per_second": 922850,
|
| 721 |
+
"minutes": 16.29,
|
| 722 |
+
"mfu_percent": 22.3,
|
| 723 |
+
"gpu_util_percent": 100,
|
| 724 |
+
"gpu_memory_gb": 79.1
|
| 725 |
+
},
|
| 726 |
+
{
|
| 727 |
+
"step": 3350,
|
| 728 |
+
"train_loss": 3.0329,
|
| 729 |
+
"lr": 0.001286,
|
| 730 |
+
"tokens_per_second": 922649,
|
| 731 |
+
"minutes": 16.52,
|
| 732 |
+
"mfu_percent": 22.2,
|
| 733 |
+
"gpu_util_percent": 100,
|
| 734 |
+
"gpu_memory_gb": 79.1
|
| 735 |
+
},
|
| 736 |
+
{
|
| 737 |
+
"step": 3400,
|
| 738 |
+
"train_loss": 2.9922,
|
| 739 |
+
"lr": 0.001251,
|
| 740 |
+
"tokens_per_second": 922830,
|
| 741 |
+
"minutes": 16.76,
|
| 742 |
+
"mfu_percent": 22.3,
|
| 743 |
+
"gpu_util_percent": 100,
|
| 744 |
+
"gpu_memory_gb": 79.1
|
| 745 |
+
},
|
| 746 |
+
{
|
| 747 |
+
"step": 3450,
|
| 748 |
+
"train_loss": 2.9825,
|
| 749 |
+
"lr": 0.001215,
|
| 750 |
+
"tokens_per_second": 922466,
|
| 751 |
+
"minutes": 17.0,
|
| 752 |
+
"mfu_percent": 22.2,
|
| 753 |
+
"gpu_util_percent": 100,
|
| 754 |
+
"gpu_memory_gb": 79.1
|
| 755 |
+
},
|
| 756 |
+
{
|
| 757 |
+
"step": 3500,
|
| 758 |
+
"train_loss": 2.9975,
|
| 759 |
+
"lr": 0.00118,
|
| 760 |
+
"tokens_per_second": 922482,
|
| 761 |
+
"minutes": 17.23,
|
| 762 |
+
"mfu_percent": 22.2,
|
| 763 |
+
"gpu_util_percent": 100,
|
| 764 |
+
"gpu_memory_gb": 79.1,
|
| 765 |
+
"val_loss": 3.0243
|
| 766 |
+
},
|
| 767 |
+
{
|
| 768 |
+
"step": 3550,
|
| 769 |
+
"train_loss": 3.0041,
|
| 770 |
+
"lr": 0.001146,
|
| 771 |
+
"tokens_per_second": 922239,
|
| 772 |
+
"minutes": 17.52,
|
| 773 |
+
"mfu_percent": 22.2,
|
| 774 |
+
"gpu_util_percent": 100,
|
| 775 |
+
"gpu_memory_gb": 79.1
|
| 776 |
+
},
|
| 777 |
+
{
|
| 778 |
+
"step": 3600,
|
| 779 |
+
"train_loss": 3.0208,
|
| 780 |
+
"lr": 0.001111,
|
| 781 |
+
"tokens_per_second": 921706,
|
| 782 |
+
"minutes": 17.75,
|
| 783 |
+
"mfu_percent": 22.2,
|
| 784 |
+
"gpu_util_percent": 100,
|
| 785 |
+
"gpu_memory_gb": 79.1
|
| 786 |
+
},
|
| 787 |
+
{
|
| 788 |
+
"step": 3650,
|
| 789 |
+
"train_loss": 2.9875,
|
| 790 |
+
"lr": 0.001077,
|
| 791 |
+
"tokens_per_second": 921485,
|
| 792 |
+
"minutes": 17.99,
|
| 793 |
+
"mfu_percent": 22.2,
|
| 794 |
+
"gpu_util_percent": 100,
|
| 795 |
+
"gpu_memory_gb": 79.1
|
| 796 |
+
},
|
| 797 |
+
{
|
| 798 |
+
"step": 3700,
|
| 799 |
+
"train_loss": 3.0218,
|
| 800 |
+
"lr": 0.001044,
|
| 801 |
+
"tokens_per_second": 921567,
|
| 802 |
+
"minutes": 18.23,
|
| 803 |
+
"mfu_percent": 22.2,
|
| 804 |
+
"gpu_util_percent": 100,
|
| 805 |
+
"gpu_memory_gb": 79.1
|
| 806 |
+
},
|
| 807 |
+
{
|
| 808 |
+
"step": 3750,
|
| 809 |
+
"train_loss": 2.9973,
|
| 810 |
+
"lr": 0.001011,
|
| 811 |
+
"tokens_per_second": 922249,
|
| 812 |
+
"minutes": 18.46,
|
| 813 |
+
"mfu_percent": 22.2,
|
| 814 |
+
"gpu_util_percent": 100,
|
| 815 |
+
"gpu_memory_gb": 79.1
|
| 816 |
+
},
|
| 817 |
+
{
|
| 818 |
+
"step": 3800,
|
| 819 |
+
"train_loss": 2.9779,
|
| 820 |
+
"lr": 0.000979,
|
| 821 |
+
"tokens_per_second": 923901,
|
| 822 |
+
"minutes": 18.7,
|
| 823 |
+
"mfu_percent": 22.3,
|
| 824 |
+
"gpu_util_percent": 100,
|
| 825 |
+
"gpu_memory_gb": 79.1
|
| 826 |
+
},
|
| 827 |
+
{
|
| 828 |
+
"step": 3850,
|
| 829 |
+
"train_loss": 3.0253,
|
| 830 |
+
"lr": 0.000947,
|
| 831 |
+
"tokens_per_second": 924971,
|
| 832 |
+
"minutes": 18.94,
|
| 833 |
+
"mfu_percent": 22.3,
|
| 834 |
+
"gpu_util_percent": 100,
|
| 835 |
+
"gpu_memory_gb": 79.1
|
| 836 |
+
},
|
| 837 |
+
{
|
| 838 |
+
"step": 3900,
|
| 839 |
+
"train_loss": 2.9768,
|
| 840 |
+
"lr": 0.000915,
|
| 841 |
+
"tokens_per_second": 924295,
|
| 842 |
+
"minutes": 19.17,
|
| 843 |
+
"mfu_percent": 22.3,
|
| 844 |
+
"gpu_util_percent": 100,
|
| 845 |
+
"gpu_memory_gb": 79.1
|
| 846 |
+
},
|
| 847 |
+
{
|
| 848 |
+
"step": 3950,
|
| 849 |
+
"train_loss": 2.9955,
|
| 850 |
+
"lr": 0.000884,
|
| 851 |
+
"tokens_per_second": 924314,
|
| 852 |
+
"minutes": 19.41,
|
| 853 |
+
"mfu_percent": 22.3,
|
| 854 |
+
"gpu_util_percent": 100,
|
| 855 |
+
"gpu_memory_gb": 79.1
|
| 856 |
+
},
|
| 857 |
+
{
|
| 858 |
+
"step": 4000,
|
| 859 |
+
"train_loss": 2.9672,
|
| 860 |
+
"lr": 0.000854,
|
| 861 |
+
"tokens_per_second": 923365,
|
| 862 |
+
"minutes": 19.65,
|
| 863 |
+
"mfu_percent": 22.3,
|
| 864 |
+
"gpu_util_percent": 100,
|
| 865 |
+
"gpu_memory_gb": 79.1,
|
| 866 |
+
"val_loss": 2.9912
|
| 867 |
+
},
|
| 868 |
+
{
|
| 869 |
+
"step": 4050,
|
| 870 |
+
"train_loss": 2.982,
|
| 871 |
+
"lr": 0.000824,
|
| 872 |
+
"tokens_per_second": 923158,
|
| 873 |
+
"minutes": 19.93,
|
| 874 |
+
"mfu_percent": 22.3,
|
| 875 |
+
"gpu_util_percent": 100,
|
| 876 |
+
"gpu_memory_gb": 79.1
|
| 877 |
+
},
|
| 878 |
+
{
|
| 879 |
+
"step": 4100,
|
| 880 |
+
"train_loss": 2.9381,
|
| 881 |
+
"lr": 0.000795,
|
| 882 |
+
"tokens_per_second": 922493,
|
| 883 |
+
"minutes": 20.17,
|
| 884 |
+
"mfu_percent": 22.2,
|
| 885 |
+
"gpu_util_percent": 100,
|
| 886 |
+
"gpu_memory_gb": 79.1
|
| 887 |
+
},
|
| 888 |
+
{
|
| 889 |
+
"step": 4150,
|
| 890 |
+
"train_loss": 2.96,
|
| 891 |
+
"lr": 0.000767,
|
| 892 |
+
"tokens_per_second": 922454,
|
| 893 |
+
"minutes": 20.4,
|
| 894 |
+
"mfu_percent": 22.2,
|
| 895 |
+
"gpu_util_percent": 100,
|
| 896 |
+
"gpu_memory_gb": 79.1
|
| 897 |
+
},
|
| 898 |
+
{
|
| 899 |
+
"step": 4200,
|
| 900 |
+
"train_loss": 2.9844,
|
| 901 |
+
"lr": 0.000739,
|
| 902 |
+
"tokens_per_second": 924196,
|
| 903 |
+
"minutes": 20.64,
|
| 904 |
+
"mfu_percent": 22.3,
|
| 905 |
+
"gpu_util_percent": 100,
|
| 906 |
+
"gpu_memory_gb": 79.1
|
| 907 |
+
},
|
| 908 |
+
{
|
| 909 |
+
"step": 4250,
|
| 910 |
+
"train_loss": 2.9594,
|
| 911 |
+
"lr": 0.000712,
|
| 912 |
+
"tokens_per_second": 925585,
|
| 913 |
+
"minutes": 20.88,
|
| 914 |
+
"mfu_percent": 22.3,
|
| 915 |
+
"gpu_util_percent": 100,
|
| 916 |
+
"gpu_memory_gb": 79.1
|
| 917 |
+
},
|
| 918 |
+
{
|
| 919 |
+
"step": 4300,
|
| 920 |
+
"train_loss": 2.9844,
|
| 921 |
+
"lr": 0.000686,
|
| 922 |
+
"tokens_per_second": 925297,
|
| 923 |
+
"minutes": 21.11,
|
| 924 |
+
"mfu_percent": 22.3,
|
| 925 |
+
"gpu_util_percent": 100,
|
| 926 |
+
"gpu_memory_gb": 79.1
|
| 927 |
+
},
|
| 928 |
+
{
|
| 929 |
+
"step": 4350,
|
| 930 |
+
"train_loss": 2.9955,
|
| 931 |
+
"lr": 0.00066,
|
| 932 |
+
"tokens_per_second": 924922,
|
| 933 |
+
"minutes": 21.35,
|
| 934 |
+
"mfu_percent": 22.3,
|
| 935 |
+
"gpu_util_percent": 100,
|
| 936 |
+
"gpu_memory_gb": 79.1
|
| 937 |
+
},
|
| 938 |
+
{
|
| 939 |
+
"step": 4400,
|
| 940 |
+
"train_loss": 2.9842,
|
| 941 |
+
"lr": 0.000635,
|
| 942 |
+
"tokens_per_second": 925657,
|
| 943 |
+
"minutes": 21.58,
|
| 944 |
+
"mfu_percent": 22.3,
|
| 945 |
+
"gpu_util_percent": 100,
|
| 946 |
+
"gpu_memory_gb": 79.1
|
| 947 |
+
},
|
| 948 |
+
{
|
| 949 |
+
"step": 4450,
|
| 950 |
+
"train_loss": 2.9217,
|
| 951 |
+
"lr": 0.000611,
|
| 952 |
+
"tokens_per_second": 926080,
|
| 953 |
+
"minutes": 21.82,
|
| 954 |
+
"mfu_percent": 22.3,
|
| 955 |
+
"gpu_util_percent": 100,
|
| 956 |
+
"gpu_memory_gb": 79.1
|
| 957 |
+
},
|
| 958 |
+
{
|
| 959 |
+
"step": 4500,
|
| 960 |
+
"train_loss": 2.9781,
|
| 961 |
+
"lr": 0.000588,
|
| 962 |
+
"tokens_per_second": 925039,
|
| 963 |
+
"minutes": 22.06,
|
| 964 |
+
"mfu_percent": 22.3,
|
| 965 |
+
"gpu_util_percent": 100,
|
| 966 |
+
"gpu_memory_gb": 79.1,
|
| 967 |
+
"val_loss": 2.9623
|
| 968 |
+
},
|
| 969 |
+
{
|
| 970 |
+
"step": 4550,
|
| 971 |
+
"train_loss": 2.9359,
|
| 972 |
+
"lr": 0.000565,
|
| 973 |
+
"tokens_per_second": 924164,
|
| 974 |
+
"minutes": 22.34,
|
| 975 |
+
"mfu_percent": 22.3,
|
| 976 |
+
"gpu_util_percent": 100,
|
| 977 |
+
"gpu_memory_gb": 79.1
|
| 978 |
+
},
|
| 979 |
+
{
|
| 980 |
+
"step": 4600,
|
| 981 |
+
"train_loss": 2.9604,
|
| 982 |
+
"lr": 0.000544,
|
| 983 |
+
"tokens_per_second": 924462,
|
| 984 |
+
"minutes": 22.58,
|
| 985 |
+
"mfu_percent": 22.3,
|
| 986 |
+
"gpu_util_percent": 100,
|
| 987 |
+
"gpu_memory_gb": 79.1
|
| 988 |
+
},
|
| 989 |
+
{
|
| 990 |
+
"step": 4650,
|
| 991 |
+
"train_loss": 2.937,
|
| 992 |
+
"lr": 0.000523,
|
| 993 |
+
"tokens_per_second": 926111,
|
| 994 |
+
"minutes": 22.81,
|
| 995 |
+
"mfu_percent": 22.3,
|
| 996 |
+
"gpu_util_percent": 100,
|
| 997 |
+
"gpu_memory_gb": 79.1
|
| 998 |
+
},
|
| 999 |
+
{
|
| 1000 |
+
"step": 4700,
|
| 1001 |
+
"train_loss": 2.9574,
|
| 1002 |
+
"lr": 0.000503,
|
| 1003 |
+
"tokens_per_second": 925254,
|
| 1004 |
+
"minutes": 23.05,
|
| 1005 |
+
"mfu_percent": 22.3,
|
| 1006 |
+
"gpu_util_percent": 100,
|
| 1007 |
+
"gpu_memory_gb": 79.1
|
| 1008 |
+
},
|
| 1009 |
+
{
|
| 1010 |
+
"step": 4750,
|
| 1011 |
+
"train_loss": 2.9611,
|
| 1012 |
+
"lr": 0.000484,
|
| 1013 |
+
"tokens_per_second": 926355,
|
| 1014 |
+
"minutes": 23.28,
|
| 1015 |
+
"mfu_percent": 22.3,
|
| 1016 |
+
"gpu_util_percent": 100,
|
| 1017 |
+
"gpu_memory_gb": 79.1
|
| 1018 |
+
},
|
| 1019 |
+
{
|
| 1020 |
+
"step": 4800,
|
| 1021 |
+
"train_loss": 2.9299,
|
| 1022 |
+
"lr": 0.000465,
|
| 1023 |
+
"tokens_per_second": 925442,
|
| 1024 |
+
"minutes": 23.52,
|
| 1025 |
+
"mfu_percent": 22.3,
|
| 1026 |
+
"gpu_util_percent": 100,
|
| 1027 |
+
"gpu_memory_gb": 79.1
|
| 1028 |
+
},
|
| 1029 |
+
{
|
| 1030 |
+
"step": 4850,
|
| 1031 |
+
"train_loss": 2.8933,
|
| 1032 |
+
"lr": 0.000448,
|
| 1033 |
+
"tokens_per_second": 924963,
|
| 1034 |
+
"minutes": 23.76,
|
| 1035 |
+
"mfu_percent": 22.3,
|
| 1036 |
+
"gpu_util_percent": 100,
|
| 1037 |
+
"gpu_memory_gb": 79.1
|
| 1038 |
+
},
|
| 1039 |
+
{
|
| 1040 |
+
"step": 4900,
|
| 1041 |
+
"train_loss": 2.9737,
|
| 1042 |
+
"lr": 0.000432,
|
| 1043 |
+
"tokens_per_second": 924506,
|
| 1044 |
+
"minutes": 23.99,
|
| 1045 |
+
"mfu_percent": 22.3,
|
| 1046 |
+
"gpu_util_percent": 100,
|
| 1047 |
+
"gpu_memory_gb": 79.1
|
| 1048 |
+
},
|
| 1049 |
+
{
|
| 1050 |
+
"step": 4950,
|
| 1051 |
+
"train_loss": 2.9918,
|
| 1052 |
+
"lr": 0.000416,
|
| 1053 |
+
"tokens_per_second": 925264,
|
| 1054 |
+
"minutes": 24.23,
|
| 1055 |
+
"mfu_percent": 22.3,
|
| 1056 |
+
"gpu_util_percent": 100,
|
| 1057 |
+
"gpu_memory_gb": 79.1
|
| 1058 |
+
},
|
| 1059 |
+
{
|
| 1060 |
+
"step": 5000,
|
| 1061 |
+
"train_loss": 2.8923,
|
| 1062 |
+
"lr": 0.000401,
|
| 1063 |
+
"tokens_per_second": 923776,
|
| 1064 |
+
"minutes": 24.47,
|
| 1065 |
+
"mfu_percent": 22.3,
|
| 1066 |
+
"gpu_util_percent": 100,
|
| 1067 |
+
"gpu_memory_gb": 79.1,
|
| 1068 |
+
"val_loss": 2.9413
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"step": 5050,
|
| 1072 |
+
"train_loss": 2.9833,
|
| 1073 |
+
"lr": 0.000388,
|
| 1074 |
+
"tokens_per_second": 924281,
|
| 1075 |
+
"minutes": 24.75,
|
| 1076 |
+
"mfu_percent": 22.3,
|
| 1077 |
+
"gpu_util_percent": 100,
|
| 1078 |
+
"gpu_memory_gb": 79.1
|
| 1079 |
+
},
|
| 1080 |
+
{
|
| 1081 |
+
"step": 5100,
|
| 1082 |
+
"train_loss": 2.916,
|
| 1083 |
+
"lr": 0.000375,
|
| 1084 |
+
"tokens_per_second": 924275,
|
| 1085 |
+
"minutes": 24.98,
|
| 1086 |
+
"mfu_percent": 22.3,
|
| 1087 |
+
"gpu_util_percent": 100,
|
| 1088 |
+
"gpu_memory_gb": 79.1
|
| 1089 |
+
},
|
| 1090 |
+
{
|
| 1091 |
+
"step": 5150,
|
| 1092 |
+
"train_loss": 2.9783,
|
| 1093 |
+
"lr": 0.000363,
|
| 1094 |
+
"tokens_per_second": 925466,
|
| 1095 |
+
"minutes": 25.22,
|
| 1096 |
+
"mfu_percent": 22.3,
|
| 1097 |
+
"gpu_util_percent": 100,
|
| 1098 |
+
"gpu_memory_gb": 79.1
|
| 1099 |
+
},
|
| 1100 |
+
{
|
| 1101 |
+
"step": 5200,
|
| 1102 |
+
"train_loss": 2.9437,
|
| 1103 |
+
"lr": 0.000353,
|
| 1104 |
+
"tokens_per_second": 924296,
|
| 1105 |
+
"minutes": 25.46,
|
| 1106 |
+
"mfu_percent": 22.3,
|
| 1107 |
+
"gpu_util_percent": 100,
|
| 1108 |
+
"gpu_memory_gb": 79.1
|
| 1109 |
+
},
|
| 1110 |
+
{
|
| 1111 |
+
"step": 5250,
|
| 1112 |
+
"train_loss": 2.8472,
|
| 1113 |
+
"lr": 0.000343,
|
| 1114 |
+
"tokens_per_second": 924268,
|
| 1115 |
+
"minutes": 25.69,
|
| 1116 |
+
"mfu_percent": 22.3,
|
| 1117 |
+
"gpu_util_percent": 100,
|
| 1118 |
+
"gpu_memory_gb": 79.1
|
| 1119 |
+
},
|
| 1120 |
+
{
|
| 1121 |
+
"step": 5300,
|
| 1122 |
+
"train_loss": 2.9167,
|
| 1123 |
+
"lr": 0.000334,
|
| 1124 |
+
"tokens_per_second": 923137,
|
| 1125 |
+
"minutes": 25.93,
|
| 1126 |
+
"mfu_percent": 22.3,
|
| 1127 |
+
"gpu_util_percent": 100,
|
| 1128 |
+
"gpu_memory_gb": 79.1
|
| 1129 |
+
},
|
| 1130 |
+
{
|
| 1131 |
+
"step": 5350,
|
| 1132 |
+
"train_loss": 2.9399,
|
| 1133 |
+
"lr": 0.000326,
|
| 1134 |
+
"tokens_per_second": 923097,
|
| 1135 |
+
"minutes": 26.17,
|
| 1136 |
+
"mfu_percent": 22.3,
|
| 1137 |
+
"gpu_util_percent": 100,
|
| 1138 |
+
"gpu_memory_gb": 79.1
|
| 1139 |
+
},
|
| 1140 |
+
{
|
| 1141 |
+
"step": 5400,
|
| 1142 |
+
"train_loss": 2.9526,
|
| 1143 |
+
"lr": 0.000319,
|
| 1144 |
+
"tokens_per_second": 925239,
|
| 1145 |
+
"minutes": 26.4,
|
| 1146 |
+
"mfu_percent": 22.3,
|
| 1147 |
+
"gpu_util_percent": 100,
|
| 1148 |
+
"gpu_memory_gb": 79.1
|
| 1149 |
+
},
|
| 1150 |
+
{
|
| 1151 |
+
"step": 5450,
|
| 1152 |
+
"train_loss": 2.9353,
|
| 1153 |
+
"lr": 0.000314,
|
| 1154 |
+
"tokens_per_second": 926014,
|
| 1155 |
+
"minutes": 26.64,
|
| 1156 |
+
"mfu_percent": 22.3,
|
| 1157 |
+
"gpu_util_percent": 100,
|
| 1158 |
+
"gpu_memory_gb": 79.1
|
| 1159 |
+
},
|
| 1160 |
+
{
|
| 1161 |
+
"step": 5500,
|
| 1162 |
+
"train_loss": 2.8749,
|
| 1163 |
+
"lr": 0.000309,
|
| 1164 |
+
"tokens_per_second": 925013,
|
| 1165 |
+
"minutes": 26.88,
|
| 1166 |
+
"mfu_percent": 22.3,
|
| 1167 |
+
"gpu_util_percent": 100,
|
| 1168 |
+
"gpu_memory_gb": 79.1,
|
| 1169 |
+
"val_loss": 2.9287
|
| 1170 |
+
},
|
| 1171 |
+
{
|
| 1172 |
+
"step": 5550,
|
| 1173 |
+
"train_loss": 2.9738,
|
| 1174 |
+
"lr": 0.000305,
|
| 1175 |
+
"tokens_per_second": 924722,
|
| 1176 |
+
"minutes": 27.16,
|
| 1177 |
+
"mfu_percent": 22.3,
|
| 1178 |
+
"gpu_util_percent": 100,
|
| 1179 |
+
"gpu_memory_gb": 79.1
|
| 1180 |
+
},
|
| 1181 |
+
{
|
| 1182 |
+
"step": 5600,
|
| 1183 |
+
"train_loss": 2.9329,
|
| 1184 |
+
"lr": 0.000302,
|
| 1185 |
+
"tokens_per_second": 924135,
|
| 1186 |
+
"minutes": 27.39,
|
| 1187 |
+
"mfu_percent": 22.3,
|
| 1188 |
+
"gpu_util_percent": 100,
|
| 1189 |
+
"gpu_memory_gb": 79.1
|
| 1190 |
+
},
|
| 1191 |
+
{
|
| 1192 |
+
"step": 5650,
|
| 1193 |
+
"train_loss": 2.9227,
|
| 1194 |
+
"lr": 0.000301,
|
| 1195 |
+
"tokens_per_second": 922406,
|
| 1196 |
+
"minutes": 27.63,
|
| 1197 |
+
"mfu_percent": 22.2,
|
| 1198 |
+
"gpu_util_percent": 100,
|
| 1199 |
+
"gpu_memory_gb": 79.1
|
| 1200 |
+
},
|
| 1201 |
+
{
|
| 1202 |
+
"step": 5700,
|
| 1203 |
+
"train_loss": 2.9227,
|
| 1204 |
+
"lr": 0.0003,
|
| 1205 |
+
"tokens_per_second": 921979,
|
| 1206 |
+
"minutes": 27.87,
|
| 1207 |
+
"mfu_percent": 22.2,
|
| 1208 |
+
"gpu_util_percent": 100,
|
| 1209 |
+
"gpu_memory_gb": 79.1
|
| 1210 |
+
},
|
| 1211 |
+
{
|
| 1212 |
+
"step": 5709,
|
| 1213 |
+
"train_loss": 2.9206,
|
| 1214 |
+
"lr": 0.0003,
|
| 1215 |
+
"tokens_per_second": 921700,
|
| 1216 |
+
"minutes": 27.91,
|
| 1217 |
+
"mfu_percent": 22.2,
|
| 1218 |
+
"gpu_util_percent": 100,
|
| 1219 |
+
"gpu_memory_gb": 79.1,
|
| 1220 |
+
"val_loss": 2.9258
|
| 1221 |
+
}
|
| 1222 |
+
],
|
| 1223 |
+
"exports": {
|
| 1224 |
+
"parity_prompts": 300,
|
| 1225 |
+
"parity_steps_per_prompt": 5,
|
| 1226 |
+
"float": {
|
| 1227 |
+
"megabytes": 60.81,
|
| 1228 |
+
"same_first_token": 1.0,
|
| 1229 |
+
"same_five_greedy_tokens": 1.0,
|
| 1230 |
+
"cached_step_ms_p50_cpu": 5.492
|
| 1231 |
+
},
|
| 1232 |
+
"int8": {
|
| 1233 |
+
"megabytes": 15.64,
|
| 1234 |
+
"same_first_token": 0.0033,
|
| 1235 |
+
"same_five_greedy_tokens": 0.0,
|
| 1236 |
+
"cached_step_ms_p50_cpu": 6.308
|
| 1237 |
+
}
|
| 1238 |
+
}
|
| 1239 |
+
}
|
v2/experiments/tinynext-v2-nofim/tokenizer.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
v2/experiments/tinynext-v2-nofim/train.py
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# "pyarrow>=15",
|
| 8 |
+
# "tokenizers>=0.20",
|
| 9 |
+
# "transformers>=4.46",
|
| 10 |
+
# "onnx>=1.17",
|
| 11 |
+
# "onnxruntime>=1.20",
|
| 12 |
+
# "safetensors>=0.4",
|
| 13 |
+
# "huggingface_hub>=0.30",
|
| 14 |
+
# "nvidia-ml-py>=12",
|
| 15 |
+
# "trackio>=0.2",
|
| 16 |
+
# ]
|
| 17 |
+
# ///
|
| 18 |
+
"""tinynext v2: a small word-piece transformer for in-browser autocomplete that can also fill in the middle.
|
| 19 |
+
|
| 20 |
+
One script does everything: it trains a tokenizer, builds a mix of general text, conversation and email,
|
| 21 |
+
trains the model, scores it with eval.py (the same harness as tinynext v1 and SmolLM2), exports ONNX with a
|
| 22 |
+
key/value cache for the browser, and uploads the lot to the model repo under v2/. Training curves, throughput
|
| 23 |
+
and GPU use go to a Trackio dashboard.
|
| 24 |
+
|
| 25 |
+
hf jobs uv run --namespace huggingface --flavor a100-large --secrets HF_TOKEN train.py
|
| 26 |
+
hf jobs uv run --namespace huggingface --flavor a10g-small --secrets HF_TOKEN train.py --smoke --no-push
|
| 27 |
+
|
| 28 |
+
The data is prepared on every CPU core before training starts, and the whole token array then sits in GPU
|
| 29 |
+
memory, so the GPU never waits on Python between steps.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
import argparse
|
| 33 |
+
import importlib.util
|
| 34 |
+
import json
|
| 35 |
+
import math
|
| 36 |
+
import os
|
| 37 |
+
import random
|
| 38 |
+
import shutil
|
| 39 |
+
import sys
|
| 40 |
+
import time
|
| 41 |
+
from pathlib import Path
|
| 42 |
+
|
| 43 |
+
import numpy as np
|
| 44 |
+
import torch
|
| 45 |
+
import torch.nn as nn
|
| 46 |
+
import torch.nn.functional as F
|
| 47 |
+
|
| 48 |
+
HERE = Path(__file__).parent
|
| 49 |
+
SPECIAL = ["<|endoftext|>", "<|pre|>", "<|suf|>", "<|mid|>"]
|
| 50 |
+
EOT, PRE, SUF, MID = range(4)
|
| 51 |
+
|
| 52 |
+
FINEWEB = "hf://datasets/HuggingFaceFW/fineweb-edu/sample/10BT/{:03d}_00000.parquet"
|
| 53 |
+
SMOLTALK = "hf://datasets/HuggingFaceTB/smoltalk/data/all/train-{:05d}-of-00009.parquet"
|
| 54 |
+
ENRON = "hf://datasets/corbt/enron-emails/data/train-{:05d}-of-00003.parquet"
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def cpus() -> int:
|
| 58 |
+
return len(os.sched_getaffinity(0)) if hasattr(os, "sched_getaffinity") else os.cpu_count() or 1
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# ---- Shared eval code ------------------------------------------------------------------------------------------
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def load_eval_module(repo: str, folder: str):
|
| 65 |
+
"""Uses eval.py and eval_set.json next to this script, or fetches them from the repo, so every model is scored
|
| 66 |
+
by one implementation on the same text. Registered as a module so worker processes can use it too."""
|
| 67 |
+
path = HERE / "eval.py"
|
| 68 |
+
if not path.exists():
|
| 69 |
+
from huggingface_hub import hf_hub_download
|
| 70 |
+
|
| 71 |
+
for name in ("eval.py", "eval_set.json"):
|
| 72 |
+
shutil.copy(hf_hub_download(repo, f"{folder}/{name}"), HERE / name)
|
| 73 |
+
spec = importlib.util.spec_from_file_location("tinynext_eval", path)
|
| 74 |
+
module = importlib.util.module_from_spec(spec)
|
| 75 |
+
sys.modules["tinynext_eval"] = module
|
| 76 |
+
spec.loader.exec_module(module)
|
| 77 |
+
return module
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
# ---- Data ------------------------------------------------------------------------------------------------------
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def to_ascii(text: str) -> str:
|
| 84 |
+
"""The browser model only sees keyboard characters, so it trains on the same."""
|
| 85 |
+
import tinynext_eval as ev
|
| 86 |
+
|
| 87 |
+
return text.translate(ev.SMART_CHARS).encode("ascii", "ignore").decode().strip()
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def smoltalk_text(batch):
|
| 91 |
+
return {"text": [to_ascii("\n\n".join(m["content"] for m in turns if m["role"] in ("user", "assistant"))) for turns in batch["messages"]]}
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def enron_text(batch):
|
| 95 |
+
"""Training senders only: the eval's held-out senders and enron-autocomplete's validation senders are skipped."""
|
| 96 |
+
import hashlib
|
| 97 |
+
|
| 98 |
+
import tinynext_eval as ev
|
| 99 |
+
|
| 100 |
+
texts = []
|
| 101 |
+
for sender, body in zip(batch["from"], batch["body"]):
|
| 102 |
+
sender = (sender or "").lower()
|
| 103 |
+
keep = "@enron.com" in sender and not ev.BULK_SENDER.search(sender)
|
| 104 |
+
keep = keep and int(hashlib.sha1(sender.encode()).hexdigest(), 16) % 100 >= 10
|
| 105 |
+
texts.append(to_ascii("\n\n".join(ev.clean_email(body or ""))) if keep else "")
|
| 106 |
+
return {"text": texts}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
# Byte-level BPE with an 8K vocabulary averages a little over 4 characters per token on English. Reading 40% more
|
| 110 |
+
# text than that covers the variance, and anything short gets repeated (and logged) in flatten().
|
| 111 |
+
CHARS_PER_TOKEN = 4.0
|
| 112 |
+
TEXT_MARGIN = 1.4
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def enough_rows(ds, budget_tokens: int, lengths: np.ndarray, seed: int):
|
| 116 |
+
"""A random subset of rows whose text adds up to roughly the token budget, so only that much gets cleaned."""
|
| 117 |
+
order = np.random.default_rng(seed).permutation(len(ds))
|
| 118 |
+
needed = np.searchsorted(np.cumsum(lengths[order]), budget_tokens * CHARS_PER_TOKEN * TEXT_MARGIN) + 1
|
| 119 |
+
return ds.select(np.sort(order[:needed]))
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
def load_sources(args, budgets: dict) -> dict:
|
| 123 |
+
"""Downloads parquet files, keeps only as many documents as each source's budget needs, and cleans them on
|
| 124 |
+
every core."""
|
| 125 |
+
import pyarrow.compute as pc
|
| 126 |
+
from datasets import load_dataset
|
| 127 |
+
|
| 128 |
+
procs = cpus()
|
| 129 |
+
fineweb = load_dataset("parquet", data_files=[FINEWEB.format(i) for i in range(args.fineweb_files)], split="train")
|
| 130 |
+
fineweb = fineweb.select_columns(["text"])
|
| 131 |
+
fineweb = enough_rows(fineweb, budgets["fineweb"], pc.utf8_length(fineweb.data.column("text")).to_numpy(), seed=0)
|
| 132 |
+
fineweb = fineweb.map(lambda b: {"text": [to_ascii(t) for t in b["text"]]}, batched=True, num_proc=procs)
|
| 133 |
+
smoltalk = load_dataset("parquet", data_files=[SMOLTALK.format(i) for i in range(args.smoltalk_files)], split="train")
|
| 134 |
+
sample = smoltalk.shuffle(seed=0).select(range(min(2000, len(smoltalk))))
|
| 135 |
+
average = np.mean([sum(len(m["content"]) for m in row["messages"]) for row in sample])
|
| 136 |
+
smoltalk = enough_rows(smoltalk, budgets["smoltalk"], np.full(len(smoltalk), average), seed=1)
|
| 137 |
+
smoltalk = smoltalk.map(smoltalk_text, batched=True, num_proc=procs, remove_columns=smoltalk.column_names)
|
| 138 |
+
enron = load_dataset("parquet", data_files=[ENRON.format(i) for i in range(3)], split="train")
|
| 139 |
+
enron = enron.map(enron_text, batched=True, num_proc=procs, remove_columns=enron.column_names)
|
| 140 |
+
sources = {"fineweb": fineweb, "smoltalk": smoltalk, "enron": enron}
|
| 141 |
+
return {name: ds.filter(lambda b: [len(t) >= 40 for t in b["text"]], batched=True, num_proc=procs) for name, ds in sources.items()}
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def train_tokenizer(sources: dict, weights: dict, vocab: int, sample_docs: int):
|
| 145 |
+
from tokenizers import Tokenizer, decoders, models, pre_tokenizers, trainers
|
| 146 |
+
|
| 147 |
+
def sample():
|
| 148 |
+
for name, weight in weights.items():
|
| 149 |
+
ds = sources[name].shuffle(seed=0)
|
| 150 |
+
for row in ds.select(range(min(len(ds), int(sample_docs * weight)))):
|
| 151 |
+
yield row["text"]
|
| 152 |
+
|
| 153 |
+
tokenizer = Tokenizer(models.BPE())
|
| 154 |
+
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)
|
| 155 |
+
tokenizer.decoder = decoders.ByteLevel()
|
| 156 |
+
trainer = trainers.BpeTrainer(vocab_size=vocab, special_tokens=SPECIAL, min_frequency=2,
|
| 157 |
+
initial_alphabet=pre_tokenizers.ByteLevel.alphabet())
|
| 158 |
+
tokenizer.train_from_iterator(sample(), trainer=trainer)
|
| 159 |
+
return tokenizer
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
def fim(ids: list[int], rng: random.Random, max_middle: int, max_suffix: int, max_prefix: int) -> list[int]:
|
| 163 |
+
"""Suffix first, then prefix, then the middle, so typing at the cursor only appends to the prompt."""
|
| 164 |
+
if len(ids) < 8:
|
| 165 |
+
return ids + [EOT]
|
| 166 |
+
start = rng.randint(1, len(ids) - 2)
|
| 167 |
+
end = min(len(ids), start + rng.randint(1, max_middle))
|
| 168 |
+
prefix, middle, suffix = ids[max(0, start - max_prefix):start], ids[start:end], ids[end:end + max_suffix]
|
| 169 |
+
if rng.random() < 0.25:
|
| 170 |
+
suffix = [] # also learn the plain "nothing after the cursor" case in this format
|
| 171 |
+
return [SUF, *suffix, PRE, *prefix, MID, *middle, EOT]
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def make_encoder(tokenizer_json: str, seq: int, fim_rate: float):
|
| 175 |
+
"""Tokenizes a batch and turns each document into training pieces: plain chunks, or fill-in-the-middle examples."""
|
| 176 |
+
|
| 177 |
+
def encode(batch, indices):
|
| 178 |
+
from tokenizers import Tokenizer
|
| 179 |
+
|
| 180 |
+
tokenizer = Tokenizer.from_str(tokenizer_json)
|
| 181 |
+
rng = random.Random(indices[0])
|
| 182 |
+
out = []
|
| 183 |
+
for encoding in tokenizer.encode_batch(batch["text"]):
|
| 184 |
+
ids, pieces = encoding.ids, []
|
| 185 |
+
for at in range(0, len(ids), seq - 8):
|
| 186 |
+
chunk = ids[at: at + seq - 8]
|
| 187 |
+
pieces += fim(chunk, rng, 24, 64, seq - 100) if rng.random() < fim_rate else chunk + [EOT]
|
| 188 |
+
out.append(pieces)
|
| 189 |
+
return {"tokens": out}
|
| 190 |
+
|
| 191 |
+
return encode
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def flatten(ds, budget: int) -> np.ndarray:
|
| 195 |
+
"""All of a source's tokens as one array, cut to its share of the budget (repeated if the source is small)."""
|
| 196 |
+
import pyarrow.compute as pc
|
| 197 |
+
|
| 198 |
+
column = ds.data.column("tokens")
|
| 199 |
+
tokens = pc.list_flatten(column).to_numpy().astype(np.uint16)
|
| 200 |
+
if len(tokens) < budget:
|
| 201 |
+
print(f" only {len(tokens) / 1e6:.0f}M tokens, repeating to reach {budget / 1e6:.0f}M", flush=True)
|
| 202 |
+
tokens = np.tile(tokens, math.ceil(budget / len(tokens)))
|
| 203 |
+
return tokens[:budget]
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def build_rows(sources: dict, tokenizer, weights: dict, args) -> tuple[np.ndarray, np.ndarray, dict]:
|
| 207 |
+
encode = make_encoder(tokenizer.to_str(), args.seq, args.fim_rate)
|
| 208 |
+
train_parts, val_parts, counts = [], [], {}
|
| 209 |
+
for name, weight in weights.items():
|
| 210 |
+
started = time.time()
|
| 211 |
+
split = sources[name].train_test_split(test_size=0.002, seed=0)
|
| 212 |
+
encoded = {part: split[part].map(encode, batched=True, batch_size=512, with_indices=True, num_proc=cpus(),
|
| 213 |
+
remove_columns=["text"]) for part in ("train", "test")}
|
| 214 |
+
budget = int(args.tokens * weight)
|
| 215 |
+
train_parts.append(flatten(encoded["train"], budget))
|
| 216 |
+
val_parts.append(flatten(encoded["test"], int(args.val_tokens * weight)))
|
| 217 |
+
counts[name] = {"docs": len(split["train"]), "train_tokens": int(len(train_parts[-1]))}
|
| 218 |
+
print(f" {name}: {len(split['train']):,} docs → {len(train_parts[-1]) / 1e6:.0f}M tokens in {time.time() - started:.0f}s", flush=True)
|
| 219 |
+
|
| 220 |
+
def rows(parts):
|
| 221 |
+
tokens = np.concatenate(parts)
|
| 222 |
+
count = len(tokens) // (args.seq + 1)
|
| 223 |
+
return tokens[: count * (args.seq + 1)].reshape(count, args.seq + 1)
|
| 224 |
+
|
| 225 |
+
return rows(train_parts), rows(val_parts), counts
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
# ---- Model -----------------------------------------------------------------------------------------------------
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
class RMSNorm(nn.Module):
|
| 232 |
+
def __init__(self, dim: int):
|
| 233 |
+
super().__init__()
|
| 234 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 235 |
+
|
| 236 |
+
def forward(self, x):
|
| 237 |
+
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + 1e-6) * self.weight
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
def rotate(x, cos, sin):
|
| 241 |
+
half = x.shape[-1] // 2
|
| 242 |
+
x1, x2 = x[..., :half], x[..., half:]
|
| 243 |
+
return torch.cat([x1 * cos - x2 * sin, x2 * cos + x1 * sin], dim=-1)
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
class Block(nn.Module):
|
| 247 |
+
def __init__(self, dim: int, heads: int, ffn: int):
|
| 248 |
+
super().__init__()
|
| 249 |
+
self.heads, self.head_dim = heads, dim // heads
|
| 250 |
+
self.norm1, self.norm2 = RMSNorm(dim), RMSNorm(dim)
|
| 251 |
+
self.qkv = nn.Linear(dim, 3 * dim, bias=False)
|
| 252 |
+
self.out = nn.Linear(dim, dim, bias=False)
|
| 253 |
+
self.gate_up = nn.Linear(dim, 2 * ffn, bias=False)
|
| 254 |
+
self.down = nn.Linear(ffn, dim, bias=False)
|
| 255 |
+
|
| 256 |
+
def forward(self, x, cos, sin, past_k, past_v, mask):
|
| 257 |
+
batch, length, _ = x.shape
|
| 258 |
+
q, k, v = self.qkv(self.norm1(x)).view(batch, length, 3, self.heads, self.head_dim).unbind(2)
|
| 259 |
+
q, k, v = rotate(q.transpose(1, 2), cos, sin), rotate(k.transpose(1, 2), cos, sin), v.transpose(1, 2)
|
| 260 |
+
if past_k is not None:
|
| 261 |
+
k, v = torch.cat([past_k, k], dim=2), torch.cat([past_v, v], dim=2)
|
| 262 |
+
if mask is None:
|
| 263 |
+
attended = F.scaled_dot_product_attention(q, k, v, is_causal=True)
|
| 264 |
+
else:
|
| 265 |
+
attended = F.scaled_dot_product_attention(q, k, v, attn_mask=mask)
|
| 266 |
+
x = x + self.out(attended.transpose(1, 2).reshape(batch, length, -1))
|
| 267 |
+
gate, up = self.gate_up(self.norm2(x)).chunk(2, dim=-1)
|
| 268 |
+
return x + self.down(F.silu(gate) * up), k, v
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
class TinyNext(nn.Module):
|
| 272 |
+
def __init__(self, vocab: int, dim: int, layers: int, heads: int, ffn: int):
|
| 273 |
+
super().__init__()
|
| 274 |
+
self.config = {"vocab": vocab, "dim": dim, "layers": layers, "heads": heads, "ffn": ffn}
|
| 275 |
+
self.embed = nn.Embedding(vocab, dim)
|
| 276 |
+
self.blocks = nn.ModuleList(Block(dim, heads, ffn) for _ in range(layers))
|
| 277 |
+
self.norm = RMSNorm(dim)
|
| 278 |
+
self.head = None # set only for export: an untied copy of the output weights, so int8 quantization covers it
|
| 279 |
+
self.head_dim = dim // heads
|
| 280 |
+
inverse = 1.0 / (10000 ** (torch.arange(0, self.head_dim, 2).float() / self.head_dim))
|
| 281 |
+
self.register_buffer("inverse_frequency", inverse, persistent=False)
|
| 282 |
+
nn.init.normal_(self.embed.weight, std=0.02)
|
| 283 |
+
|
| 284 |
+
def forward(self, ids, past_k=None, past_v=None):
|
| 285 |
+
"""ids: [batch, length]. past_k/past_v: [layers, batch, heads, past, head_dim] or None.
|
| 286 |
+
Returns logits for every position and the updated cache."""
|
| 287 |
+
past = 0 if past_k is None else past_k.shape[3]
|
| 288 |
+
length = ids.shape[1]
|
| 289 |
+
positions = torch.arange(length, device=ids.device) + past
|
| 290 |
+
angles = positions[:, None].float() * self.inverse_frequency[None, :]
|
| 291 |
+
cos, sin = angles.cos()[None, None], angles.sin()[None, None]
|
| 292 |
+
mask = None
|
| 293 |
+
if past_k is not None:
|
| 294 |
+
keys = torch.arange(past + length, device=ids.device)
|
| 295 |
+
mask = keys[None, :] <= positions[:, None]
|
| 296 |
+
x = self.embed(ids)
|
| 297 |
+
new_k, new_v = [], []
|
| 298 |
+
for index, block in enumerate(self.blocks):
|
| 299 |
+
x, k, v = block(x, cos, sin, None if past_k is None else past_k[index], None if past_v is None else past_v[index], mask)
|
| 300 |
+
new_k.append(k)
|
| 301 |
+
new_v.append(v)
|
| 302 |
+
logits = self.norm(x) @ (self.embed.weight.T if self.head is None else self.head)
|
| 303 |
+
return logits, torch.stack(new_k), torch.stack(new_v)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
class BrowserStep(nn.Module):
|
| 307 |
+
"""The ONNX graph: always takes a cache (possibly empty) and returns only the last position's logits."""
|
| 308 |
+
|
| 309 |
+
def __init__(self, model: TinyNext):
|
| 310 |
+
super().__init__()
|
| 311 |
+
self.model = model
|
| 312 |
+
|
| 313 |
+
def forward(self, ids, past_k, past_v):
|
| 314 |
+
logits, k, v = self.model(ids, past_k, past_v)
|
| 315 |
+
return logits[:, -1], k, v
|
| 316 |
+
|
| 317 |
+
|
| 318 |
+
# ---- Training --------------------------------------------------------------------------------------------------
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
class GpuMonitor:
|
| 322 |
+
"""Reads GPU utilization and memory through NVML, so the logs show whether the GPU is actually busy."""
|
| 323 |
+
|
| 324 |
+
def __init__(self):
|
| 325 |
+
try:
|
| 326 |
+
import pynvml
|
| 327 |
+
|
| 328 |
+
pynvml.nvmlInit()
|
| 329 |
+
self.nvml, self.handle = pynvml, pynvml.nvmlDeviceGetHandleByIndex(0)
|
| 330 |
+
except Exception as error: # no NVIDIA GPU (a laptop smoke run): report nothing rather than fail
|
| 331 |
+
print(f"GPU monitoring off: {error}", flush=True)
|
| 332 |
+
self.nvml = None
|
| 333 |
+
|
| 334 |
+
def read(self) -> dict:
|
| 335 |
+
if not self.nvml:
|
| 336 |
+
return {}
|
| 337 |
+
rates = self.nvml.nvmlDeviceGetUtilizationRates(self.handle)
|
| 338 |
+
memory = self.nvml.nvmlDeviceGetMemoryInfo(self.handle)
|
| 339 |
+
return {"gpu_util_percent": rates.gpu, "gpu_memory_gb": round(memory.used / 1e9, 1)}
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
def evaluate_loss(model, rows: torch.Tensor, device, batch: int) -> float:
|
| 343 |
+
model.eval()
|
| 344 |
+
losses = []
|
| 345 |
+
with torch.no_grad(), torch.autocast(device.type, dtype=torch.bfloat16, enabled=device.type == "cuda"):
|
| 346 |
+
for at in range(0, len(rows), batch):
|
| 347 |
+
chunk = rows[at: at + batch].long()
|
| 348 |
+
logits, _, _ = model(chunk[:, :-1])
|
| 349 |
+
losses.append(F.cross_entropy(logits.float().flatten(0, 1), chunk[:, 1:].flatten()).item())
|
| 350 |
+
model.train()
|
| 351 |
+
return float(np.mean(losses))
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def train(model, rows: torch.Tensor, val_rows: torch.Tensor, args, device, tracker) -> list[dict]:
|
| 355 |
+
steps = int(args.epochs * len(rows) // args.batch)
|
| 356 |
+
decay = [p for p in model.parameters() if p.dim() >= 2]
|
| 357 |
+
no_decay = [p for p in model.parameters() if p.dim() < 2]
|
| 358 |
+
optimizer = torch.optim.AdamW([{"params": decay, "weight_decay": 0.1}, {"params": no_decay, "weight_decay": 0.0}],
|
| 359 |
+
lr=args.lr, betas=(0.9, 0.95), fused=device.type == "cuda")
|
| 360 |
+
warmup = max(1, steps // 50)
|
| 361 |
+
schedule = lambda step: min(1, step / warmup) * (0.1 + 0.9 * 0.5 * (1 + math.cos(math.pi * min(1, step / steps))))
|
| 362 |
+
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, schedule)
|
| 363 |
+
compiled = torch.compile(model) if device.type == "cuda" else model
|
| 364 |
+
parameters = sum(p.numel() for p in model.parameters())
|
| 365 |
+
gpu, history = GpuMonitor(), []
|
| 366 |
+
generator = torch.Generator(device=device).manual_seed(0)
|
| 367 |
+
window_started, window_tokens, started = time.time(), 0, time.time()
|
| 368 |
+
print(f"training {steps:,} steps of {args.batch * args.seq:,} tokens", flush=True)
|
| 369 |
+
for step in range(steps):
|
| 370 |
+
index = torch.randint(0, len(rows), (args.batch,), device=device, generator=generator)
|
| 371 |
+
chunk = rows[index].long()
|
| 372 |
+
with torch.autocast(device.type, dtype=torch.bfloat16, enabled=device.type == "cuda"):
|
| 373 |
+
logits, _, _ = compiled(chunk[:, :-1])
|
| 374 |
+
loss = F.cross_entropy(logits.float().flatten(0, 1), chunk[:, 1:].flatten())
|
| 375 |
+
optimizer.zero_grad(set_to_none=True)
|
| 376 |
+
loss.backward()
|
| 377 |
+
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
|
| 378 |
+
optimizer.step()
|
| 379 |
+
scheduler.step()
|
| 380 |
+
window_tokens += args.batch * args.seq
|
| 381 |
+
if step % args.log_every == 0 or step == steps - 1:
|
| 382 |
+
loss_value = loss.item() # syncs the GPU, so throughput below is real
|
| 383 |
+
seconds = time.time() - window_started
|
| 384 |
+
tokens_per_second = window_tokens / max(seconds, 1e-9)
|
| 385 |
+
entry = {
|
| 386 |
+
"step": step, "train_loss": round(loss_value, 4), "lr": round(scheduler.get_last_lr()[0], 6),
|
| 387 |
+
"tokens_per_second": round(tokens_per_second), "minutes": round((time.time() - started) / 60, 2),
|
| 388 |
+
# Training compute is about 6 FLOPs per parameter per token; an A100 does 312 TFLOP/s in bf16.
|
| 389 |
+
"mfu_percent": round(100 * 6 * parameters * tokens_per_second / 312e12, 1), **gpu.read(),
|
| 390 |
+
}
|
| 391 |
+
if step % (args.log_every * 10) == 0 or step == steps - 1:
|
| 392 |
+
entry["val_loss"] = round(evaluate_loss(model, val_rows, device, args.batch), 4)
|
| 393 |
+
history.append(entry)
|
| 394 |
+
tracker.log(entry, step=step)
|
| 395 |
+
print(json.dumps(entry), flush=True)
|
| 396 |
+
window_started, window_tokens = time.time(), 0
|
| 397 |
+
return history
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
# ---- Eval, export --------------------------------------------------------------------------------------------
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
def as_token_lm(ev, name: str, model: TinyNext, tokenizer, device, fim: bool = True):
|
| 404 |
+
texts = [tokenizer.decode([i], skip_special_tokens=False) if i >= len(SPECIAL) else "" for i in range(tokenizer.get_vocab_size())]
|
| 405 |
+
|
| 406 |
+
@torch.no_grad()
|
| 407 |
+
def next_logits(ids, cache):
|
| 408 |
+
past_k, past_v = cache if cache else (None, None)
|
| 409 |
+
logits, k, v = model(torch.tensor([ids], device=device), past_k, past_v)
|
| 410 |
+
return logits[0, -1].float().cpu().numpy(), (k, v)
|
| 411 |
+
|
| 412 |
+
encode = lambda text: tokenizer.encode(text).ids or [EOT]
|
| 413 |
+
# A model trained without fill-in-the-middle never saw the special tokens, so it only gets the text before.
|
| 414 |
+
prompt = (lambda prefix, suffix: prefix if not suffix else [SUF, *suffix, PRE, *prefix, MID]) if fim else None
|
| 415 |
+
return ev.TokenLM(name, next_logits, encode, texts, set(range(len(SPECIAL))), prompt=prompt)
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
def parity_prompts(ev, tokenizer, count: int = 300) -> list[list[int]]:
|
| 419 |
+
"""Real text from the eval set, cut at random points, as token prompts."""
|
| 420 |
+
rng = random.Random(0)
|
| 421 |
+
texts = [p for domain in ev.load_eval_set().values() for doc in domain for p in doc]
|
| 422 |
+
prompts = []
|
| 423 |
+
for text in rng.sample(texts, min(count, len(texts))):
|
| 424 |
+
ids = tokenizer.encode(text[: rng.randint(40, len(text))]).ids[-300:]
|
| 425 |
+
if len(ids) >= 4:
|
| 426 |
+
prompts.append(ids)
|
| 427 |
+
return prompts
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
def greedy_tokens(step, ids: list[int], empty, steps: int) -> list[int]:
|
| 431 |
+
"""Prompt, then `steps` cached greedy steps; returns the top token at each point."""
|
| 432 |
+
logits, k, v = step(np.array([ids]), empty, empty)
|
| 433 |
+
tops = [int(logits.argmax())]
|
| 434 |
+
for _ in range(steps):
|
| 435 |
+
logits, k, v = step(np.array([[tops[-1]]]), k, v)
|
| 436 |
+
tops.append(int(logits.argmax()))
|
| 437 |
+
return tops
|
| 438 |
+
|
| 439 |
+
|
| 440 |
+
def export(model: TinyNext, output: Path, device, prompts: list[list[int]]) -> dict:
|
| 441 |
+
"""Float and int8 ONNX for the browser, checked against PyTorch on real prompts over several cached steps."""
|
| 442 |
+
import onnxruntime as ort
|
| 443 |
+
from onnxruntime.quantization import QuantType, quantize_dynamic
|
| 444 |
+
|
| 445 |
+
model = model.float().eval().to("cpu")
|
| 446 |
+
model.head = nn.Parameter(model.embed.weight.detach().T.contiguous().clone())
|
| 447 |
+
cfg = model.config
|
| 448 |
+
head_dim = cfg["dim"] // cfg["heads"]
|
| 449 |
+
empty = np.zeros((cfg["layers"], 1, cfg["heads"], 0, head_dim), np.float32)
|
| 450 |
+
# Trace with a non-empty cache so no shape gets fixed at zero; the checks below start from an empty one.
|
| 451 |
+
with torch.no_grad():
|
| 452 |
+
_, trace_k, trace_v = model(torch.tensor([[1, 2]]))
|
| 453 |
+
float_path, int8_path = output / "model.onnx", output / "model_int8.onnx"
|
| 454 |
+
torch.onnx.export(
|
| 455 |
+
BrowserStep(model), (torch.tensor([[5, 6, 7]]), trace_k, trace_v), float_path, opset_version=17,
|
| 456 |
+
input_names=["input_ids", "past_k", "past_v"], output_names=["logits", "present_k", "present_v"],
|
| 457 |
+
dynamic_axes={"input_ids": {1: "length"}, "past_k": {3: "past"}, "past_v": {3: "past"},
|
| 458 |
+
"present_k": {3: "total"}, "present_v": {3: "total"}},
|
| 459 |
+
dynamo=False,
|
| 460 |
+
)
|
| 461 |
+
quantize_dynamic(float_path, int8_path, weight_type=QuantType.QInt8, op_types_to_quantize=["MatMul", "Gather"], per_channel=True)
|
| 462 |
+
|
| 463 |
+
@torch.no_grad()
|
| 464 |
+
def torch_step(ids, k, v):
|
| 465 |
+
past = None if k.shape[3] == 0 else (torch.from_numpy(k), torch.from_numpy(v))
|
| 466 |
+
logits, nk, nv = model(torch.from_numpy(ids), *(past or (None, None)))
|
| 467 |
+
return logits[0, -1].numpy(), nk.numpy(), nv.numpy()
|
| 468 |
+
|
| 469 |
+
expected = [greedy_tokens(torch_step, ids, empty, 4) for ids in prompts]
|
| 470 |
+
report = {"parity_prompts": len(prompts), "parity_steps_per_prompt": 5}
|
| 471 |
+
for name, path in (("float", float_path), ("int8", int8_path)):
|
| 472 |
+
session = ort.InferenceSession(str(path), providers=["CPUExecutionProvider"])
|
| 473 |
+
onnx_step = lambda ids, k, v: (lambda out: (out[0][0], out[1], out[2]))(
|
| 474 |
+
session.run(None, {"input_ids": ids.astype(np.int64), "past_k": k, "past_v": v}))
|
| 475 |
+
got = [greedy_tokens(onnx_step, ids, empty, 4) for ids in prompts]
|
| 476 |
+
first = np.mean([g[0] == e[0] for g, e in zip(got, expected)])
|
| 477 |
+
all_steps = np.mean([g == e for g, e in zip(got, expected)])
|
| 478 |
+
_, pk, pv = onnx_step(np.array([prompts[0]]), empty, empty)
|
| 479 |
+
timings = []
|
| 480 |
+
for _ in range(200):
|
| 481 |
+
began = time.perf_counter()
|
| 482 |
+
onnx_step(np.array([[8]]), pk, pv)
|
| 483 |
+
timings.append((time.perf_counter() - began) * 1000)
|
| 484 |
+
report[name] = {
|
| 485 |
+
"megabytes": round(path.stat().st_size / 1e6, 2),
|
| 486 |
+
"same_first_token": round(float(first), 4),
|
| 487 |
+
"same_five_greedy_tokens": round(float(all_steps), 4),
|
| 488 |
+
"cached_step_ms_p50_cpu": round(float(np.median(timings)), 3),
|
| 489 |
+
}
|
| 490 |
+
model.head = None
|
| 491 |
+
model.to(device)
|
| 492 |
+
return report
|
| 493 |
+
|
| 494 |
+
|
| 495 |
+
def headline(scored: dict) -> dict:
|
| 496 |
+
"""The few eval numbers worth a chart: typing saved and 2+ word suggestions at the app's cutoff."""
|
| 497 |
+
table = scored["cutoffs"]["0.5"]
|
| 498 |
+
out = {}
|
| 499 |
+
for key, m in table.items():
|
| 500 |
+
slug = key.replace("/", "_")
|
| 501 |
+
out[f"eval/{slug}/saved_with_tab"] = m["saved_with_tab"]
|
| 502 |
+
out[f"eval/{slug}/right"] = m["right"]
|
| 503 |
+
out[f"eval/{slug}/multiword_shown"] = m["multiword_shown"]
|
| 504 |
+
return out
|
| 505 |
+
|
| 506 |
+
|
| 507 |
+
# ---- Prepared data ---------------------------------------------------------------------------------------------
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
def data_key(args) -> str:
|
| 511 |
+
"""Prepared data depends only on these settings, so a training run can find the matching files."""
|
| 512 |
+
return f"{args.name}-v{args.vocab}-s{args.seq}-t{int(args.tokens / 1e6)}M-fim{args.fim_rate}-{args.mix}".replace(",", "_").replace("=", "")
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
def prepare(args, weights: dict, output: Path):
|
| 516 |
+
budgets = {name: int((args.tokens + args.val_tokens) * weight) for name, weight in weights.items()}
|
| 517 |
+
started = time.time()
|
| 518 |
+
sources = load_sources(args, budgets)
|
| 519 |
+
print(f"sources ready in {time.time() - started:.0f}s: " + ", ".join(f"{n} {len(d):,} docs" for n, d in sources.items()), flush=True)
|
| 520 |
+
tokenizer = train_tokenizer(sources, weights, args.vocab, args.tokenizer_docs)
|
| 521 |
+
tokenizer.save(str(output / "tokenizer.json"))
|
| 522 |
+
rows, val_rows, counts = build_rows(sources, tokenizer, weights, args)
|
| 523 |
+
return tokenizer, rows, val_rows, counts
|
| 524 |
+
|
| 525 |
+
|
| 526 |
+
def upload_prepared(args, output: Path, rows: np.ndarray, val_rows: np.ndarray, counts: dict, minutes: float):
|
| 527 |
+
from huggingface_hub import HfApi
|
| 528 |
+
|
| 529 |
+
folder = output / "data"
|
| 530 |
+
folder.mkdir(exist_ok=True)
|
| 531 |
+
rows.astype(np.uint16).tofile(folder / "train.bin")
|
| 532 |
+
val_rows.astype(np.uint16).tofile(folder / "val.bin")
|
| 533 |
+
shutil.copy(output / "tokenizer.json", folder / "tokenizer.json")
|
| 534 |
+
meta = {"seq": args.seq, "train_rows": len(rows), "val_rows": len(val_rows), "counts": counts, "minutes": round(minutes, 1), "args": vars(args)}
|
| 535 |
+
(folder / "meta.json").write_text(json.dumps(meta, indent=1))
|
| 536 |
+
api = HfApi(token=os.environ.get("HF_TOKEN"))
|
| 537 |
+
api.create_repo(args.data_repo, repo_type="dataset", private=True, exist_ok=True)
|
| 538 |
+
api.upload_folder(folder_path=str(folder), repo_id=args.data_repo, repo_type="dataset", path_in_repo=data_key(args),
|
| 539 |
+
commit_message=f"prepared data: {data_key(args)}")
|
| 540 |
+
print(f"Prepared data at https://huggingface.co/datasets/{args.data_repo}/tree/main/{data_key(args)}", flush=True)
|
| 541 |
+
|
| 542 |
+
|
| 543 |
+
def download_prepared(args, output: Path):
|
| 544 |
+
from huggingface_hub import snapshot_download
|
| 545 |
+
from tokenizers import Tokenizer
|
| 546 |
+
|
| 547 |
+
local = Path(snapshot_download(args.data_repo, repo_type="dataset", allow_patterns=[f"{data_key(args)}/*"], max_workers=16))
|
| 548 |
+
folder = local / data_key(args)
|
| 549 |
+
meta = json.loads((folder / "meta.json").read_text())
|
| 550 |
+
shutil.copy(folder / "tokenizer.json", output / "tokenizer.json")
|
| 551 |
+
rows = np.fromfile(folder / "train.bin", dtype=np.uint16).reshape(meta["train_rows"], meta["seq"] + 1)
|
| 552 |
+
val_rows = np.fromfile(folder / "val.bin", dtype=np.uint16).reshape(meta["val_rows"], meta["seq"] + 1)
|
| 553 |
+
return Tokenizer.from_file(str(output / "tokenizer.json")), rows, val_rows, meta["counts"]
|
| 554 |
+
|
| 555 |
+
|
| 556 |
+
# ---- Main ------------------------------------------------------------------------------------------------------
|
| 557 |
+
|
| 558 |
+
|
| 559 |
+
def parse_args():
|
| 560 |
+
parser = argparse.ArgumentParser()
|
| 561 |
+
parser.add_argument("--vocab", type=int, default=8192)
|
| 562 |
+
parser.add_argument("--dim", type=int, default=320)
|
| 563 |
+
parser.add_argument("--layers", type=int, default=8)
|
| 564 |
+
parser.add_argument("--heads", type=int, default=5)
|
| 565 |
+
parser.add_argument("--ffn", type=int, default=864)
|
| 566 |
+
parser.add_argument("--seq", type=int, default=512)
|
| 567 |
+
parser.add_argument("--tokens", type=float, default=1.5e9, help="Training tokens")
|
| 568 |
+
parser.add_argument("--val-tokens", type=float, default=4e6)
|
| 569 |
+
parser.add_argument("--epochs", type=float, default=1.0)
|
| 570 |
+
parser.add_argument("--batch", type=int, default=512)
|
| 571 |
+
parser.add_argument("--lr", type=float, default=3e-3)
|
| 572 |
+
parser.add_argument("--fim-rate", type=float, default=0.5)
|
| 573 |
+
parser.add_argument("--mix", default="fineweb=0.6,smoltalk=0.3,enron=0.1")
|
| 574 |
+
parser.add_argument("--fineweb-files", type=int, default=2, help="Each is about 2 GB of text, roughly 0.9B tokens")
|
| 575 |
+
parser.add_argument("--smoltalk-files", type=int, default=9)
|
| 576 |
+
parser.add_argument("--tokenizer-docs", type=int, default=200_000)
|
| 577 |
+
parser.add_argument("--eval-pauses", type=int, default=1000)
|
| 578 |
+
parser.add_argument("--log-every", type=int, default=50)
|
| 579 |
+
parser.add_argument("--repo", default="cfahlgren1/tinynext")
|
| 580 |
+
parser.add_argument("--folder", default="v2", help="Where this run's outputs are uploaded")
|
| 581 |
+
parser.add_argument("--eval-folder", default="v2", help="Where the shared eval.py and eval_set.json live")
|
| 582 |
+
parser.add_argument("--name", default="tinynext-v2")
|
| 583 |
+
parser.add_argument("--trackio-space", default="cfahlgren1/tinynext-trackio")
|
| 584 |
+
parser.add_argument("--stage", choices=("all", "prepare", "train"), default="all",
|
| 585 |
+
help="prepare: build the tokenizer and token arrays on a CPU job and save them to --data-repo. "
|
| 586 |
+
"train: download them and train on the GPU. all: both in one job.")
|
| 587 |
+
parser.add_argument("--data-repo", default="cfahlgren1/tinynext-data")
|
| 588 |
+
parser.add_argument("--smoke", action="store_true", help="Tiny settings to check the pipeline end to end")
|
| 589 |
+
parser.add_argument("--no-push", action="store_true")
|
| 590 |
+
args = parser.parse_args()
|
| 591 |
+
if args.smoke:
|
| 592 |
+
args.vocab, args.dim, args.layers, args.heads, args.ffn, args.seq = 2048, 64, 2, 2, 128, 256
|
| 593 |
+
args.tokens, args.val_tokens, args.batch, args.tokenizer_docs = 5e6, 2e5, 64, 5000
|
| 594 |
+
args.fineweb_files, args.smoltalk_files, args.eval_pauses, args.log_every = 1, 1, 20, 10
|
| 595 |
+
args.name = "tinynext-v2-smoke"
|
| 596 |
+
return args
|
| 597 |
+
|
| 598 |
+
|
| 599 |
+
class NoTracker:
|
| 600 |
+
def log(self, *_, **__):
|
| 601 |
+
pass
|
| 602 |
+
|
| 603 |
+
def finish(self):
|
| 604 |
+
pass
|
| 605 |
+
|
| 606 |
+
|
| 607 |
+
def start_tracker(args):
|
| 608 |
+
if args.no_push and not os.environ.get("HF_TOKEN"):
|
| 609 |
+
return NoTracker()
|
| 610 |
+
import trackio
|
| 611 |
+
|
| 612 |
+
trackio.init(project="tinynext", name=args.name, space_id=args.trackio_space, config=vars(args))
|
| 613 |
+
return trackio
|
| 614 |
+
|
| 615 |
+
|
| 616 |
+
def main():
|
| 617 |
+
args = parse_args()
|
| 618 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu")
|
| 619 |
+
torch.manual_seed(0)
|
| 620 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
| 621 |
+
torch.backends.cudnn.allow_tf32 = True
|
| 622 |
+
output = HERE / "output"
|
| 623 |
+
output.mkdir(exist_ok=True)
|
| 624 |
+
ev = load_eval_module(args.repo, args.eval_folder)
|
| 625 |
+
weights = {k: float(v) for k, v in (part.split("=") for part in args.mix.split(","))}
|
| 626 |
+
print(f"device {device}, {cpus()} CPUs, mix {weights}", flush=True)
|
| 627 |
+
tracker = start_tracker(args)
|
| 628 |
+
|
| 629 |
+
started = time.time()
|
| 630 |
+
if args.stage == "train":
|
| 631 |
+
tokenizer, rows, val_rows, counts = download_prepared(args, output)
|
| 632 |
+
else:
|
| 633 |
+
tokenizer, rows, val_rows, counts = prepare(args, weights, output)
|
| 634 |
+
data_minutes = (time.time() - started) / 60
|
| 635 |
+
print(f"data ready in {data_minutes:.1f} min: {rows.size / 1e6:.0f}M train tokens, {val_rows.size / 1e6:.1f}M val", flush=True)
|
| 636 |
+
if args.stage == "prepare":
|
| 637 |
+
upload_prepared(args, output, rows, val_rows, counts, data_minutes)
|
| 638 |
+
return
|
| 639 |
+
|
| 640 |
+
# The whole token array lives on the GPU; each step just indexes into it.
|
| 641 |
+
rows_gpu = torch.from_numpy(rows.astype(np.int32)).to(device)
|
| 642 |
+
val_gpu = torch.from_numpy(val_rows.astype(np.int32)).to(device)
|
| 643 |
+
model = TinyNext(tokenizer.get_vocab_size(), args.dim, args.layers, args.heads, args.ffn).to(device)
|
| 644 |
+
parameters = sum(p.numel() for p in model.parameters())
|
| 645 |
+
print(f"{parameters / 1e6:.2f}M parameters", flush=True)
|
| 646 |
+
started = time.time()
|
| 647 |
+
history = train(model, rows_gpu, val_gpu, args, device, tracker)
|
| 648 |
+
train_minutes = (time.time() - started) / 60
|
| 649 |
+
|
| 650 |
+
model.eval()
|
| 651 |
+
from safetensors.torch import save_file
|
| 652 |
+
|
| 653 |
+
save_file({k: v.contiguous() for k, v in model.state_dict().items()}, output / "model.safetensors")
|
| 654 |
+
scored = ev.score(as_token_lm(ev, args.name, model, tokenizer, device, fim=args.fim_rate > 0), ev.pauses(ev.load_eval_set(), args.eval_pauses))
|
| 655 |
+
(output / "metrics").mkdir(exist_ok=True)
|
| 656 |
+
(output / "metrics" / f"{args.name}.json").write_text(json.dumps(scored, indent=1))
|
| 657 |
+
tracker.log(headline(scored))
|
| 658 |
+
exported = export(model, output, device, parity_prompts(ev, tokenizer))
|
| 659 |
+
|
| 660 |
+
config = {
|
| 661 |
+
**model.config, "parameters": parameters, "seq": args.seq, "special_tokens": dict(zip(SPECIAL, range(len(SPECIAL)))),
|
| 662 |
+
"prompt": "No text after the cursor: the text before it. Otherwise: <|suf|> after <|pre|> before <|mid|>.",
|
| 663 |
+
}
|
| 664 |
+
(output / "config.json").write_text(json.dumps(config, indent=1))
|
| 665 |
+
report = {"args": vars(args), "parameters": parameters, "data": counts, "data_minutes": round(data_minutes, 1),
|
| 666 |
+
"train_minutes": round(train_minutes, 1), "history": history, "exports": exported}
|
| 667 |
+
(output / "report.json").write_text(json.dumps(report, indent=1))
|
| 668 |
+
print(json.dumps(exported, indent=1))
|
| 669 |
+
print(ev.table([output / "metrics" / f"{args.name}.json"]))
|
| 670 |
+
tracker.finish()
|
| 671 |
+
|
| 672 |
+
for name in ("train.py", "eval.py", "eval_set.json"):
|
| 673 |
+
shutil.copy(HERE / name, output / name)
|
| 674 |
+
if (HERE / "metrics").exists():
|
| 675 |
+
for path in (HERE / "metrics").glob("*.json"):
|
| 676 |
+
if not (output / "metrics" / path.name).exists():
|
| 677 |
+
shutil.copy(path, output / "metrics" / path.name)
|
| 678 |
+
if args.no_push:
|
| 679 |
+
print(f"Skipping upload; everything is in {output}")
|
| 680 |
+
return
|
| 681 |
+
from huggingface_hub import HfApi
|
| 682 |
+
|
| 683 |
+
HfApi(token=os.environ.get("HF_TOKEN")).upload_folder(
|
| 684 |
+
folder_path=str(output), repo_id=args.repo, path_in_repo=args.folder, repo_type="model",
|
| 685 |
+
commit_message=f"{args.name}: {parameters / 1e6:.1f}M params, {train_minutes:.0f} min on GPU",
|
| 686 |
+
)
|
| 687 |
+
print(f"Uploaded to https://huggingface.co/{args.repo}/tree/main/{args.folder}")
|
| 688 |
+
|
| 689 |
+
|
| 690 |
+
if __name__ == "__main__":
|
| 691 |
+
main()
|