Whisper-small — Luganda Agricultural ASR (E2 · Stage 1)
"Building an ASR Model for Luganda Agricultural Information Access"
Experiment E2 of a 9-condition matrix (3 models × 3 strategies). Training logged in real-time at W&B run.
Evaluation Results
| Test set | Domain | n | WER (%) | CER (%) | 95 % CI |
|---|---|---|---|---|---|
| CV25 Luganda — test (T1) | General Luganda | 11,823 | 46.5 | 48.04 | [35.25, 57.63] |
| Yogera Agricultural — test (T2) | Agricultural Luganda | 11,679 | 34.94 | 11.54 | [34.43, 35.46] |
Domain gap (T2 − T1 WER): -11.56 pp
Decoding uses beam search (num_beams = 5) with custom <|luganda|> language token
forced at position 1 (Luganda is not in Whisper's 99 supported languages).
Training Details
| Parameter | Value |
|---|---|
| Base model | openai/whisper-small |
| Strategy | Single-stage fine-tuning (Stage 1) |
| Training data | Common Voice 25 Luganda — train split |
| Validation | Common Voice 25 Luganda — dev split |
| Max steps | 15,000 |
| Warmup steps | 500 |
| Learning rate | 1e-05 |
| Effective batch size | 32 |
| Precision | bf16 |
| SpecAugment | Yes |
| Best validation WER | 46.28% |
| Total steps trained | 15,000 |
Usage
from transformers import pipeline
# Model config stores forced_decoder_ids for <|luganda|> + <|transcribe|>.
# No need to pass language= (Luganda is not in Whisper's built-in token list).
pipe = pipeline(
"automatic-speech-recognition",
model="Gemmar/luganda-agr-asr-whisper-small-stage1",
generate_kwargs={"task": "transcribe", "num_beams": 5},
)
result = pipe("your_audio.wav")
print(result["text"])
Citation
@mastersthesis{gemmar2026luganda,
author = {Freedom Gemmar},
title = {Building an ASR Model for Luganda Agricultural Information Access},
school = {Makerere University},
year = {2026},
}