Environment for testing and fine-tuning OpenAI Whisper models on African languages, starting with English (baseline/control) and Kiswahili. Chichewa will be added the same way once that phase starts (see Adding a new language).
whisper/
├── lib/ # shared code - config loading, dataset I/O, collator, metrics, model loading
├── scripts/ # 4 CLI entry points, parameterized by --language
│ ├── prepare_dataset.py # pull a dataset subset -> manifest + wav files
│ ├── run_baseline.py # WER + confidence report for a (pretrained or fine-tuned) model
│ ├── finetune.py # fine-tuning loop
│ └── export_model.py # sanity check + CTranslate2 export
├── colab_finetune.ipynb # runs finetune.py on a Colab GPU with real hyperparameters
├── english/
│ ├── config.yaml # language + dataset config, CPU-smoke-test hyperparameter overrides
│ ├── data/ # generated by prepare_dataset.py (gitignored)
│ ├── results/ # generated by run_baseline.py (gitignored)
│ └── models/ # generated by finetune.py / export_model.py (gitignored)
└── kiswahili/ # same structure
All pipeline logic lives in lib/ and scripts/; language folders hold only a
config file plus generated artifacts, so the four scripts behave identically for
every language - only config.yaml differs.
python -m venv .venv
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass # only if activation is blocked
.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
# CPU box (this machine):
pip install torch --index-url https://download.pytorch.org/whl/cpu
# GPU box later: pip install torch (or the CUDA-specific index URL from pytorch.org/get-started/locally)
pip install -r requirements.txtffmpeg is not required for the default dataset (WAV audio, decoded via soundfile).
It would be needed if a source with MP3/OGG audio is added later
(winget install --id Gyan.FFmpeg).
- Internet is needed at
pip installtime and at dataset-download time. - No Hugging Face account or token is needed for the default dataset
(
google/fleurs, ungated, CC-BY-4.0). - Mozilla Common Voice is not used as the default source: as of October 2025 it's
gated behind a separate Mozilla Data Collective
account rather than being directly downloadable via
datasets.prepare_dataset.pyis dataset-source-agnostic (config-drivendataset_id/dataset_config), so Common Voice (or any other corpus, e.g. real Ushahidi audio) can be swapped in later purely viaconfig.yaml, with no code changes.
All commands below work identically for --language english and --language kiswahili.
# 1. Pull a small dataset subset (defaults to data.max_samples[<split>] in config.yaml)
python whisper/scripts/prepare_dataset.py --language english --split train
python whisper/scripts/prepare_dataset.py --language english --split validation
python whisper/scripts/prepare_dataset.py --language english --split test
# 2. Baseline accuracy of the pretrained model (WER + per-sample confidence)
python whisper/scripts/run_baseline.py --language english --model openai/whisper-tiny
# 3. Fine-tune (CPU smoke test - see below)
python whisper/scripts/finetune.py --language english --model openai/whisper-tiny
# 4. Sanity-check + export the fine-tuned model
python whisper/scripts/export_model.py --language english \
--model-dir whisper/english/models/whisper-tiny-finetunedResults land in whisper/<language>/results/baseline_<model>_<split>.{json,csv} -
per-sample reference/hypothesis/WER/confidence plus an aggregate WER and mean
confidence. Confidence is currently a sequence-level proxy (exp(average log-prob)
of the generated sequence, via model.generate(output_scores=True)); a per-word
confidence flag would use model.compute_transition_scores aligned to word
boundaries - not implemented yet, noted here as the next step if that granularity is
needed.
This machine has no GPU. Locally, finetune.py runs with each language's
config.yaml overrides - a handful of steps, batch size 2, fp16 forced off - just
to prove the training loop executes, loss trends down over those steps, and a
checkpoint saves and reloads correctly. It does not produce a usable model.
Real fine-tuning happens on a GPU, e.g. Google Colab (free T4 GPU tier; Colab Pro
for longer/bigger runs): open whisper/colab_finetune.ipynb in Colab, which clones
this repo, installs dependencies, pulls a much larger dataset slice, and runs the
same finetune.py pointed at whisper/lib/default_config.yaml instead of a
language's CPU overrides - using the reference hyperparameters from Hugging Face's
"Fine-Tune Whisper for Multilingual ASR"
guide (lr=1e-5, warmup_steps=500, max_steps=5000, batch_size=16, fp16=True).
Nothing in the scripts changes between the two runs - only the config and the machine.
Colab's free tier disconnects after idle periods and caps sessions at ~12 hours.
Training checkpoints every save_steps regardless of environment, so a disconnect
loses at most that many steps - resume with:
python whisper/scripts/finetune.py --language kiswahili --config whisper/lib/default_config.yaml \
--resume-from-checkpoint whisper/kiswahili/models/<checkpoint-dir>/checkpoint-<step>Optional: pass --use-peft to either finetune.py invocation to wrap the model in a
LoRA adapter (fewer trainable parameters - faster on CPU, lighter on GPU).
export_model.py reloads the fine-tuned model as a sanity check (one sample
transcription), then runs ct2-transformers-converter to produce an
int8-quantized CTranslate2 export for fast
CPU inference via faster-whisper.
GGUF/whisper.cpp export is intentionally not implemented yet - its converter has
known compatibility gaps with safetensors-only checkpoints; revisit if whisper.cpp
deployment becomes a concrete need.
- Create
whisper/<language>/config.yamlwithlanguage_name(must match Whisper's tokenizer language name, e.g.swahilinotsw),language_code,dataset_id,dataset_config, and any CPU-smoke-testtrain:overrides. - Rerun the four scripts above with
--language <language>.
For Chichewa, google/fleurs already has a config (ny_mw, Nyanja/Chichewa -
Malawi) - confirm it's still current before use, since dataset catalogs change.