Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
e9d6e90
Add boundary-marker pretokenizer prototypes and write-up
claude Jul 26, 2026
b9018cc
Add FineWiki English results: v5 beats baseline on prose-only training
claude Jul 26, 2026
9fc5c4b
Complete FineWiki 6-language results: v5 beats baseline in all six
claude Jul 26, 2026
acf6a0b
Span-based boundary pretokenizer with configurable targets, plus tests
claude Jul 26, 2026
9a3c92c
FineWiki 1GB grid: en_plain_bpe
claude Jul 26, 2026
fff6254
Make the 1GB grid disk-lean: stream text, free corpora per language
claude Jul 26, 2026
4b14bb0
FineWiki 1GB grid: en_bnd_w_bpe
claude Jul 26, 2026
0a09900
Run BPE across all languages before MinGram
claude Jul 27, 2026
509b4aa
FineWiki 1GB grid: en_bnd_wp_bpe
claude Jul 27, 2026
be1a20a
Retry transient CDN failures; isolate cell failures from the grid
claude Jul 27, 2026
ae193ba
FineWiki 1GB grid: en_bnd_wpd_bpe
claude Jul 27, 2026
90a9635
FineWiki 1GB grid: de_plain_bpe
claude Jul 27, 2026
dae2cc6
FineWiki 1GB grid: de_bnd_w_bpe
claude Jul 27, 2026
14a840b
FineWiki 1GB grid: de_bnd_wp_bpe
claude Jul 27, 2026
f59e52a
FineWiki 1GB grid: de_bnd_wpd_bpe
claude Jul 27, 2026
7ae4931
FineWiki 1GB grid: fi_plain_bpe
claude Jul 27, 2026
586fc5d
FineWiki 1GB grid: fi_bnd_w_bpe
claude Jul 27, 2026
57db40c
FineWiki 1GB grid: fi_bnd_wp_bpe
claude Jul 27, 2026
e187c94
FineWiki 1GB grid: fi_bnd_wpd_bpe
claude Jul 27, 2026
f5abd0f
FineWiki 1GB grid: ru_plain_bpe
claude Jul 27, 2026
d4a456d
FineWiki 1GB grid: ru_bnd_w_bpe
claude Jul 27, 2026
3e791aa
FineWiki 1GB grid: ru_bnd_wp_bpe
claude Jul 27, 2026
56d152b
FineWiki 1GB grid: ru_bnd_wpd_bpe
claude Jul 27, 2026
05d3ec5
Read all parquet shards per language, not just the first
claude Jul 27, 2026
504a72e
FineWiki 1GB grid: ar_plain_bpe
claude Jul 27, 2026
edfe276
FineWiki 1GB grid: ar_bnd_w_bpe
claude Jul 27, 2026
33fd244
FineWiki 1GB grid: ar_bnd_wp_bpe
claude Jul 27, 2026
ba68cdb
FineWiki 1GB grid: ar_bnd_wpd_bpe
claude Jul 27, 2026
3a74386
FineWiki 1GB grid: ko_plain_bpe
claude Jul 27, 2026
4017ae7
FineWiki 1GB grid: ko_bnd_w_bpe
claude Jul 27, 2026
85d238a
FineWiki 1GB grid: ko_bnd_wp_bpe
claude Jul 27, 2026
594df6f
FineWiki 1GB grid: ko_bnd_wpd_bpe
claude Jul 27, 2026
9186358
Rewrite paper for the span-based design and 1GB results
claude Jul 27, 2026
5dec932
Support digit_handling with boundaries; quantify the digit-variant tax
claude Jul 27, 2026
daad06d
FineWiki 1GB grid: en_plain_mingram
claude Jul 27, 2026
75322fb
Add digit-split experiment; ScriptPretokenizer needs two fixes for di…
claude Jul 27, 2026
2babe2c
FineWiki 1GB grid: en_plain_SPLIT
claude Jul 27, 2026
10c8dd2
Withhold eval documents from training; scale digit axis to 250M chars
claude Jul 27, 2026
2e65d9d
FineWiki 1GB grid: en_plain_None
claude Jul 27, 2026
4d35928
FineWiki 1GB grid: en_bnd_wpd_None
claude Jul 27, 2026
08eda80
FineWiki 1GB grid: en_plain_SPLIT
claude Jul 27, 2026
f93ed99
Fix KeyError on non-ASCII numerics under digit_handling
claude Jul 27, 2026
c57bd36
FineWiki 1GB grid: en_bnd_wpd_SPLIT
claude Jul 27, 2026
dc38616
FineWiki 1GB grid: en_plain_RTL3
claude Jul 27, 2026
908b309
FineWiki 1GB grid: en_bnd_wpd_RTL3
claude Jul 27, 2026
e8d1f1a
Digit-handling axis: the bound holds exactly, and buys +0.33pp
claude Jul 27, 2026
0e2bc7c
Add MinGram vs BPE grid at a scale that completes
claude Jul 27, 2026
6af84aa
FineWiki 1GB grid: en_plain_bpe
claude Jul 27, 2026
f59e525
FineWiki 1GB grid: en_plain_mingram
claude Jul 27, 2026
940acfc
FineWiki 1GB grid: en_bnd_w_bpe
claude Jul 27, 2026
dfc84bb
FineWiki 1GB grid: en_bnd_w_mingram
claude Jul 27, 2026
6cbb060
FineWiki 1GB grid: en_bnd_wp_bpe
claude Jul 27, 2026
a8a3ccb
FineWiki 1GB grid: en_bnd_wp_mingram
claude Jul 27, 2026
cfb2d98
FineWiki 1GB grid: en_bnd_wpd_bpe
claude Jul 27, 2026
3f69509
FineWiki 1GB grid: en_bnd_wpd_mingram
claude Jul 27, 2026
d338146
FineWiki 1GB grid: ru_plain_bpe
claude Jul 27, 2026
f635a7c
FineWiki 1GB grid: ru_plain_mingram
claude Jul 27, 2026
6bcc34f
FineWiki 1GB grid: ru_bnd_w_bpe
claude Jul 27, 2026
afe74f4
FineWiki 1GB grid: ru_bnd_w_mingram
claude Jul 27, 2026
435f841
FineWiki 1GB grid: ru_bnd_wp_bpe
claude Jul 27, 2026
96e081a
FineWiki 1GB grid: ru_bnd_wp_mingram
claude Jul 27, 2026
db827eb
FineWiki 1GB grid: ru_bnd_wpd_bpe
claude Jul 27, 2026
9472090
FineWiki 1GB grid: ru_bnd_wpd_mingram
claude Jul 27, 2026
998853f
FineWiki 1GB grid: ko_plain_bpe
claude Jul 27, 2026
5d0c61e
FineWiki 1GB grid: ko_plain_mingram
claude Jul 27, 2026
dbac233
FineWiki 1GB grid: ko_bnd_w_bpe
claude Jul 27, 2026
333caf9
FineWiki 1GB grid: ko_bnd_w_mingram
claude Jul 27, 2026
fcfca9b
FineWiki 1GB grid: ko_bnd_wp_bpe
claude Jul 27, 2026
5b27f37
FineWiki 1GB grid: ko_bnd_wp_mingram
claude Jul 27, 2026
936b88d
FineWiki 1GB grid: ko_bnd_wpd_bpe
claude Jul 27, 2026
4dc915b
FineWiki 1GB grid: ko_bnd_wpd_mingram
claude Jul 27, 2026
3c69ea9
MinGram results, and Korean changes sign with scale
claude Jul 27, 2026
db956b5
Add ACL LaTeX source and bibliography
claude Jul 28, 2026
edada5c
Cite SCRIPT and MinGram correctly; match the MinGram paper's table style
claude Jul 29, 2026
92f9670
Use the supplied bibliography; add related work on SuperBPE and Bound…
claude Jul 29, 2026
ee42f38
State the pretokenization dependency of the single-marker design
claude Jul 29, 2026
ee02cd2
Add caps codes for word spans, in the style of the older Claude token…
claude Jul 29, 2026
727a13f
Add caps-code compression experiment
claude Jul 29, 2026
33a7655
FineWiki 1GB grid: en_bnd_wpd
claude Jul 29, 2026
11ae9e4
FineWiki 1GB grid: en_bnd_wpd_caps
claude Jul 29, 2026
6e0b3bd
Caps codes remove 29% of the vocabulary at no compression cost
claude Jul 29, 2026
92d1787
Set up the downstream LM evaluation for boundary tokenizers
claude Jul 30, 2026
126585a
Downstream README: concrete branch, verification step, and deliverables
claude Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions marker_experiments/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Rebuildable and far too large to track: pretokenized corpora (~90MB each x24),
# on-disk text blocks (~1GB per language), held-out eval slices, BPE init caches.
corpora/
# (text blocks no longer written: streamed straight from parquet)
eval_texts/
bpe_init_cache/
396 changes: 396 additions & 0 deletions marker_experiments/boundary_pretokenizer.py

