CoolFace
Modelpublic

NAMAA-Space/NAMAA-Saudi-ASR-V1

sourceHugging Faceapache-2.0updated 6d agoView on Hugging Face
2likes46downloads
Model Card

๐ŸŽ™๏ธ NAMAA Saudi-Dialect ASR V1

A Saudi Arabic Speech Recognition Model for Arabic & Saudi Transcribe.

<p align="center"> <img src="https://cdn-uploads.huggingface.co/production/uploads/628f7a71dd993507cfcbe587/irk5eBewCXEphFwNvuoNB.png" alt="NAMAA Saudi-Dialect ASR V1" width="500"> </p>

This is a lightweight LoRA adapter fine-tuned on approximately 30 hours of human-transcribed Saudi Podcast Speech.

On the reported Saudi Evaluation Set, the model acheives:

26.50% WER and 15.28% CER with a produced 22.5M trainable parameters Approximately of nearly 90 MB of adapter weights, used with the 2.07B-parameter base model.


At a glance

PropertyDetails
TaskAutomatic speech recognition
LanguageArabic โ€” Saudi dialectal speech
Base modelCohere Transcribe Arabic
AdaptationLoRA
Training speechApproximately 30 hours across 2,400 source segments
Trainable parameters22.5M โ€” approximately 1.1% of the base parameter count
Adapter downloadApproximately 90 MB / 86 MiB
Audio inputMono, 16 kHz
OutputArabic transcription
Evaluated domainSaudi podcasts and interviews

The adapter file size is not the total inference memory requirement: the base model must also be loaded.

Evaluation

All systems were evaluated on the same 826 held-out segments containing approximately 10.8 hours of Saudi podcast speech.

Evaluation used human reference transcripts and identical Arabic orthographic normalization:

  • โ€”Diacritic removal.
  • โ€”Hamza, alef, and ta marbuta normalization.
  • โ€”Punctuation removal.

Lower WER and CER are better. These results describe performance on this evaluation set, rather than a general ranking across Arabic ASR tasks.

ModelBase parametersWER โ†“CER โ†“
Saudi-Dialect ASR โ€” this adapter2.07B + LoRA26.50%15.28%
Cohere Transcribe Arabic2.07B29.12%16.32%
Whisper large-v31.55B37.99%21.29%
Whisper large-v3-turbo0.81B38.30%21.14%
Nemotron 3.5 ASR streaming0.64B50.29%29.92%
ArTST v30.15B53.96%33.22%

What changed relative to the base?

MeasureBaseSaudi adapterChange
WER29.12%26.50%โˆ’2.62 percentage points
CER16.32%15.28%โˆ’1.04 percentage points
Substitutions15,12613,562โˆ’1,564
Insertions5,5054,401โˆ’1,104
Deletions2,9383,487+549

The adapter produces fewer substitutions and insertions, but more deletions. Overall WER improves despite this trade-off.

Segment-level analysis

  • โ€”536 of 826 segments showed lower WER than the base model.
  • โ€”The reported 95% bootstrap confidence interval for the mean per-segment WER difference was [โˆ’3.00, โˆ’2.29] percentage points.
  • โ€”Negative differences favor the Saudi adapter.

This confidence interval concerns the mean per-segment difference. It should not be interpreted as a confidence interval for the corpus-level WER reduction, which weights segments by reference length.


Quick start

Install the dependencies:

bash
pip install torch transformers peft accelerate soundfile scipy

The following example is for a regular Python environment with CPU or dedicated GPU access.

python
import math
import os

import numpy as np
import soundfile as sf
import torch
from peft import PeftModel
from scipy.signal import resample_poly
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor


BASE = "CohereLabs/cohere-transcribe-arabic-07-2026"
ADAPTER = "NAMAA-Space/NAMAA-Saudi-ASR-V1"
TOKEN = os.environ.get("HF_TOKEN", "").strip()

if not TOKEN:
    raise RuntimeError(
        "Set HF_TOKEN with read access to the private adapter."
    )

device = "cuda" if torch.cuda.is_available() else "cpu"
dtype = (
    torch.bfloat16
    if device == "cuda" and torch.cuda.is_bf16_supported()
    else torch.float32
)

processor = AutoProcessor.from_pretrained(
    BASE,
    token=TOKEN,
    trust_remote_code=True,
)

# Load and merge on CPU before moving to the inference device.
with torch.device("cpu"):
    model = AutoModelForSpeechSeq2Seq.from_pretrained(
        BASE,
        token=TOKEN,
        trust_remote_code=True,
        dtype=dtype,
    )

    model = PeftModel.from_pretrained(
        model,
        ADAPTER,
        token=TOKEN,
        torch_device="cpu",
    ).merge_and_unload()

model = model.to(device).eval()

