# Turkish district (ilçe) name generator A small **separate** side task inside this repo, deliberately kept apart from the main [eldamar-tokenizer](../README.md) BPE pipeline. Same four tiny architectures, but a different dataset (Turkish district names) and the original repo's plain **character** tokeniser — no BPE. ``` $ python districts/generate_districts.py gemma4 --count 10 --temperature 0.8 --seed 1 karaisalı tosya çukurca lapseki mudurnu mudurnu çukurca göynü… erenler selkit ``` `karaisalı`, `tosya`, `lapseki`, `mudurnu` and `erenler` are real districts the model has learnt; `selkit` and the rest are invented but plausibly Turkish. ## What it reuses (unchanged) This task **does not touch** the `src/` BPE pipeline. It reuses the original `single_letter_transformers` repo directly: - `single_letter_transformers/data/temizle_isimler.py` — the repo's Turkish aware cleaner (correct here: it lower-cases with the proper Turkish `I/İ` rules, splits multi-word names, and de-duplicates). - each architecture's `tokenizer.py` (`CharTokenizer`), `config.py` and `model.py`. ## Data Source: the Turkish Wikipedia article [**Türkiye'nin ilçeleri**](https://tr.wikipedia.org/wiki/Türkiye'nin_ilçeleri), a single large sortable table where column 1 is the province (il) and **column 2 is the district (ilçe)**. [`scrape_ilceler.py`](scrape_ilceler.py) fetches it through the MediaWiki API (URL-encoding the Turkish title so it can't get corrupted) and keeps the display text of every column-2 link. - `ilceler_ham.txt` — **973** raw district names (matches the article's stated count). - `ilceler_temiz.txt` — **950** cleaned tokens, produced by the repo's `temizle_isimler.py`. Vocabulary: **32** characters (29 Turkish letters + newline + the digits `1`/`9`, which leak in from the one numeric district "19 Mayıs" → `19`; left as-is because the brief was to use the repo cleaner unchanged). ## Results All four architectures trained for a **uniform 5,000 steps** on CPU (baseline `ln 32 ≈ 3.47`). Because they all share the same character tokeniser, the losses are directly comparable across architectures. | Architecture | Params | Steps | Final loss | Sample names | | -------------------------- | ------ | ----- | ---------- | ------------------------------------------- | | **Qwen3** (dense) | 19.6k | 5000 | 0.85 | çınar, karaman, paluova, tikmen | | **Qwen3.5** (hybrid) | 42.1k | 5000 | 0.57 | aydıncık, havsa, başyayla, büyükçekmece | | **Gemma** (sliding-window) | 63.4k | 5000 | **0.54** | altındağ, gökçeada, sarıoğlan, arsambitözü | | **DeepSeek-V3** (MoE) | 48.0k | 5000 | 0.62 | çamlıhemşin, konyaaltı, bigadiç, çatalpınar | ## Run it ```bash python districts/scrape_ilceler.py # -> ilceler_ham.txt (973) python single_letter_transformers/data/temizle_isimler.py \ districts/ilceler_ham.txt districts/ilceler_temiz.txt # -> ilceler_temiz.txt (950) for a in qwen3 qwen3_5 gemma4 deepseek3; do python districts/train_districts.py $a; done python districts/generate_districts.py gemma4 --count 20 --temperature 0.8 ``` `train_districts.py [--steps N]` and `generate_districts.py [--count N --temperature T --seed S]`. Keep the step count the same across all four for a fair comparison (the default is 5,000 for every architecture). ## Files ``` districts/ ├── scrape_ilceler.py # fetch + extract column 2 (İlçe) from tr.wikipedia ├── ilceler_ham.txt # 973 raw district names ├── ilceler_temiz.txt # 950 cleaned tokens (via the repo's temizle_isimler.py) ├── train_districts.py # train one architecture (CharTokenizer) → checkpoints/.pt ├── generate_districts.py # sample district names from a checkpoint └── checkpoints/ # .pt (4 models) ```