Large diffs are not rendered by default.

150 changes: 150 additions & 0 deletions marker_experiments/caps_grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""Do caps codes pay for themselves?

Same duplication argument as the leading space, applied to case: without caps codes a
vocabulary holds 'The' and 'the', 'NASA' and 'nasa' as separate entries. With them, a
title-case span is a shift code plus the lowercased form, so the pieces are shared.

The cost is one extra token per capitalised span, and sentence-initial capitals are very
frequent, so this can easily come out negative. Section 5.3 already showed that reclaiming
vocabulary does not automatically buy compression: removing a 3.17% digit-variant tax was
worth +0.33pp.

en, 250M characters, 32,768 additional vocabulary, BPE, evaluation withheld from training
-- the same setup as the digit axis, so the plain and bnd_wpd cells there are directly
comparable and are reused.
"""

import json
import os
import sys
import time

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)

from script_bpe.corpus.base import PretokenizedCorpus
from script_bpe.pretokenize.scriptencoding import ScriptEncodingV3
from script_bpe.tokenizers.bpe.trainer import BPETrainer, BPETrainerConfig

import finewiki1gb_grid as G
from boundary_pretokenizer import BoundaryScriptPretokenizer, BoundaryScriptPretokenizerConfig
from finewiki1gb_grid import CORPORA, NUM_WORKERS, VOCAB, analyse_vocab, commit_cell, ensure_eval, log, train_batches

LANG = "en"
CHARS = 250_000_000
RESULT_PATH = os.path.join(HERE, "caps_result.json")
TOKENIZERS = os.path.join(HERE, "tokenizers")

VARIANTS = {
"bnd_wpd": dict(caps_codes=False),
"bnd_wpd_caps": dict(caps_codes=True),
}


def make_pt(**kw):
return BoundaryScriptPretokenizer(
BoundaryScriptPretokenizerConfig(
script_config=ScriptEncodingV3, boundary_targets=("word", "punct", "digit"), **kw
)
)


def case_stats(tokenizer, pt):
"""Vocabulary spent on case variants of the same word.

