""" © KAND CA 2026 - train a 32K BPE tokenizer balanced across English and Arabic. The existing custom_llama_tokenizer (32K) was fit on Arabic-only text (uonlp/CulturaX, ar). It works on English by falling back toward byte-level fragments - functional, but roughly 2x tokens/word versus a tokenizer that actually learned English subwords, measured on the router corpus. This script fixes that at the source: interleave English and Arabic documents into the SAME training stream before the BPE merges are learned, so common English and Arabic subwords both earn vocabulary slots on equal footing, rather than English being an afterthought squeezed into merges fit for Arabic. Same sources as the two pretraining corpora this tokenizer is meant to serve: Arabic - kaust-generative-ai/fineweb-edu-ar (what tokens_20B_sep.bin is built from) English - HuggingFaceFW/fineweb-edu (what build_tokens_en.py streams) 5M documents each, alternating one-for-one, matching the original tokenizer's 10M-document training budget so this is a like-for-like replacement, not a smaller or larger fit. python train_tokenizer_bilingual.py """ from itertools import islice from datasets import load_dataset from tokenizers import ByteLevelBPETokenizer from tqdm import tqdm N_PER_LANG = 5_000_000 OUT_PREFIX = "bilingual32k_tokenizer" ar = load_dataset("kaust-generative-ai/fineweb-edu-ar", "ar", split="train", streaming=True) en = load_dataset("HuggingFaceFW/fineweb-edu", "sample-10BT", split="train", streaming=True) def get_training_corpus(): ar_it = (ex["text"] for ex in ar if (ex.get("text") or "").strip()) en_it = (ex["text"] for ex in en if (ex.get("text") or "").strip()) for a, e in tqdm(islice(zip(ar_it, en_it), N_PER_LANG), total=N_PER_LANG, desc="[*] feeding AR+EN pairs"): yield a yield e tokenizer = ByteLevelBPETokenizer() print("[*] training bilingual tokenizer...") tokenizer.train_from_iterator( get_training_corpus(), vocab_size=32_000, min_frequency=2, show_progress=True, special_tokens=["", "", "", "", ""], ) tokenizer.save_model(".", OUT_PREFIX) print(f"[+] saved -> {OUT_PREFIX}-vocab.json / {OUT_PREFIX}-merges.txt")