Hadra-TTS-f5
The collective's speech synthesiser for Algerian Darja: a fine-tune of
IbrahimSalah/Arabic-F5-TTS-v2 (a Flow-Matching Diffusion Transformer, DiT
dim 1024 / depth 22 / heads 18) on three OddAdmix Algerian speech collections
— 69,066 filtered utterances (~399 hours) spanning Kahwa conversational
podcasts, Loubna expressive stories, and Rawi folklore narratives.
No speech-quality evaluation has been measured for this model — no MOS, no intelligibility score, no speaker-similarity number — so Results names the gap instead of a headline. An interactive demo is linked under Usage; demo audio is illustrative, not a measurement.
Results
No evaluation has been measured. There is no held-out TTS test set, no reference-audio protocol, and no baseline scored in the same harness — nothing to table, and no headline number is claimed. The 0.4950 figure in Training recipe is a batch training loss, not an evaluation score.
Anchor harnesses. The collective's default reference suites are DziriEval
and MADAR. Both are text suites and do not cover speech synthesis, so no anchor
score applies to this model — unmeasured with that reason, not by omission.
The ASR-side counterparts (algerian-nlp/Hadra-ASR-whisper-medium,
algerian-nlp/Hadra-ASR-whisper-small) are separate models with their own
cards; their WERs are recognition scores, not synthesis scores, and are not
carried here.
Intended use
Speech synthesis from Algerian Darja text: narration, storytelling, dubbing, voice-assistant output, and accessibility reading. A starting point for fine-tuning other Algerian Arabic voice tasks.
Not suitable for: speech recognition or any transcription task; translation between languages; any language or dialect other than Algerian Darija; cloning a real person's voice without their consent; any decision about a person. The training audio comes from a small speaker set (see Limitations), so outputs may resemble those voices. Heavy French code-switching renders best with Latin-script French words; full Arabic transliteration of French may degrade quality. It has not been evaluated for bias, toxicity, or factuality.
Usage
f5-tts, huggingface_hub, torch, nothing else. The weights load through
the external f5-tts package — no modelling code ships in this repo, so
trust_remote_code is unnecessary.
Unexecuted snippet (not run against this repo here; output shapes unmeasured). The checkpoint path below is the collective repo id — an earlier revision of this card pointed the download at a personal namespace, which is not the release:
from huggingface_hub import hf_hub_download
import torch
from f5_tts.model import CFM, DiT
from f5_tts.model.utils import get_tokenizer
# Weights from this repo; vocabulary from the base repo (not shipped here).
ckpt_path = hf_hub_download("algerian-nlp/Hadra-TTS-f5", "model_last.pt")
vocab_path = hf_hub_download("IbrahimSalah/Arabic-F5-TTS-v2", "vocab.txt")
vocab_char_map, vocab_size = get_tokenizer(vocab_path, "custom")
model = CFM(
transformer=DiT(
dim=1024, depth=22, heads=18, ff_mult=2,
text_dim=512, text_mask_padding=False,
conv_layers=8, pe_attn_head=1,
text_num_embeds=vocab_size, mel_dim=100,
),
mel_spec_kwargs=dict(
n_fft=1024, hop_length=256, win_length=1024,
n_mel_channels=100, target_sample_rate=24000,
mel_spec_type="vocos",
),
vocab_char_map=vocab_char_map,
)
ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False)
model.load_state_dict(ckpt["ema_model_state_dict"], strict=False)
model.eval()
CLI inference (exact command shape; reference audio and texts are yours):
f5-tts_infer-cli \
--ckpt_file model_last.pt \
--vocab_file vocab.txt \
--ref_audio reference_darja.wav \
--ref_text "واش راك، كلشي مزيان؟" \
--gen_text "النص اللي تبغي تولدو بالدارجة الجزائرية" \
--output_dir ./output
Input-preparation notes the reader will get wrong: resample reference audio to mono 24,000 Hz float32; normalise input text with the Darja pipeline below (the same pipeline used in training) before inference; keep Latin-script French words as Latin — transliterating them into Arabic script was never trained through this path.
import re
_FR_TAG_RE = re.compile(r"\[\s*(?:French|FR)\s*:\s*(.*?)\]", re.IGNORECASE)
_BRACKET_RE = re.compile(r"\[.*?\]|<.*?>|\(.*?\)")
_NOISE_CHARS = re.compile(r"[*#@~_^&%$+=/\\|{}\[\]`\"«»]")
def normalize_darja(text: str) -> str:
text = _FR_TAG_RE.sub(r"\1", text) # expand French tags, keep the words
text = _BRACKET_RE.sub("", text) # strip laugh/bracket markers
text = _NOISE_CHARS.sub("", text) # strip noise characters
text = text.replace("ـ", "") # tatweel elongation
text = text.replace("إ", "ا").replace("أ", "ا").replace("آ", "ا")
text = text.replace("ى", "ي")
return " ".join(text.split()).strip()
Interactive demo (illustrative, not a measurement): f5tts-algerian-darja-demo.streamlit.app.
Architecture
| Base checkpoint | IbrahimSalah/Arabic-F5-TTS-v2 (547,500-step Arabic checkpoint) |
| Transformer | DiT, dim 1024 / depth 22 / heads 18, ff_mult 2, conv_layers 8 |
| Text conditioning | text_dim 512, text_mask_padding False |
| Mel spectrogram | n_fft 1024, hop 256, win 1024, 100 mel channels, vocos, 24,000 Hz |
| Vocabulary | 2,580 Arabic tokens, reused from the base checkpoint (not shipped here) |
| Positions / max length | utterance filter 2.0–12.0 s at training; synthesis chunking unmeasured |
| Objective | Flow-matching TTS fine-tuning, base frozen nowhere — full DiT fine-tuned |
Deviations from the base checkpoint: step and optimiser state were stripped
from model_547500_8_18.pt before fine-tuning to avoid momentum contamination
from pre-training; gradient checkpointing was enabled for T4 VRAM; the
vocabulary is unchanged from the base Arabic checkpoint and stays compatible
with Darja phoneme coverage by assertion, not by measurement.
Training data
Three OddAdmix Algerian speech collections, filtered to 2.0–12.0 s duration and 1.0–25.0 chars/sec density, resampled to 24,000 Hz mono float32 on the fly (streaming, no local disk):
| subset | domain | raw utterances | filtered utterances | duration |
|---|---|---|---|---|
| Kahwa podcast | conversational / spontaneous | 23,264 | 23,264 | ~110h |
| Loubna stories | expressive narratives | 48,590 | 41,301 | ~237h |
| Rawi folklore | cultural oral folklore | 5,296 | 4,501 | ~52h |
| Total | multi-domain | 77,150 | 69,066 | ~399h |
Per-subset retention is 100% / 85.0% / 85.0%; overall 69,066 of 77,150 is 89.5% computed — the "~85%" stated on the original card describes the Loubna and Rawi subsets, not the total. Every row derives from the three named Hub datasets; per-row source id, licence, and retrieval date are unmeasured (the load streamed, no manifest was written). The text normaliser above is unversioned — no name and version is stamped on any artifact. What it preserves that carries meaning: French spans inside tags are unwrapped and kept as code-switch context rather than deleted, and Latin-script French stays Latin.
Decontamination. Unmeasured: no screen of training audio against any held-out TTS test protocol is documented, and no held-out TTS test set exists.
Licence composition of the training audio
The weights are Apache-2.0. That grant does not relicense the audio they were trained on. The composition, so you can make your own judgement:
| tier | rows | share |
|---|---|---|
| other (unresolvable Hub licence on all three OddAdmix sets, as read 2026-09-17 and recorded on the Hadra ASR cards) | 77,150 raw (69,066 filtered) | 100% |
A permissive-only rebuild cannot be cut by code from this information — contact the audio owners before redistributing derivatives.
Training recipe
| Objective | Flow-matching TTS fine-tuning of the full DiT |
| Masking | not applicable (no masking schedule; diffusion/flow-matching) |
| Optimiser | AdamW 8-bit (bitsandbytes), lr peak 2e-5, betas unmeasured, max grad norm 1.0 |
| Batch | 2,000 mel-frames per GPU x 6 accumulation = ~12,000 frames/step |
| Schedule | cosine annealing, 2,000-step warmup |
| Steps | 48,574 across 8 Kaggle sessions (Sep 20–23 2026); frame counts, not token counts, so tokens and epochs are unmeasured |
| Regularisation | gradient checkpointing (checkpoint_activations=True), num_workers=0, periodic gc.collect() + cuda.empty_cache() |
| Precision | FP16 mixed |
| Hardware | 1x NVIDIA Tesla T4 16 GB (Kaggle background multi-session); wall-clock unmeasured |
| Seed | unmeasured |
| Save | every 500 updates; intermediates deleted afterwards (see Files) |
| Monitoring | W&B k_touati-estin/f5tts-algerian-darja |
Final training loss 0.4950 (batch cross-entropy, step 48,574). Training loss
only — no validation curve was published. Each session resumed automatically
from model_last.pt on the Hub; the W&B "crashed" status reflects Kaggle's
~12-hour session limit, not training errors:
| session | run id | date | steps reached | final batch loss | status |
|---|---|---|---|---|---|
| 1 | wxcxx3mi | Sep 20 | 0 | — | setup/env error |
| 2 | ymp61rc4 | Sep 20 | 2 | 1.0581 | setup/env error |
| 3 | cknieh8f | Sep 20 | 969 | 0.4266 | Kaggle time limit |
| 4 | m2zoj7ak | Sep 20 | 0 | — | setup/env error |
| 5 | hniwvpbu | Sep 21 | 13,214 | 0.9916 | Kaggle time limit |
| 6 | gyrlliys | Sep 22 | 26,014 | 1.1612 | Kaggle time limit |
| 7 | zyah6mu2 | Sep 22 | 38,865 | 0.4460 | Kaggle time limit |
| 8 | tk464wii | Sep 23 | 48,574 | 0.4950 | training complete |
What the session log says and what it refuses to say: per-session final losses are single-batch training points at different resumption offsets, not a validation curve — they say training ran to step 48,574; they refuse any convergence or voice-quality claim, and session-to-session values are not comparable with each other.
Limitations
No measured quality number constrains any use. There is no MOS, no intelligibility score, and no speaker-similarity measurement — every quality claim about this model's voice is unreproduced until a held-out listening or reference-audio protocol scores it.
A small speaker set is the whole voice. The OddAdmix collections derive from a small number of speakers; outputs may carry their vocal characteristics, and cloning a real person's voice without consent is out of scope.
Three domains are the whole world. Kahwa podcasts plus Loubna and Rawi storytelling, all OddAdmix — Central/Western registers dominate; Eastern, Saharan, noisy-field, and heavily French-matrix speech are outside the measured envelope, and nothing about training measured them.
Contamination is unbounded, not cleared. With no held-out TTS test set and no train/test partition documented for synthesis, leakage can neither be confirmed nor excluded.
Evaluated never vs unmeasured. Training batch loss on one resume chain (single run, unmeasured seed) vs everything else: no anchor suite, no robustness sweep, no human side-by-side.
No safety evaluation of any kind has been performed.
Files
| file | size | contents |
|---|---|---|
model_last.pt | unmeasured | final weights at step 48,574; SHA-256 unmeasured here — hash the download before quoting |
last-checkpoint/ | unmeasured | Kaggle async sync mirror of model_last.pt |
vocab.txt | not shipped | 2,580-token Arabic vocabulary — fetch from IbrahimSalah/Arabic-F5-TTS-v2 |
Sizes and hashes are unmeasured here — they were not read from a staged
directory, so none are quoted. Deliberately not shipped: intermediate
checkpoints (model_48000.pt, model_48500.pt, removed to reduce repository
size), the optimiser state, the training audio, and the base weights (fetch
the base repo).
Reproduction
Source checkpoint: model_last.pt in this repo at step 48,574 (SHA-256
unmeasured here). Training has no published script — the W&B run and the
session table above are the record, and the base reset stripped step and
optimiser state from model_547500_8_18.pt before fine-tuning began.
Exact inference path (after pip install f5-tts huggingface_hub):
f5-tts_infer-cli \
--ckpt_file model_last.pt \
--vocab_file vocab.txt \
--ref_audio reference_darja.wav \
--ref_text "واش راك، كلشي مزيان؟" \
--gen_text "النص اللي تبغي تولدو بالدارجة الجزائرية" \
--output_dir ./output
Seeding notes: the training seed is unmeasured — reruns will move by an unmeasured amount. If a number cannot be reproduced from this section, it is not a result: that applies to the 0.4950 training loss outside this exact resume chain, and there is no evaluation number to reproduce at all.
Citation
@misc{algerian_nlp_hadra_tts_f5_2026,
title = {Hadra-TTS-f5: Flow-Matching Speech Synthesis for Algerian Arabic (Darja)},
author = {Touati, Kamel and Algerian NLP Collective},
year = {2026},
url = {https://huggingface.co/algerian-nlp/Hadra-TTS-f5},
}
@misc{salah_arabic_f5_tts_v2,
title = {Arabic-F5-TTS-v2},
author = {Salah, Ibrahim},
url = {https://huggingface.co/IbrahimSalah/Arabic-F5-TTS-v2},
note = {Base checkpoint fine-tuned here; publication metadata unmeasured},
}
Licence
Apache-2.0 for the weights and card. Read the licence composition of the training audio above before redistributing derivatives — a permissive grant on the weights makes no claim about the underlying speech.