# Replace this with your audio file.
audio, sample_rate = sf.read(
    "sample.wav",
    dtype="float32",
    always_2d=True,
)

audio = audio.mean(axis=1)

if audio.size == 0:
    raise ValueError("The audio file is empty.")

if not np.isfinite(audio).all():
    raise ValueError("The audio contains invalid sample values.")

if sample_rate != 16000:
    divisor = math.gcd(sample_rate, 16000)
    audio = resample_poly(
        audio,
        up=16000 // divisor,
        down=sample_rate // divisor,
    ).astype(np.float32)

inputs = processor(
    audio=audio,
    sampling_rate=16000,
    return_tensors="pt",
)

chunk_index = inputs.pop("audio_chunk_index", None)

prepared = {}
for key, value in inputs.items():
    if torch.is_tensor(value):
        if value.is_floating_point():
            value = value.to(device=device, dtype=dtype)
        else:
            value = value.to(device)
    prepared[key] = value

with torch.inference_mode():
    outputs = model.generate(
        **prepared,
        max_new_tokens=440,
    )

parts = [
    text.strip()
    for text in processor.batch_decode(
        outputs,
        skip_special_tokens=True,
    )
]

if chunk_index is not None:
    if torch.is_tensor(chunk_index):
        chunk_index = chunk_index.detach().cpu().tolist()

    if len(chunk_index) == len(parts):
        order = sorted(
            range(len(parts)),
            key=lambda index: chunk_index[index],
        )
        parts = [parts[index] for index in order]

transcript = " ".join(part for part in parts if part)
print(transcript)

Long recordings

The processor used in this project splits recordings longer than approximately 35 seconds into windows.

Decode every output row. Using only the first decoded result silently discards subsequent windows.

The example concatenates window transcriptions in order. It does not provide timestamps or explicit overlap reconciliation; inspect window boundaries for repetitions or omissions when processing long recordings.


Training

SettingValue
Base architectureFastConformer encoder + transformer decoder
Base parameters2.07B, frozen during adaptation
LoRA rank32
LoRA alpha64
Target modulesq_proj, k_proj, v_proj, o_proj, fc1, fc2
Trainable parametersApproximately 22.5M
Source training segments2,400 โ€” approximately 30 hours
Audio sample rate16 kHz
Epochs3
Reported optimizer steps867
Effective batch size16
Learning-rate scheduleOneCycle, peak learning rate 1e-4
Precisionbfloat16
Checkpoint selectionWER measured from generated transcriptions

Source segments were divided into training windows. The source-segment count therefore differs from the number of chunked training examples.

Training insight: transcript boundaries matter

The source segments average approximately 45 seconds, exceeding the encoder's approximately 35-second training window.

In the reported diagnostic comparison, teacher-forcing cross-entropy increased from 0.71 to 3.18 outside that window. Chunking was therefore important, but the human transcripts did not include timestamps.

Why proportional splitting failed

An initial approach divided each transcript across audio windows in proportion to their duration.

This assumes a roughly uniform speaking rate. Pauses, fast speech, and uneven sentence lengths violate that assumption and can assign words to the wrong audio window.

The resulting model showed:

  • โ€”A 39% reduction in validation cross-entropy.
  • โ€”A 7-percentage-point increase in WER.
  • โ€”Generated text length falling to 88% of the reference length.

Lower teacher-forcing loss did not translate into better transcriptions.

The alignment-based approach

The improved workflow used ASR-assisted transcript alignment:

  1. 1.Transcribe each audio window with the base model.
  2. 2.Align the predicted word sequences with the human transcript.
  3. 3.Use those alignments to locate transcript boundaries.
  4. 4.Train on the corresponding portions of the human transcript.

This uses model predictions to estimate boundaries while retaining human-written text as the training target.

Teacher-forcing cross-entropy in the target-quality comparison decreased from 0.802 with proportional splitting to 0.530 with alignment-based splitting.

Practical lesson: evaluate generated transcriptions during training. Cross-entropy alone can favor a model that omits speech.

Intended use

The adapter is intended for experimentation and transcription workflows involving Saudi Arabic speech, particularly podcasts and interviews.

Review generated transcripts before using them in publications, datasets, or other settings where transcription accuracy matters.

Limitations

  • โ€”Domain coverage: training and evaluation focus on podcasts and interviews. Performance on broadcast news, call centers, read speech, and other domains has not been established.
  • โ€”Long-audio boundaries: concatenating independently decoded windows can require additional boundary handling.

Citation

bibtex
@misc{nacar2026namaasaudiasr,
  author       = {Nacar, Omer},
  title        = {{NAMAA Saudi-Dialect ASR V1}},
  year         = {2026},
  howpublished = {Hugging Face model repository},
  url          = {https://huggingface.co/NAMAA-Space/NAMAA-Saudi-ASR-V1}
}