Download train_tokenizer.py from SlayerLab/gollem-v5-ckpts: direct link, hf CLI and curl.
- Browser
- Download file 2.88 kB
-
https://huggingface.co/SlayerLab/gollem-v5-ckpts/resolve/e88580ae13aca9b6a7520fae0d34262caa156aa2/train_tokenizer.py
- Command line
-
hf download hf://SlayerLab/gollem-v5-ckpts@e88580ae13aca9b6a7520fae0d34262caa156aa2/train_tokenizer.py
-
curl -L -o train_tokenizer.py https://huggingface.co/SlayerLab/gollem-v5-ckpts/resolve/e88580ae13aca9b6a7520fae0d34262caa156aa2/train_tokenizer.py
2.88 kB
| #!/usr/bin/env python3 | |
| """train_tokenizer.py - GoLLeM-v5 (EN) tokenizer training recipe. | |
| Reproduces the canonical `tokenizer.json` shipped in this repo: | |
| - byte-level BPE (GPT-2 lineage), pre-tokenizer + decoder = ByteLevel | |
| - model vocab 12285 (256 byte alphabet + 12029 learned merges) | |
| - 3 special tokens appended: <|endoftext|> <|im_start|> <|im_end|> | |
| (=> 12288 effective ids; models pad the embedding to 12288) | |
| - trained on the minimal-en-corpus (FineWeb-Edu EN broad mix; `en.parquet`, | |
| the same source uploaded as SlayerLab/minimal-en-corpus-5b). | |
| The shipped `tokenizer.json` remains the canonical / authoritative artifact: | |
| a fresh run reproduces a functionally-equivalent tokenizer, but exact merge | |
| order depends on the corpus snapshot/order, so byte-identity is not guaranteed. | |
| Use this script to audit the method; use `tokenizer.json` for exact parity. | |
| Usage: | |
| python train_tokenizer.py --corpus en.parquet --out tokenizer.json | |
| python train_tokenizer.py --limit 50000 --out tok_smoke.json # quick recipe check | |
| """ | |
| import argparse | |
| import pyarrow.parquet as pq | |
| from tokenizers import Tokenizer, models, trainers, pre_tokenizers, decoders | |
| SPECIAL = ["<|endoftext|>", "<|im_start|>", "<|im_end|>"] | |
| def iter_text(parquet_path, col="text", limit=None): | |
| pf = pq.ParquetFile(parquet_path) | |
| n = 0 | |
| for batch in pf.iter_batches(batch_size=10000, columns=[col]): | |
| for t in batch.column(0).to_pylist(): | |
| if not t: | |
| continue | |
| yield t | |
| n += 1 | |
| if limit and n >= limit: | |
| return | |
| def build(vocab_size): | |
| tok = Tokenizer(models.BPE()) | |
| # ByteLevel with add_prefix_space=False matches the canonical pre_tokenizer/decoder. | |
| tok.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) | |
| tok.decoder = decoders.ByteLevel() | |
| trainer = trainers.BpeTrainer( | |
| vocab_size=vocab_size, | |
| special_tokens=SPECIAL, | |
| initial_alphabet=pre_tokenizers.ByteLevel.alphabet(), # full 256-byte alphabet | |
| show_progress=True, | |
| ) | |
| return tok, trainer | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--corpus", default="C:/Projekty/datasets/build/en/en.parquet") | |
| ap.add_argument("--out", default="tokenizer.json") | |
| ap.add_argument("--col", default="text") | |
| # 12288 = 12285 learned (256 bytes + 12029 merges) + 3 specials, as in canonical. | |
| ap.add_argument("--vocab", type=int, default=12288) | |
| ap.add_argument("--limit", type=int, default=None, help="cap #docs (smoke test)") | |
| a = ap.parse_args() | |
| tok, trainer = build(a.vocab) | |
| tok.train_from_iterator(iter_text(a.corpus, a.col, a.limit), trainer=trainer) | |
| tok.save(a.out) | |
| print(f"saved {a.out} vocab_size={tok.get_vocab_size()} " | |
| f"(specials={SPECIAL}, pre_tokenizer=ByteLevel)") | |
| if __name__ == "__main__": | |
| main() | |