Standalone HuggingFace model (no PEFT dependency required). Adapter has been merged into base weights — load directly with transformers. For further fine-tuning prefer the LoRA adapter.
Held-out test sets, n=100 per dialect, beam=1, deterministic Arabic normalizer (src/normalization.py).
Zero-shot baseline is the unmodified openai/whisper-large-v3-turbo (CT2 int8 / CPU). Fine-tuned numbers
are this model evaluated as PEFT bf16 on a single L4 GPU (apples-to-apples with training precision).
| Dialect | Test source | Zero-shot WER | Fine-tuned WER | Δ |
|---|---|---|---|---|
| MSA | FLEURS Arabic | 10.4% | 11.5% | +1.1 pp |
| Egyptian | Casablanca | 65.0% | 62.7% | −2.3 pp ✅ |
| Gulf | Casablanca | 61.1% | 58.6% | −2.5 pp ✅ |
| avg (3 dialects) | 45.5% | 44.3% | −1.2 pp |
The val WER during training reaches 33.10% on a held-out slice of the training-source distribution.
openai/whisper-large-v3-turbo (this model regresses ~1 pp on FLEURS MSA)openai/whisper-large-v3-turbon=907 (dialect-balanced val mix, no Maghrebi)
| step | val WER | val loss |
|---|---|---|
| 500 | 36.47% | 0.561 |
| 1000 | 36.67% | 0.529 |
| 1500 | 37.83% | 0.518 |
| 2000 | 33.30% | 0.507 |
| 2500 | 33.29% | 0.503 |
| 3000 ← best (loaded as final) | 33.10% | 0.500 |
| Dialect | Source |
|---|---|
| MSA | Common Voice 18 (MohamedRashad/common-voice-18-arabic) |
| Egyptian | MGB-3 (broadcast TV) |
| Levantine | MASC (broadcast TV) |
| Gulf | (held-out evaluation only) |
Maghrebi excluded — Whisper has insufficient Moroccan/Algerian Arabic in pretraining (84.7% zero-shot WER at large-v3 int8) for QLoRA to bring it within range of other dialects in this pipeline.
from transformers import WhisperForConditionalGeneration, WhisperProcessor
import torch
model = WhisperForConditionalGeneration.from_pretrained(
"dev-ahmedhany/whisper-large-v3-turbo-arabic-ft", torch_dtype=torch.bfloat16
)
processor = WhisperProcessor.from_pretrained("dev-ahmedhany/whisper-large-v3-turbo-arabic-ft", language="arabic", task="transcribe")
# inputs = processor(audio, sampling_rate=16000, return_tensors="pt")
# ids = model.generate(input_features=inputs.input_features, language="arabic", task="transcribe")
# text = processor.batch_decode(ids, skip_special_tokens=True)
@misc{hany2026whisper-arabic-dialects,
author = {Hany, Ahmed},
title = {Production-Grade Arabic Multi-Dialect ASR via QLoRA Fine-Tuning of Whisper},
year = {2026},
url = {https://github.com/dev-ahmedhany/whisper-arabic-dialects},
orcid = {0009-0000-8756-9520}
}
4 commits
Standalone HuggingFace model (no PEFT dependency required). Adapter has been merged into base weights — load directly with transformers. For further fine-tuning prefer the LoRA adapter.
Held-out test sets, n=100 per dialect, beam=1, deterministic Arabic normalizer (src/normalization.py).
Zero-shot baseline is the unmodified openai/whisper-large-v3-turbo (CT2 int8 / CPU). Fine-tuned numbers
are this model evaluated as PEFT bf16 on a single L4 GPU (apples-to-apples with training precision).
| Dialect | Test source | Zero-shot WER | Fine-tuned WER | Δ |
|---|---|---|---|---|
| MSA | FLEURS Arabic | 10.4% | 11.5% | +1.1 pp |
| Egyptian | Casablanca | 65.0% | 62.7% | −2.3 pp ✅ |
| Gulf | Casablanca | 61.1% | 58.6% | −2.5 pp ✅ |
| avg (3 dialects) | 45.5% | 44.3% | −1.2 pp |
The val WER during training reaches 33.10% on a held-out slice of the training-source distribution.
openai/whisper-large-v3-turbo (this model regresses ~1 pp on FLEURS MSA)openai/whisper-large-v3-turbon=907 (dialect-balanced val mix, no Maghrebi)
| step | val WER | val loss |
|---|---|---|
| 500 | 36.47% | 0.561 |
| 1000 | 36.67% | 0.529 |
| 1500 | 37.83% | 0.518 |
| 2000 | 33.30% | 0.507 |
| 2500 | 33.29% | 0.503 |
| 3000 ← best (loaded as final) | 33.10% | 0.500 |
| Dialect | Source |
|---|---|
| MSA | Common Voice 18 (MohamedRashad/common-voice-18-arabic) |
| Egyptian | MGB-3 (broadcast TV) |
| Levantine | MASC (broadcast TV) |
| Gulf | (held-out evaluation only) |
Maghrebi excluded — Whisper has insufficient Moroccan/Algerian Arabic in pretraining (84.7% zero-shot WER at large-v3 int8) for QLoRA to bring it within range of other dialects in this pipeline.
from transformers import WhisperForConditionalGeneration, WhisperProcessor
import torch
model = WhisperForConditionalGeneration.from_pretrained(
"dev-ahmedhany/whisper-large-v3-turbo-arabic-ft", torch_dtype=torch.bfloat16
)
processor = WhisperProcessor.from_pretrained("dev-ahmedhany/whisper-large-v3-turbo-arabic-ft", language="arabic", task="transcribe")
# inputs = processor(audio, sampling_rate=16000, return_tensors="pt")
# ids = model.generate(input_features=inputs.input_features, language="arabic", task="transcribe")
# text = processor.batch_decode(ids, skip_special_tokens=True)
@misc{hany2026whisper-arabic-dialects,
author = {Hany, Ahmed},
title = {Production-Grade Arabic Multi-Dialect ASR via QLoRA Fine-Tuning of Whisper},
year = {2026},
url = {https://github.com/dev-ahmedhany/whisper-arabic-dialects},
orcid = {0009-0000-8756-9520}
}
4 commits