Counts entries whose decoded text has a distinct-cased counterpart also in the
vocabulary ('The'/'the'), which is the case analogue of the ' X'/'X' pair count.
"""
marker = getattr(pt, "marker_token_id", None)
codes = {pt.shift_token_id, pt.caps_token_id} - {None}
texts = {}
for t in tokenizer.tokens.values():
ids = [x for x in t.atomic_tokens if x != marker and x not in codes]
if not ids:
continue
txt = pt.try_decode_strict(ids)
if txt and txt.isalpha():
texts.setdefault(txt, 0)
texts[txt] += 1
pairs = 0
seen = set()
for txt in texts:
if txt.islower() or txt in seen:
continue
low = txt.lower()
if low != txt and low in texts:
pairs += 1
seen.add(txt)
seen.add(low)
return {
"alpha_entries": len(texts),
"case_dup_pairs": pairs,
"case_dup_vocab_frac": 2 * pairs / len(tokenizer.tokens),
}


def main():
os.makedirs(TOKENIZERS, exist_ok=True)
G.CHARS_PER_LANG = CHARS
results = json.load(open(RESULT_PATH)) if os.path.exists(RESULT_PATH) else {}
eval_texts = ensure_eval(LANG)
eval_chars = sum(map(len, eval_texts))
log(f"eval: {len(eval_texts)} docs, {eval_chars:,} chars")

for tag, kw in VARIANTS.items():
key = f"{LANG}_{tag}"
if key in results:
log(f"{key}: done, skipping")
continue
pt = make_pt(**kw)
corpus_name = f"caps250_{LANG}_{tag}"
try:
corpus = PretokenizedCorpus(name=corpus_name, base_path=CORPORA, pretokenizer=pt)
except FileNotFoundError:
t = time.time()
corpus = PretokenizedCorpus.from_text_batches(
name=corpus_name, base_path=CORPORA, pretokenizer=pt,
text_batches=train_batches(LANG), num_workers=NUM_WORKERS,
)
log(f"{key}: corpus built in {time.time()-t:.0f}s "
f"unique_chunks={corpus.metadata.get('unique_chunks'):,}")

t = time.time()
tokenizer = BPETrainer(
pt, corpus, BPETrainerConfig(additional_vocab_size=VOCAB, num_workers=NUM_WORKERS)
).train()
train_time = time.time() - t
# Prefix with the corpus tag. Without it this 250M-char cell writes
# en_bnd_wpd_bpe_32k.json.gz, the same path the 1 GB grid uses, and silently
# replaces that artifact with a smaller-corpus tokenizer of the same name.
out = os.path.join(TOKENIZERS, f"{corpus_name}_bpe_32k.json.gz")
tokenizer.save(out)

toks = fails = 0
for text in eval_texts:
ids = tokenizer.encode(text)
toks += len(ids)
if tokenizer.decode(ids) != text:
fails += 1

results[key] = {
"lang": LANG, "variant": tag, "caps_codes": kw["caps_codes"],
"atomic_vocab": len(pt.atomic_tokens), "vocab_size": len(tokenizer.tokens),
"train_seconds": round(train_time),
"unique_chunks": corpus.metadata.get("unique_chunks"),
"eval_chars": eval_chars, "eval_tokens": toks,
"eval_chars_per_token": eval_chars / toks,
"roundtrip_failures": fails,
**analyse_vocab(tokenizer, pt), **case_stats(tokenizer, pt),
}
with open(RESULT_PATH, "w") as f:
json.dump(results, f, indent=2)
log(f" {key}: {eval_chars/toks:.4f} ch/tok case_pairs="
f"{results[key]['case_dup_pairs']} {round(train_time)}s rt={fails}")
commit_cell(key)

log(f"DONE: {len(results)} cells")


if __name__ == "__main__":
main()
44 changes: 44 additions & 0 deletions marker_experiments/caps_result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"en_bnd_wpd": {
"lang": "en",
"variant": "bnd_wpd",
"caps_codes": false,
"atomic_vocab": 1711,
"vocab_size": 34479,
"train_seconds": 92,
"unique_chunks": 906491,
"eval_chars": 2219281,
"eval_tokens": 571265,
"eval_chars_per_token": 3.884853789397215,
"roundtrip_failures": 0,
"distinct_alpha_words_with_own_token": 15021,
"space_dup_pairs": 5,
"space_dup_vocab_frac": 0.0002900316134458656,
"marker_variant_extra_slots": 212,
"whitespace_only_vocab_entries": 28,
"alpha_entries": 26661,
"case_dup_pairs": 5017,
"case_dup_vocab_frac": 0.29101772093158157
},
"en_bnd_wpd_caps": {
"lang": "en",
"variant": "bnd_wpd_caps",
"caps_codes": true,
"atomic_vocab": 1713,
"vocab_size": 34481,
"train_seconds": 92,
"unique_chunks": 906765,
"eval_chars": 2219281,
"eval_tokens": 571502,
"eval_chars_per_token": 3.8832427533062,
"roundtrip_failures": 0,
"distinct_alpha_words_with_own_token": 15051,
"space_dup_pairs": 5,
"space_dup_vocab_frac": 0.00029001479075432845,
"marker_variant_extra_slots": 214,
"whitespace_only_vocab_entries": 28,
"alpha_entries": 21819,
"case_dup_pairs": 91,
"case_dup_vocab_frac": 0.005278269191728778
}
}
Loading
Loading