Nemotron ASR Streaming: Persian (Farsi), podcast / conversational
A streaming speech-recognition model for conversational Persian. It continues fine-tuning mehdi-hf/nemotron-asr-streaming-farsi on 365 hours of Persian podcast speech from bplus_podcast_persian and Tabaghe16_dataset_persian.
- Better on podcast speech: 12.3% WER on held-out podcast episodes, against 16.4% for the base model. That's 25% fewer errors.
- Writes the way people speak: it learned the datasets' colloquial transcription style (
رو,هستن,میخوایم). That's what you want for podcasts and conversation. On formal read-speech benchmarks it scores worse than the base model (see Results). - Same architecture and interface as the base model: 600M-parameter cache-aware FastConformer + RNN-T, the 1,024-piece Persian tokenizer and the
fa-IRprompt. It runs live chunk by chunk or on whole files, with 1.12 s or 0.32 s look-ahead.
Which model to use: for podcasts, interviews and casual conversation, use this one. For formal or read speech (news, audiobooks, written-style transcripts), use the base model.
Results
WER / CER in %, lower is better. Both models were evaluated the same way in the same run: true chunk-by-chunk streaming with NeMo's cache-aware streaming script, the fa-IR prompt fixed, greedy decoding. Scoring uses the base model's normalizer: ZWNJ read as a space, punctuation removed, Arabic letter forms folded, numbers spelled out. As a check of the setup, the base model's FLEURS and Common Voice numbers below match its own published card (8.81 / 19.12).
1.12 s look-ahead (most accurate)
| Test set | Clips | Base model | This model | Change |
|---|---|---|---|---|
| Podcast held-out test (all) | 4,182 | 16.44 / 8.69 | 12.31 / 5.97 | −4.13 WER |
| ↳ bplus episodes | 2,340 | 5.63 / 2.20 | 4.81 / 1.70 | −0.82 |
| ↳ Tabaghe16 episodes | 1,842 | 22.85 / 12.58 | 16.76 / 8.53 | −6.09 |
| FLEURS fa test (formal read speech) | 852 | 8.82 / 2.94 | 12.91 / 4.81 | +4.09 |
| Common Voice 22 fa test (read sentences) | 10,661 | 19.12 / 5.80 | 22.01 / 7.64 | +2.89 |
0.32 s look-ahead (lower latency)
| Test set | Clips | Base model | This model |
|---|---|---|---|
| Podcast held-out test (all) | 4,182 | 18.08 / 9.84 | 13.54 / 6.78 |
| ↳ bplus episodes | 2,340 | 7.49 / 3.44 | 6.30 / 2.66 |
| ↳ Tabaghe16 episodes | 1,842 | 24.37 / 13.67 | 17.83 / 9.25 |
| FLEURS fa test | 852 | 9.01 / 3.03 | 12.98 / 4.56 |
| Common Voice 22 fa test | 10,661 | 19.93 / 6.08 | 21.97 / 7.20 |
Raw results: eval_results/.
Why FLEURS and Common Voice get worse
Most of the extra errors on FLEURS are register: the speech is heard correctly but written in the colloquial form this model was trained on, while the FLEURS references use formal written Persian. These were the most frequent new substitutions on FLEURS (reference → this model):
| Formal (reference) | Colloquial (this model) | Count |
|---|---|---|
| را | رو | 42 |
| هستند | هستن | 35 |
| کردند | کردن | 29 |
| دارند | دارن | 29 |
| باشند | باشن | 28 |
| کنند | کنن | 27 |
| است | هست | 15 |
Not all of the change is style. A smaller number of utterances show real regressions compared with the base model, for example dropped sentence endings on long, formal sentences and an occasional repetition loop.
How to use
Use it exactly like the base model, with this repo's .nemo file. See the base model card for the full streaming example.
from huggingface_hub import hf_hub_download
from nemo.collections.asr.models import ASRModel
path = hf_hub_download("MohammadGholizadeh/nemotron-asr-streaming-farsi-podcast",
"nemotron-asr-streaming-farsi-podcast.nemo")
model = ASRModel.restore_from(path).eval()
model.encoder.set_default_att_context_size([56, 13]) # 1.12 s look-ahead; [56, 3] for 0.32 s
model.set_inference_prompt("fa-IR") # required
Command-line streaming over a NeMo manifest:
git clone --depth 1 --branch v3.0.0 https://github.com/NVIDIA-NeMo/Speech.git nemo-speech
python nemo-speech/examples/asr/asr_cache_aware_streaming/speech_to_text_cache_aware_streaming_infer.py \
model_path=nemotron-asr-streaming-farsi-podcast.nemo dataset_manifest=manifest.json output_path=out/ \
target_lang=fa-IR att_context_size=[56,13] compute_dtype=float32 batch_size=32
Set the
fa-IRprompt. As with the base model, don't use NeMo 3.0'smodel.transcribe()orspeech_to_text_eval.pyunmodified. They pick the language prompt at random per utterance. Useset_inference_prompt("fa-IR")in streaming, or the streaming script withtarget_lang=fa-IR.
This repo has the NeMo checkpoint only. It doesn't include 🤗 Transformers weights.
What the model outputs
- Colloquial Persian script, no punctuation, standard ZWNJ spelling (
میخوایم,کتابها) - Numbers as spoken words
- No Latin letters. Training clips whose transcript contained Latin script were removed.
Training
| Initialized from | mehdi-hf/nemotron-asr-streaming-farsi (.nemo). Tokenizer, decoder, joint and all other weights kept. No layers re-initialized |
| Data | 338,529 clips / 365.3 h at 16 kHz (see below) |
| Language prompt | fa-IR, prompt_mode=langID (as in the base model) |
| Schedule | 5,000 steps (about 5 passes over the data), AdamW, LR 3e-5 cosine to 1e-6, 200 warmup steps |
| Batching | Lhotse duration bucketing (25 buckets), the base model's OOMptimizer batch sizes (42–894 clips per batch), clips ≤ 20 s |
| Hardware | 1× NVIDIA GH200 (96 GB), 2 h 46 min, NeMo Speech 3.0.0, PyTorch 2.13 |
| Checkpoint | final step. Dev WER (NeMo's in-training scoring, unnormalized) fell from 14.4% at step 500 to 13.5% at step 5,000 |
Scripts are in training/: data preparation, the training command, and evaluation. The recipe follows train_nemotron.sh from the base model's repo, with the changes listed above.
Data
| Dataset | Train clips | Train hours | Dev (clips / h) | Test (clips / h) |
|---|---|---|---|---|
MohammadGholizadeh/bplus_podcast_persian |
189,436 | 139.3 | 2,134 / 1.5 | 2,340 / 1.7 |
MohammadGholizadeh/Tabaghe16_dataset_persian |
149,093 | 226.0 | 2,008 / 3.3 | 1,842 / 3.0 |
| Total | 338,529 | 365.3 | 4,142 / 4.8 | 4,182 / 4.8 |
Preparation (training/prep_hf_datasets.py):
- Text: transcripts were normalized with the base model's training normalizer (
to_training_text), the same form the base model was trained on. - Filters: the base model's rules were applied. 5,925 clips containing Latin script were dropped, plus 360 for length, speaking rate or letter ratio. 346,853 of 353,138 clips were kept. No CER/label-quality filtering was done.
- Held-out split: whole episodes/videos were held out per dataset, about 1% of audio each for dev and test.
The models were never trained on FLEURS or Common Voice.
Limitations
- Formal / read speech: worse than the base model (FLEURS 12.9% vs 8.8%), mainly because it writes colloquial forms. Use the base model if you need formal written-style transcripts.
- Small, episode-level held-out set: the podcast test set covers 5 episodes (3 bplus, 2 Tabaghe16), and is split by episode, not by speaker. Recurring hosts appear in both training and test. The podcast numbers therefore measure new episodes of the same shows. On unseen speakers and other shows, expect a smaller gain.
- Regressions: occasional dropped sentence endings and repetition loops appear on long formal sentences that the base model handled well.
- Labels: the training labels were used as provided and weren't verified by listening.
- Inherited from the base model: Persian only, no Latin script, numbers as words, not evaluated on dialects.
License
This model is a derivative of nvidia/nemotron-3.5-asr-streaming-0.6b (via mehdi-hf/nemotron-asr-streaming-farsi) and is distributed under the OpenMDW License Agreement, version 1.1, the base model's license. A copy is in LICENSE. See NOTICE for attributions.
Acknowledgements
- Base model:
mehdi-hf/nemotron-asr-streaming-farsiand its code (text normalization, recipe, evaluation), built on NVIDIA'snemotron-3.5-asr-streaming-0.6b. - Training and evaluation: NVIDIA NeMo Speech 3.0.0.