File size: 3,384 Bytes
b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a b2ad782 aba2c0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | """train point-1 on tinyshakespeare.
fits logits[b] = w * h[b] to the byte histogram. the loss is convex in one
variable so newton's method gets the exact optimum. writes model.safetensors,
config.json, report.txt.
"""
import json, math, os, struct, urllib.request
CORPUS_URL = "https://raw.githubusercontent.com/karpathy/char-rnn/master/data/tinyshakespeare/input.txt"
CORPUS_LOCAL = "corpus.txt"
BYTES_VOCAB = [10] + list(range(32, 127))
H = {b: max(-1.0, min(1.0, (b - 79) / 47.0)) for b in BYTES_VOCAB}
def get_corpus():
if not os.path.exists(CORPUS_LOCAL):
urllib.request.urlretrieve(CORPUS_URL, CORPUS_LOCAL)
return CORPUS_LOCAL
def histogram(path):
counts = dict.fromkeys(BYTES_VOCAB, 0)
total = 0
with open(path, "rb") as f:
while chunk := f.read(65536):
for b in chunk:
if b in counts:
counts[b] += 1
total += len(chunk)
return counts, total
def write_safetensors(w):
payload = struct.pack("<f", w)
header = {"w": {"dtype": "F32", "shape": [1], "data_offsets": [0, 4]}}
hb = json.dumps(header, separators=(",", ":")).encode()
with open("model.safetensors", "wb") as f:
f.write(struct.pack("<Q", len(hb)) + hb + payload)
def main():
counts, total = histogram(get_corpus())
n = float(total)
uniform_loss = math.log(len(BYTES_VOCAB))
floor = -sum((c / n) * math.log(c / n) for c in counts.values() if c)
ch = sum(counts[b] * H[b] for b in BYTES_VOCAB) / n
# newton on L(w) = -(sum c_b (w h_b - logZ)) / n
w = 0.0
log = []
for step in range(60):
ex = [math.exp(w * H[b]) for b in BYTES_VOCAB]
z = sum(ex)
eh = sum(e * H[b] for e, b in zip(ex, BYTES_VOCAB)) / z
var = sum(e * H[b] ** 2 for e, b in zip(ex, BYTES_VOCAB)) / z - eh * eh
loss = -(sum(counts[b] * (w * H[b] - math.log(z)) for b in BYTES_VOCAB)) / n
log.append((step, w, loss))
if abs(eh - ch) < 1e-12:
break
w -= (eh - ch) / max(var, 1e-12)
write_safetensors(w)
cfg = {
"architectures": ["Point1ForCausalLM"],
"model_type": "point1",
"vocab_size": len(BYTES_VOCAB),
"byte_feature": "(b - 79) / 47 clipped to [-1, 1]",
"auto_map": {
"AutoConfig": "modeling_point1.Point1Config",
"AutoModelForCausalLM": "modeling_point1.Point1ForCausalLM",
},
}
with open("config.json", "w") as f:
json.dump(cfg, f, indent=2)
psum = sum(math.exp(w * H[b]) for b in BYTES_VOCAB)
ranked = sorted(
((math.exp(w * H[b]) / psum, chr(b) if b != 10 else "\\n") for b in BYTES_VOCAB),
reverse=True,
)
lines = [
"POINT-1 TRAINING REPORT",
"=" * 52,
f"corpus tinyshakespeare, {total:,} bytes",
"parameters 1",
"",
]
lines += [f"newton {s:>3} w = {wi:+.6f} loss = {li:.4f}" for s, wi, li in log]
lines += [
"",
f"uniform {uniform_loss:.4f} nats/byte",
f"unigram floor {floor:.4f}",
f"point-1 {loss:.4f}",
"",
"top tokens:",
]
lines += [f" '{t}' {p:.4f}" for p, t in ranked[:8]]
report = "\n".join(lines)
print(report)
with open("report.txt", "w") as f:
f.write(report + "\n")
if __name__ == "__main__":
main()
|