Instructions to use NAMAA-Space/NAMAA-Saudi-ASR-V1 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use NAMAA-Space/NAMAA-Saudi-ASR-V1 with PEFT:
Task type is invalid.
- Notebooks
- Google Colab
- Kaggle
Configuration Parsing Warning:In adapter_config.json: "peft.task_type" must be a string
ποΈ NAMAA Saudi-Dialect ASR V1
A Saudi Arabic Speech Recognition Model for Arabic & Saudi Transcribe.
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
| Property | Details |
|---|---|
| Task | Automatic speech recognition |
| Language | Arabic β Saudi dialectal speech |
| Base model | Cohere Transcribe Arabic |
| Adaptation | LoRA |
| Training speech | Approximately 30 hours across 2,400 source segments |
| Trainable parameters | 22.5M β approximately 1.1% of the base parameter count |
| Adapter download | Approximately 90 MB / 86 MiB |
| Audio input | Mono, 16 kHz |
| Output | Arabic transcription |
| Evaluated domain | Saudi 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.
| Model | Base parameters | WER β | CER β |
|---|---|---|---|
| Saudi-Dialect ASR β this adapter | 2.07B + LoRA | 26.50% | 15.28% |
| Cohere Transcribe Arabic | 2.07B | 29.12% | 16.32% |
| Whisper large-v3 | 1.55B | 37.99% | 21.29% |
| Whisper large-v3-turbo | 0.81B | 38.30% | 21.14% |
| Nemotron 3.5 ASR streaming | 0.64B | 50.29% | 29.92% |
| ArTST v3 | 0.15B | 53.96% | 33.22% |
What changed relative to the base?
| Measure | Base | Saudi adapter | Change |
|---|---|---|---|
| WER | 29.12% | 26.50% | β2.62 percentage points |
| CER | 16.32% | 15.28% | β1.04 percentage points |
| Substitutions | 15,126 | 13,562 | β1,564 |
| Insertions | 5,505 | 4,401 | β1,104 |
| Deletions | 2,938 | 3,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:
pip install torch transformers peft accelerate soundfile scipy
The following example is for a regular Python environment with CPU or dedicated GPU access.
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
| Setting | Value |
|---|---|
| Base architecture | FastConformer encoder + transformer decoder |
| Base parameters | 2.07B, frozen during adaptation |
| LoRA rank | 32 |
| LoRA alpha | 64 |
| Target modules | q_proj, k_proj, v_proj, o_proj, fc1, fc2 |
| Trainable parameters | Approximately 22.5M |
| Source training segments | 2,400 β approximately 30 hours |
| Audio sample rate | 16 kHz |
| Epochs | 3 |
| Reported optimizer steps | 867 |
| Effective batch size | 16 |
| Learning-rate schedule | OneCycle, peak learning rate 1e-4 |
| Precision | bfloat16 |
| Checkpoint selection | WER 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:
- Transcribe each audio window with the base model.
- Align the predicted word sequences with the human transcript.
- Use those alignments to locate transcript boundaries.
- 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
@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}
}
- Downloads last month
- 11
Model tree for NAMAA-Space/NAMAA-Saudi-ASR-V1
Base model
CohereLabs/cohere-transcribe-03-2026