Instructions to use anwar-dev/Bayan-Arabic-TTS-v1.0 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- NeMo
How to use anwar-dev/Bayan-Arabic-TTS-v1.0 with NeMo:
# tag did not correspond to a valid NeMo domain.
- Notebooks
- Google Colab
- Kaggle
Download compare_models/scripts/evaluate_compare.py from anwar-dev/Bayan-Arabic-TTS-v1.0: direct link, hf CLI and curl.
- Browser
- Download file 6.04 kB
-
https://huggingface.co/anwar-dev/Bayan-Arabic-TTS-v1.0/resolve/main/compare_models/scripts/evaluate_compare.py
- Command line
-
hf download hf://anwar-dev/Bayan-Arabic-TTS-v1.0/compare_models/scripts/evaluate_compare.py
-
curl -L -o evaluate_compare.py https://huggingface.co/anwar-dev/Bayan-Arabic-TTS-v1.0/resolve/main/compare_models/scripts/evaluate_compare.py
6.04 kB
| #!/usr/bin/env python3 | |
| """Evaluate every model folder with Whisper (CER/WER) and TitaNet (speaker similarity). | |
| Folder layout: | |
| <root>/<model>/sample_00.wav ... | |
| Usage: | |
| python evaluate_compare.py --root /path/eval_in \ | |
| --models bayan,magpie,xtts,chatterbox,mms \ | |
| --text-file ../texts.txt --out ../metrics.json --csv ../results.csv \ | |
| --whisper /path/whisper-large-v3 --titanet /path/titanet.nemo \ | |
| --speaker-ref-dir /path/wav22k | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import csv | |
| import json | |
| import re | |
| import unicodedata | |
| from pathlib import Path | |
| import numpy as np | |
| import soundfile as sf | |
| import torch | |
| import torch.nn.functional as F | |
| from faster_whisper import WhisperModel | |
| from jiwer import cer, wer | |
| from nemo.collections.asr.models import EncDecSpeakerLabelModel | |
| DIACRITICS = re.compile(r"[\u0610-\u061a\u064b-\u065f\u0670\u06d6-\u06ed\u0640]") | |
| NUMBER_WORDS = ( | |
| "واحد|واحده|اثنان|اثنين|ثلاثه|اربعه|خمسه|سته|سبعه|ثمانيه|تسعه|عشره|عشر|" | |
| "عشرون|عشرين|ثلاثون|ثلاثين|اربعون|اربعين|خمسون|خمسين|ستون|ستين|" | |
| "سبعون|سبعين|ثمانون|ثمانين|تسعون|تسعين|مايه|مائه|ميه|ميتين|مائتين|مئتين|مائتان|" | |
| "الف|الاف|الفين|الفان|مليون|مليار|مليارات|" | |
| "ثلاثمائه|ثلاثمايه|اربعمائه|اربعمايه|خمسمائه|خمسمايه|ستمائه|ستمايه|" | |
| "سبعمائه|سبعمايه|ثمانمائه|ثمانمايه|تسعمائه|تسعمايه" | |
| ) | |
| UNITS = "كم|كيلومتر|كيلومترات|كيلومترا|متر|مترا|امتار|عام|عاما|اعوام|سنوات|سنه|دوله|دول|شخص|اشخاص" | |
| NUM_RE = re.compile(rf"\bو?(?:{NUMBER_WORDS}|{UNITS}|[0-9]+)\b") | |
| def normalize_ar(text: str) -> str: | |
| text = unicodedata.normalize("NFKC", text) | |
| text = DIACRITICS.sub("", text) | |
| text = ( | |
| text.replace("أ", "ا").replace("إ", "ا").replace("آ", "ا") | |
| .replace("ى", "ي").replace("ة", "ه").replace("ؤ", "و").replace("ئ", "ي") | |
| ) | |
| text = re.sub(r"[^\w\s]", " ", text) | |
| return re.sub(r"\s+", " ", text).strip() | |
| def mask_numbers(text: str) -> str: | |
| out = NUM_RE.sub("NUM", normalize_ar(text)) | |
| out = re.sub(r"(?:NUM\s*)+", "NUM ", out) | |
| return re.sub(r"\s+", " ", out).strip() | |
| def main() -> int: | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--root", required=True) | |
| ap.add_argument("--models", required=True) | |
| ap.add_argument("--text-file", required=True) | |
| ap.add_argument("--out", required=True) | |
| ap.add_argument("--csv", required=True) | |
| ap.add_argument("--whisper", required=True) | |
| ap.add_argument("--titanet", required=True) | |
| ap.add_argument("--speaker-ref-dir", required=True) | |
| ap.add_argument("--ref-stride", type=int, default=50) | |
| ap.add_argument("--ref-count", type=int, default=12) | |
| args = ap.parse_args() | |
| root = Path(args.root) | |
| texts = [ln.strip() for ln in Path(args.text_file).read_text(encoding="utf-8").splitlines() if ln.strip()] | |
| whisper = WhisperModel(args.whisper, device="cpu", compute_type="int8") | |
| sv = EncDecSpeakerLabelModel.restore_from(args.titanet, map_location="cpu").eval() | |
| refs = sorted(Path(args.speaker_ref_dir).glob("*.wav"))[:: args.ref_stride][: args.ref_count] | |
| with torch.no_grad(): | |
| embs = torch.stack([F.normalize(sv.get_embedding(str(p)).reshape(-1), dim=0) for p in refs]) | |
| voice = F.normalize(embs.mean(0), dim=0) | |
| print(f"voice centroid from {len(refs)} clips") | |
| report: dict[str, dict] = {} | |
| for model in [m.strip() for m in args.models.split(",") if m.strip()]: | |
| files = sorted((root / model).glob("sample_*.wav")) | |
| rows = [] | |
| for f, ref in zip(files, texts): | |
| segs, _ = whisper.transcribe(str(f), language="ar", beam_size=5, vad_filter=False, condition_on_previous_text=False) | |
| hyp = " ".join(s.text.strip() for s in segs).strip() | |
| c = float(cer(normalize_ar(ref), normalize_ar(hyp))) | |
| c_norm = float(cer(mask_numbers(ref), mask_numbers(hyp))) | |
| w = float(wer(normalize_ar(ref), normalize_ar(hyp))) | |
| with torch.no_grad(): | |
| e = F.normalize(sv.get_embedding(str(f)).reshape(-1), dim=0) | |
| sim = float(e @ voice) | |
| dur = float(sf.info(str(f)).duration) | |
| rows.append({"file": f.name, "cer": c, "cer_norm": c_norm, "wer": w, | |
| "sim": sim, "duration": dur, "hyp": hyp, "ref": ref}) | |
| print(f"{model}/{f.name} CER={c:.3f} CER*={c_norm:.3f} WER={w:.3f} SIM={sim:.3f}") | |
| report[model] = { | |
| "n": len(rows), | |
| "mean_cer": float(np.mean([r["cer"] for r in rows])), | |
| "mean_cer_norm": float(np.mean([r["cer_norm"] for r in rows])), | |
| "mean_wer": float(np.mean([r["wer"] for r in rows])), | |
| "mean_sim": float(np.mean([r["sim"] for r in rows])), | |
| "total_duration": float(np.sum([r["duration"] for r in rows])), | |
| "samples": rows, | |
| } | |
| Path(args.out).write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8") | |
| with Path(args.csv).open("w", newline="", encoding="utf-8") as fh: | |
| wr = csv.writer(fh) | |
| wr.writerow(["model", "file", "cer", "cer_numeric_normalized", "wer", "sim", "duration", "hypothesis"]) | |
| for model, rep in report.items(): | |
| for r in rep["samples"]: | |
| wr.writerow([model, r["file"], f"{r['cer']:.4f}", f"{r['cer_norm']:.4f}", | |
| f"{r['wer']:.4f}", f"{r['sim']:.4f}", f"{r['duration']:.2f}", r["hyp"]]) | |
| for model, rep in report.items(): | |
| print(f"\n{model}: CER={rep['mean_cer']:.4f} CER*={rep['mean_cer_norm']:.4f} " | |
| f"WER={rep['mean_wer']:.4f} SIM={rep['mean_sim']:.3f} dur={rep['total_duration']:.1f}s") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |