Downloads · 30 days
58
7% of all-time downloads
rakansuliman/tadabur-whisper-medium
tadabur-whisper-medium is a machine learning model from rakansuliman. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as cc-by-nc-4.0.
Fine-tuned Whisper Medium on the Tadabur dataset for Quran ASR, Surah/Ayah identification, and reciter recognition.
Downloads · 30 days
58
7% of all-time downloads
All-time downloads
854
Public
Parameters
764M
6.1 GB on disk
Likes
2
Public
Click a slice to open those files.
.safetensors3.1 GB · 100%
From the Hugging Face model README
Fine-tuned Whisper Medium on the Tadabur dataset for Quran ASR, Surah/Ayah identification, and reciter recognition.
CS465 Machine Learning Project — Spring 2026
v2 (current). Trained on the full corpus — 1,105 hours, 339,473 clips —
with reciter- and surah-disjoint evaluation. v1 was trained on a single
9,432-sample shard and evaluated on a split from that same shard; it remains
available at revision v1-single-shard.
Given a Quran audio recitation, the pipeline returns:
WER and CER use undiacritized normalization (tashkeel stripped,
alef/ya/ta-marbuta unified, punctuation dropped). The training target was
text_ar_simple. Diacritized WER would be considerably higher.
| Evaluation split | Clips | Audio | WER | CER |
|---|---|---|---|---|
| Unseen reciters and unseen surahs | 231 | 0.6 h | 4.73% | 1.80% |
| Unseen surahs (seen reciters) | 10,509 | 34.4 h | 4.46% | 1.86% |
| Unseen reciters (seen surahs) | 8,142 | 25.8 h | 0.67% | 0.40% |
| In-distribution | 3,459 | 11.2 h | 0.33% | 0.17% |
The first two rows describe real accuracy. The Quran is a closed corpus of 6,236 ayahs, so a random split puts the same text on both sides and the decoder's language prior does much of the work — which is what produces 0.33% and 0.67%. On text the model has never transcribed, error settles near 4.5%.
Unseen voices cost far less than unseen text (0.67% vs 4.46%). Whisper's encoder was pretrained on ~680k hours of varied speech, so ten unfamiliar reciters barely register; corpus familiarity in the decoder is the larger effect.
Vanilla openai/whisper-medium evaluated on the same splits (1,500 clips per
split, identical normalization):
| Split | Vanilla Whisper Medium | Tadabur v2 | Relative reduction |
|---|---|---|---|
| In-distribution | 11.78% | 0.33% | 97% |
| Unseen surahs | 11.40% | 4.46% | 61% |
| Unseen reciters | 18.09% | 0.67% | 96% |
| Unseen reciters + surahs | 24.22% | 4.73% | 80% |
Note that vanilla does worse on held-out reciters (18.09%) than on held-out surahs (11.40%) — the reverse of the fine-tuned ordering. The held-out reciters are therefore genuinely harder audio, not easier. That makes v2's 0.67% on that split direct evidence for the language-prior reading above: the advantage comes from knowing the text, not from favourable acoustics.
Vanilla's un-normalized WER is 31.99%, against 11.78% normalized — it emits different orthography and diacritics, so normalized figures are the fair comparison for both models.
Tadabur-Whisper-Small (Alherran, released with the dataset) evaluated on the same splits:
| Model | Params | test_seen | test_surah | test_reciter | Both held out |
|---|---|---|---|---|---|
| Vanilla Whisper Medium | 769M | 11.78% | 11.40% | 18.09% | 24.22% |
| Tadabur-Whisper-Small † | 244M | 2.02% | 2.15% | 12.43% | 12.60% |
| This model (v2) | 769M | 0.33% | 4.46% * | 0.67% | 4.73% * |
† Trained on the full Tadabur corpus. These splits are held out from this model's training, not from his — so surahs 12/32/48/67/86 and the ten held-out reciters are likely in-distribution for Tadabur-Whisper-Small. Its figures are therefore not held-out results. * Held out from this model's training only.
Read this table carefully rather than as a ranking. On test_surah the
small model scores better (2.15% vs 4.46%) — but that is a seen-text number
against an unseen-text number, which is not a like-for-like comparison. The
only row where both models face the same condition is test_seen, where both
have seen the data during training: 0.33% versus 2.02%.
One detail resists a clean explanation: if Tadabur-Whisper-Small trained on
everything, its fall to 12.43% on test_reciter is steep. That mirrors the
vanilla baseline's pattern (18.09% there against 11.78% on test_seen), so
those reciters are genuinely harder audio — but it leaves open whether they
were in its training data. Its model card does not state a split, so this is
unresolved.
Settling it properly would need either Alherran's split definition or an evaluation set neither model trained on.
v1 reported 6.26% WER against a 41.10% vanilla baseline and 47.06% for Tadabur-Whisper-Small (Alherran's model, released with the dataset). Those came from v1's 500-clip same-distribution split and are not comparable to the table above.
A fair worry for a fixed corpus: a decoder could emit canonical ayahs from weak acoustic evidence and score well without listening. Tested by truncating audio to 50% and measuring how many reference words still appear.
| Condition | Coverage, full audio | Coverage, half audio | Retained |
|---|---|---|---|
| Text seen in training | 99.6% | 58.3% | 58.5% |
| Text never seen | 95.2% | 53.1% | 55.8% |
Half the audio costs half the words, by nearly the same margin either way. A model reciting from memory would have stayed near 99% on familiar text. No memorization signal — the seen/unseen gap is a language prior, not retrieval.
| Metric | Held-out surahs | Random split |
|---|---|---|
| Top-1, clip-weighted (micro) | 91.84% | 96.10% |
| Top-1, class-weighted (macro) | 85.97% | — |
| Top-5, micro | 97.91% | 99.42% |
| Top-5, macro | 95.96% | — |
The held-out-surah column is the one to trust. A random split lets the same reciter's reading of the same surah fall on both sides, leaking recording-session characteristics — microphone, room, mastering. v1's 98.47% was measured under that weaker protocol.
Accuracy depends heavily on how much audio a reciter contributes:
| Training clips | Reciters | Mean top-1 |
|---|---|---|
| Under 100 | 36 | 64.9% |
| 100–400 | 118 | 81.5% |
| Over 400 | 150 | 94.5% |
For reciters in the sparse tail, prefer top-5 or a confidence threshold.
| File | Size | Description |
|---|---|---|
model.safetensors | 3.06 GB | Fine-tuned Whisper Medium weights |
reciter_classifier.pt | 2.76 MB | MLP reciter classifier (retrained on the v2 encoder) |
reciter_idx_to_id.json | 1.25 KB | Classifier index → reciter ID |
reciter_id_to_idx.json | 1.25 KB | Reciter ID → classifier index |
sheikh_dict.json | 2.7 KB | Reciter Arabic name → ID |
surah_dict.json | 2.7 KB | Surah index → Arabic name |
quran_simple.json | ~3 MB | Full Quran text for ayah matching |
supported_reciters.txt | — | All 335 supported reciters |
eval/ | — | Raw evaluation output backing every number above |
pip install transformers torch librosa rapidfuzz huggingface_hub
from transformers import WhisperProcessor, WhisperForConditionalGeneration
import librosa, torch
MODEL = "rakansuliman/tadabur-whisper-medium"
processor = WhisperProcessor.from_pretrained(MODEL)
model = WhisperForConditionalGeneration.from_pretrained(MODEL)
model.eval()
audio, _ = librosa.load("recitation.wav", sr=16000)
inputs = processor(audio, sampling_rate=16000, return_tensors="pt").input_features
with torch.no_grad():
ids = model.generate(
inputs,
language="arabic",
task="transcribe",
max_new_tokens=225,
suppress_tokens=[],
forced_decoder_ids=None,
)
text = processor.batch_decode(ids, skip_special_tokens=True)[0]
print(text)
Audio must be 16 kHz mono. Whisper's window is a fixed 30 seconds — segment longer recordings before transcribing.
v2 changes how embeddings are pooled. The classifier was retrained with pooling masked to frames that actually contain audio. Whisper pads every clip to 30 s, and with a median clip near 13 s the old unmasked
.mean(dim=1)averaged mostly silence. Code written for v1 will still run against v2 weights but will lose accuracy.
from huggingface_hub import hf_hub_download
import torch, torch.nn as nn, json
MODEL = "rakansuliman/tadabur-whisper-medium"
hf_hub_download(MODEL, "reciter_classifier.pt", local_dir="./")
hf_hub_download(MODEL, "reciter_idx_to_id.json", local_dir="./")
hf_hub_download(MODEL, "sheikh_dict.json", local_dir="./")
class ReciterClassifier(nn.Module):
def __init__(self, hidden_dim, num_classes):
super().__init__()
self.net = nn.Sequential(
nn.Linear(hidden_dim, 512), nn.BatchNorm1d(512), nn.ReLU(), nn.Dropout(0.3),
nn.Linear(512, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(0.2),
nn.Linear(256, num_classes),
)
def forward(self, x): return self.net(x)
with open("reciter_idx_to_id.json") as f:
idx_to_id = {int(k): int(v) for k, v in json.load(f).items()}
with open("sheikh_dict.json", encoding="utf-8-sig") as f:
sheikh = {int(v): k for k, v in json.load(f).items()} # name→id, inverted
clf = ReciterClassifier(1024, len(idx_to_id))
clf.load_state_dict(torch.load("reciter_classifier.pt", map_location="cpu"))
clf.eval()
with torch.no_grad():
hidden = model.model.encoder(inputs).last_hidden_state # (1, 1500, 1024)
# mask to real audio: each encoder frame covers 20 ms
n_frames = min(1500, max(1, int(len(audio) / 16000 / 0.02)))
embedding = hidden[:, :n_frames].mean(dim=1).float()
logits = clf(embedding)
pred_idx = logits.argmax(dim=1).item()
confidence = torch.softmax(logits, dim=1).max().item()
reciter_id = idx_to_id[pred_idx]
reciter_name = sheikh.get(reciter_id, f"ID {reciter_id}")
print(f"Reciter: {reciter_name} ({confidence*100:.1f}%)")
from rapidfuzz import process, fuzz
hf_hub_download(MODEL, "quran_simple.json", local_dir="./")
hf_hub_download(MODEL, "surah_dict.json", local_dir="./")
with open("quran_simple.json", encoding="utf-8") as f:
quran = json.load(f) # all 6,236 ayahs
with open("surah_dict.json", encoding="utf-8-sig") as f:
surah_names = json.load(f)
match, score, _ = process.extractOne(text, quran, scorer=fuzz.token_sort_ratio)
print(f"Matched ayah: {match} (confidence {score:.0f}%)")
Match quality follows transcription quality, so expect it to be weakest exactly where WER is highest — on unfamiliar recitations.
Audio Input (mic / file / video)
↓
Whisper Encoder ←─ runs once, shared
├── Whisper Decoder → Arabic text
└── MLP Classifier → Reciter name
↓
RapidFuzz matching against 6,236 ayahs
↓
Surah name + Ayah number + confidence
Linear(1024→512) → BatchNorm → ReLU → Dropout(0.3)
→ Linear(512→256) → BatchNorm → ReLU → Dropout(0.2)
→ Linear(256→335)
openai/whisper-medium — started fresh, not continued from v1From the 938 GB source: decoded, resampled to 16 kHz mono, re-encoded FLAC; dropped clips over 30 s (Whisper's window) and under 0.5 s, and transcripts over 440 tokens (decoder limit 448). 361,583 of ~385k clips survive — 1,105 h of the corpus's 1,400 h, since the dropped clips were the longest ones.
| Split | Construction | Clips |
|---|---|---|
train | remainder | 339,473 |
test_surah | surahs 12, 32, 48, 67, 86 held out entirely | 10,509 |
test_reciter | reciters 15, 19, 97, 119, 412, 423, 481, 586, 617, 649 held out entirely | 8,142 |
test_seen | 1% random holdout | 3,459 |
Held-out reciters were drawn from the mid-frequency band — enough audio for a meaningful test set without removing a major contributor from training.
See supported_reciters.txt for all 335, including:
عبد الباسط عبد الصمد، محمد صديق المنشاوي، ياسر الدوسري، سعود الشريم، ماهر المعيقلي، عبدالرحمن السديس، and 329 more.
| Revision | ASR training data | Headline WER |
|---|---|---|
main (v2) | 339,473 clips / 1,105 h | 4.46% (unseen surahs) |
v1-single-shard | 9,432 clips / 1 shard | 6.26% (same-distribution split) |
@misc{suliman2026tadabur,
author = {Suliman, Rakan and Mamdoh, Abdulrahman and Aldosari, Hussam and Khalid, Mohammed},
title = {Tadabur: Quran ASR with Surah/Ayah Identification and Reciter Recognition},
year = {2026},
url = {https://huggingface.co/rakansuliman/tadabur-whisper-medium}
}
Please also cite the dataset this model was trained on:
@misc{alherran2026tadabur,
author = {Alherran, Faisal},
title = {Tadabur: A Large-Scale Quran Audio Dataset},
year = {2026},
eprint = {2604.18932},
archivePrefix = {arXiv},
primaryClass = {cs.SD},
doi = {10.48550/arXiv.2604.18932},
url = {https://arxiv.org/abs/2604.18932}
}
CC BY-NC 4.0 — Research and educational use only. Please engage with Quran content respectfully. 🤲