# RU-CPT corpus + training — runbook Scripts for building our own RU-native base (continued pretraining of Qwen3-1.7B-Base). Full plan: `Maven/docs/plans/2026-07-11-ru-cpt-base.md`. ## One-time setup ```bash pip install datasets ftfy datasketch fasttext openai peft accelerate wget -O data/lid.176.bin \ https://dl.fbaipublicfiles.com/fasttext/supervised-models/lid.176.bin huggingface-cli login # accept CulturaX (gated) license ``` `fasttext` build fails → `pip install fasttext-wheel`. Move the model → `export FASTTEXT_LID=/path`. ## Run order ```bash # Phase 2 — corpus (build first; longest) python corpus_fetch.py all ROUTER_BASE_URL="https://your-router/v1" ROUTER_API_KEY="..." \ ROUTER_MODELS="m-a,m-b,m-c" python corpus_synth.py # ≤10% hard cap MAVEN_LOGS=/path/to/dialogue.jsonl python corpus_logs.py # optional python corpus_clean.py # ftfy+langID+dedup python corpus_stats.py # DONE-CHECK, eyeball python corpus_pack.py # → data/cpt_packed/ # Phase 3 — CPT (days; --resume to continue; CPT_PATH=dora if OOM) HSA_OVERRIDE_GFX_VERSION=11.0.0 python train_cpt.py 2>&1 | tee cpt_run.log # Phase 4 — eval + gate python eval_cyrillic.py --model Qwen/Qwen3-1.7B-Base # baseline python eval_cyrillic.py --model ./Qwen3-1.7B-ru-cpt # must beat baseline # Phase 6-7 — persona LoRA (train_rocm.py @ ./Qwen3-1.7B-ru-cpt) → GGUF → Q8_0 → homesrv ``` ## Gotchas (a fresh agent WILL hit these) - **Run `corpus_clean.py` with NO args (all buckets in ONE invocation).** Dedup is a single in-memory MinHash-LSH shared across buckets. Cleaning buckets in separate runs = no cross-bucket dedup = duplicated data across sources. - **Disk space.** `corpus_fetch.py` over-pulls ~1.5× and CulturaX streaming still caches to `HF_DATASETS_CACHE` (`/mnt/D/.cache/...`). Expect tens of GB of raw + cache. Check `df -h /mnt/D` before starting; `rm -rf data/cpt_raw` after packing. - **Strict order.** fetch → clean → pack → train. `corpus_pack.py` reads `data/cpt_clean/`; `train_cpt.py` reads `data/cpt_packed/`. Skipping a stage silently trains on nothing (empty dataset → instant "done", garbage model). - **`corpus_pack.py` prints the final token count — READ IT.** Must be ~300M ±50M. Way under → a fetch failed or clean dropped too much; way over → over-pulled. Do not train on a 20M-token corpus and expect CPT to work. - **Verify the base repo id exists**: `Qwen/Qwen3-1.7B-Base`. If HF 404s, the naming shifted — find the current Qwen3 ~1.7B *base* (non-Instruct) id. - **Eval held-out set must NOT be training data.** `--eval-text` should point at real RU text you set aside before packing, or the PPL number is a lie. - **Re-running is safe.** fetch/clean/pack/synth all overwrite their outputs; CPT resumes with `--resume`. No manual cleanup needed between retries. ## Hard rules (full list in the plan §9) 1. CPT corpus = raw text; persona `{response,mood}` is a separate Phase-6 dataset. 2. Synthetic ≤ 10%. 3. lr 1e-5, 1 epoch. 4. Base = Qwen3-1.7B-**Base**. 5. Never quantize before merge. 6. All sources through corpus_clean.py. 7. Don't skip a DONE-CHECK; if CPT loses to raw, stop (Phase 5 gate).