CraneAILabs/edu-ganda-gemma-e2b-v5
0844
edu-ganda-gemma-e2b-v5 (EXPERIMENTAL — current best)
Experimental research checkpoint — Crane AI Labs' current best Luganda primary-education assistant. A SLERP merge (alpha 0.5) of two Crane experimental Gemma-4-E2B checkpoints:
a065_polished_v2— Luganda-vocabulary-repaired base (good Luganda content, weak instruction-following), andganda-e2b-v4(edu-ganda-gemma-e2b-v4) — strong instruction-following (weaker Luganda content).
The merge combines V2's Luganda accuracy with v4's instruction-following, and beats V2, every finetuning attempt (GRPO/SFT), and every alternative merge we tried (including pre-QAT-v4 merges).
Good at (guard-free, vs the a065polishedv2 base)
Bad at
- FLORES lug→en translation — chrF about −3.3 vs base.
- Guarded followed% caps around ~44% (n=25, a coarse judge metric).
Required serving settings (OPTIMAL — from a guard sweep)
- `repetition_penalty=1.0` (off) + `no_repeat_ngram_size=4` → doom 0/0, math 68.3, IF 68.3. This is the recommended guard. The older
1.15 / 3guard is over-tuned and costs roughly −7 pt math and −3 pt IF for no doom benefit here. eos_token_id=[<eos>, <end_of_turn>].- Prepend
<bos>(id 2) before the chat-templated prompt.
Base models
a065_polished_v2(Crane experimental, Luganda-vocab-repaired)ganda-e2b-v4=CraneAILabs/edu-ganda-gemma-e2b-v4(Crane experimental)
Experimental research checkpoint. Best-effort Luganda content; review before high-stakes use.
Usage
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
MODEL = "CraneAILabs/edu-ganda-gemma-e2b-v5"
tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForCausalLM.from_pretrained(MODEL, torch_dtype=torch.bfloat16, device_map="auto").eval()
eos_ids = [tok.eos_token_id] + tok.convert_tokens_to_ids(["<end_of_turn>"])
def chat(prompt, max_new_tokens=256):
text = tok.apply_chat_template([{"role": "user", "content": prompt}],
add_generation_prompt=True, tokenize=False)
inputs = tok(text, return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=max_new_tokens, do_sample=False,
repetition_penalty=1.0, no_repeat_ngram_size=4, # guard: prevents loops
eos_token_id=eos_ids, pad_token_id=tok.pad_token_id or tok.eos_token_id)
return tok.decode(out[0, inputs.input_ids.shape[1]:], skip_special_tokens=True).strip()
print(chat("Nnyonnyola engeri y'okunaaba engalo mu Luganda."))Recommended decoding: greedy with repetition_penalty=1.0, no_repeat_ngram_size=4 (best doom/math/instruction-following tradeoff from a guard sweep), eos_token_id=[<eos>, <end_of_turn>]. The n-gram guard is needed to prevent loops.
