Downloads · 30 days
8
6% of all-time downloads
Egonyu/ateso-english-nllb
ateso-english-nllb is a translation model from Egonyu. Use it when you need text moved from one language to another. It is set up for transformers. The card lists the license as cc-by-nc-4.0.
⚠️ Use Egonyu/ateso-english-nllb-v3 instead English → Ateso on this model does not produce Ateso. It produces Luganda, an unrelated Bantu language — fluently and confidently, which makes the failure easy to miss if yo…
Downloads · 30 days
8
6% of all-time downloads
All-time downloads
136
Public
Parameters
615M
2.5 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors2.5 GB · 99%
From the Hugging Face model README
⚠️ Use
Egonyu/ateso-english-nllb-v3insteadEnglish → Ateso on this model does not produce Ateso. It produces Luganda, an unrelated Bantu language — fluently and confidently, which makes the failure easy to miss if you do not read Ateso.
"The children are going to school." -> "Abaana bagenda ku ssomero." # Luganda "I am hungry." -> "Nnina enjala." # Luganda
Ateso → English works on this model and is genuinely Ateso-aware. Only the reverse direction is affected.
The teo_Latn token does not exist in base NLLB-200, so it was added and its
embedding initialised by copying the lug_Latn (Luganda) row. The model was then
wrapped in LoRA targeting only q_proj, v_proj, k_proj, out_proj, fc1, fc2, with
no modules_to_save.
That froze the embedding table. The Luganda seed was made untrainable and never moved across the whole training run:
torch.equal(emb[teo_id], emb[lug_id]) # True
(emb[teo_id] - emb[lug_id]).abs().max() # 0.000e+00
torch.equal(lm_head[teo_id], lm_head[lug_id]) # True (weights are tied)
Since NLLB ties lm_head to the input embedding, forced_bos_token_id=teo_Latn
was mathematically identical to forced_bos_token_id=lug_Latn. Ateso → English
worked because the encoder learned Ateso; the decoder side was never trained.
The general lesson: if you add a new language token to a multilingual model
and then fine-tune with LoRA, the new embedding is frozen unless you explicitly
include it — via modules_to_save, or by unfreezing the embedding table. Training
will complete, the loss will fall, and your new language will silently remain a
copy of whatever you seeded it from.
Test for it directly. BLEU will not catch this — fluent output in the wrong language can score plausibly against nothing:
a = generate(text, forced_bos_token_id=new_lang_id)
b = generate(text, forced_bos_token_id=seed_lang_id)
assert a != b, "the new language token never separated from its seed"
| v1 | v3 | |
|---|---|---|
| Fine-tuning | LoRA (embedding frozen) | Full fine-tune |
teo_Latn seed | lug_Latn (Bantu, unrelated) | Re-seeded, norm-matched |
cos(teo_Latn, lug_Latn) | +1.0000 | −0.0157 |
| Ateso lexicon overlap, En→Teo | 0.000 | 0.842 |
This model remains published because the failure is instructive and because Ateso → English still works. For anything practical, use v3.
cc-by-nc-4.0, inherited from facebook/nllb-200-distilled-600M.
Non-commercial use only.
@misc{egonyu2026ateso,
title = {Ateso--English Neural Machine Translation},
author = {Egonyu, Daniel},
year = {2026},
howpublished = {\url{https://huggingface.co/Egonyu/ateso-english-nllb-v3}},
note = {Ateker Language Initiative}
}
Built by Daniel Egonyu · Ateker Language Initiative