SPB Git

spb/forge Public MIT

Forge — LLM training from scratch in pure C++20 + Metal on Apple Silicon.

C++ 61.2% C 23% Python 7.6% TeX 7.2% CMake 1.1%
2.1 KB · 62 lines python
Raw Blame History
1# Author: Simon-Pierre Boucher — contact@spboucher.ai2"""Cross-check the Python (vectorized) and C++ (greedy lowest-id) BPE3encoders on real text.45Encodes a text sample with tools/prepare_data.py's encoder, dumps the ids,6then runs test_tokenizer with FORGE_TOK_* pointing at them so the C++ side7compares. Exits nonzero on disagreement.89Usage:10  python3 tests/tokenizer_agreement.py --model data/tinystories/tok4096.model \11      --text data/tinystories/TinyStoriesV2-GPT4-valid.txt --bytes 200000 \12      --binary build/test_tokenizer13"""14import argparse15import os16import subprocess17import sys18import tempfile1920sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "tools"))21import prepare_data as pd  # noqa: E402222324def main():25    ap = argparse.ArgumentParser()26    ap.add_argument("--model", required=True)27    ap.add_argument("--text", required=True)28    ap.add_argument("--bytes", type=int, default=200000)29    ap.add_argument("--binary", default="build/test_tokenizer")30    args = ap.parse_args()3132    with open(args.text, "rb") as f:33        sample = f.read(args.bytes)34    # cut at a story boundary so the comparison matches how .bin is built35    sep = b"<|endoftext|>"36    if sep in sample:37        sample = sample[: sample.rindex(sep)]3839    pd._MERGES = pd.load_merges(args.model)40    ids = pd.encode_block(sample)41    print(f"python: {len(sample)} bytes -> {len(ids)} tokens")4243    with tempfile.TemporaryDirectory() as td:44        text_path = os.path.join(td, "text.bin")45        ids_path = os.path.join(td, "ids.txt")46        with open(text_path, "wb") as f:47            f.write(sample)48        with open(ids_path, "w") as f:49            f.write("\n".join(str(int(i)) for i in ids))5051        env = dict(os.environ)52        env["FORGE_TOK_MODEL"] = os.path.abspath(args.model)53        env["FORGE_TOK_TEXT"] = text_path54        env["FORGE_TOK_IDS"] = ids_path55        rc = subprocess.call([os.path.abspath(args.binary)], env=env,56                             cwd=os.path.dirname(os.path.abspath(args.binary)))57    sys.exit(rc)585960if __name__ == "__main__":61    main()62