Instructions to use Thareah/Tha-ASR with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Thareah/Tha-ASR with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("automatic-speech-recognition", model="Thareah/Tha-ASR")# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForSpeechSeq2Seq processor = AutoProcessor.from_pretrained("Thareah/Tha-ASR") model = AutoModelForSpeechSeq2Seq.from_pretrained("Thareah/Tha-ASR", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Tha-ASR: Khmer + English speech recognition
Tha-ASR is a Whisper-small model fine-tuned to transcribe Khmer, English, and Khmer–English code-switched speech, where both languages are mixed in the same sentence. It writes Khmer in Khmer script and English in Latin script, with punctuation.
Compared with the previous version (v1), this release cuts the English word error rate from 11.1 % to 8.3 % and the code-switch character error rate from 14.1 % to 4.5 %, and is slightly better on Khmer.
| Architecture | Whisper small (encoder-decoder transformer, 12 + 12 layers, 242 M parameters) |
| Base model | PhanithLIM/whisper-small-aug-28-april-lightning-v1, a Khmer fine-tune of openai/whisper-small |
| Languages | Khmer (km), English (en) |
| Input | 16 kHz mono audio, up to 30 s per call (≤ 15 s recommended for Khmer) |
| Output | Text without timestamps |
| Weights | model.safetensors, float32, 967 MB |
| Code | github.com/chestharastan/Tha-ASR: training, evaluation and a local web app |
Evaluation
All test sets are held out: no training utterance shares its text with a test or dev sentence.
| Test set | Utterances | Metric | v1 | Tha-ASR (v2) |
|---|---|---|---|---|
FLEURS Khmer (km_kh, test) |
765 | CER | 12.74 % | 12.57 % |
| khm-asr-open (test) | 765 | CER | 12.72 % | 12.35 % |
FLEURS English (en_us, test) |
647 | WER | 11.09 % | 8.27 % |
FLEURS English (en_us, test) |
647 | CER | 5.05 % | 3.72 % |
| Khmer–English code-switch (held out) | 534 | CER | 14.08 % | 4.46 % |
How it was measured. Clean audio, beam search with 5 beams, batch size 4, max_new_tokens=440, and the language
token set to each test set's language. Khmer is scored with CER after Unicode NFC normalisation, removing
zero-width characters, and ignoring spaces and punctuation (Khmer has no reliable word spacing, so WER is not
meaningful). English is scored with WER after lower-casing and removing punctuation. Lower is better.
Read these numbers with care:
- 537 of the 765 khm-asr-open test sentences also appear in the FLEURS Khmer test set, so the two Khmer results largely overlap.
- The code-switch set was built by the same data pipeline that produced the code-switch training data, not collected from natural conversations, and it is small. Expect higher error rates on spontaneous mixed-language speech.
How to use
pip install torch transformers librosa
Transcribe a clip (up to 30 s)
import librosa
import torch
from transformers import WhisperForConditionalGeneration, WhisperProcessor
model_id = "Thareah/Tha-ASR"
processor = WhisperProcessor.from_pretrained(model_id)
model = WhisperForConditionalGeneration.from_pretrained(model_id).eval()
audio, _ = librosa.load("speech.wav", sr=16000, mono=True)
inputs = processor(audio, sampling_rate=16000, return_tensors="pt")
with torch.inference_mode():
ids = model.generate(inputs.input_features, language="km", task="transcribe", num_beams=5, max_new_tokens=440)
print(processor.batch_decode(ids, skip_special_tokens=True)[0])
Use language="en" for English.
Detect Khmer or English automatically
Whisper's built-in language detection chooses among 99 languages and can drift to Thai or Lao on Khmer speech. Comparing only the Khmer and English language tokens is more reliable:
def detect_km_en(features):
tok = processor.tokenizer
lang_ids = [tok.convert_tokens_to_ids("<|km|>"), tok.convert_tokens_to_ids("<|en|>")]
start = torch.tensor([[tok.convert_tokens_to_ids("<|startoftranscript|>")]])
with torch.inference_mode():
logits = model(input_features=features, decoder_input_ids=start).logits[0, -1]
return ("km", "en")[int(logits[lang_ids].argmax())]
language = detect_km_en(inputs.input_features)
ids = model.generate(inputs.input_features, language=language, task="transcribe", num_beams=5, max_new_tokens=440)
Long recordings
Cut long audio at pauses into pieces of at most 15 s, then transcribe the pieces as a batch. Khmer needs many tokens
per second of speech, and Whisper's decoder holds only 448 tokens. Splitting at pauses also avoids the repetition
loops that fixed-length chunking can cause. This example uses the Silero voice detector that comes with faster-whisper
(pip install faster-whisper):
from faster_whisper.vad import VadOptions, get_speech_timestamps
audio, _ = librosa.load("meeting.mp3", sr=16000, mono=True)
spans = get_speech_timestamps(audio, VadOptions(max_speech_duration_s=15, min_silence_duration_ms=300, speech_pad_ms=200))
pieces = [audio[s["start"]:s["end"]] for s in spans]
features = processor(pieces, sampling_rate=16000, return_tensors="pt").input_features
with torch.inference_mode():
ids = model.generate(features, language="km", task="transcribe", num_beams=5, max_new_tokens=440)
for s, text in zip(spans, processor.batch_decode(ids, skip_special_tokens=True)):
print(f"[{s['start'] / 16000:7.1f}s - {s['end'] / 16000:7.1f}s] {text.strip()}")
For many pieces, run them in batches of 8–16 to limit memory. On a GPU, load the model with
torch_dtype=torch.float16 and move it and the features to "cuda".
Training
Data
v1 was fine-tuned from the base model on 36.5 hours (27,966 utterances):
| Source | Language | Utterances | Hours |
|---|---|---|---|
| seanghay/km-speech-corpus | km | 14,838 | 10.4 |
| rinabuoy/khm-asr-open (train) | km | 6,712 | 8.7 |
google/fleurs en_us (train) |
en | 2,565 | 7.4 |
google/fleurs km_kh (train) |
km | 1,654 | 7.0 |
| seanghay/khmer_mpwt_speech | km | 1,850 | 1.8 |
| seanghay/khmer_grkpp_speech | km | 347 | 1.4 |
Before training, 21,615 duplicate utterances shared between these aggregated corpora were removed, along with 236
utterances whose text appears in a dev or test set. The dev set is the FLEURS km_kh and en_us dev splits
(717 utterances).
v2 (this model) continues from v1 for one more pass over a larger mix:
- the v1 data, with FLEURS Khmer and khm-asr-open repeated three times;
- up to 100 hours of additional Khmer speech;
- additional English speech, not repeated;
- Khmer–English code-switched utterances.
As in v1, rows whose text appears in any dev or test set (including the code-switch test set) were removed, as were exact repeats.
Procedure
| v1 | v2 | |
|---|---|---|
| Initialised from | base model | v1 |
| Learning rate | 1e-5 | 5e-6 |
| Epochs | 1 | 1 |
| Batch | 2 × 8 gradient accumulation = 16 | same |
| Schedule | linear, 300 warm-up steps | same |
| Optimiser | AdamW 8-bit (bitsandbytes), weight decay 0.01, gradient clipping 1.0 | same |
| Precision | bf16 mixed precision, gradient checkpointing | same |
| Seed | 42 | 42 |
Targets are <|lang|><|transcribe|><|notimestamps|> text <|endoftext|>, so the model keeps its language
identification but is not trained to predict timestamps.
To make the model hold up on real microphones, the training script corrupts 70 % of clips on the fly with random combinations of: DEMAND background noise (0–25 dB SNR), other speakers in the background, simulated room reverb, speed changes (0.9–1.1×), microphone hiss, a telephone band filter, and volume changes. SpecAugment is applied on top.
Limitations
- Timestamps: the model was trained without timestamp tokens. Take timing from a voice detector, as in the long-recording example above.
- Long audio: feed at most ~15 s of Khmer at a time; longer pieces can overflow the 448-token decoder and get cut off.
- Silence and noise: like other Whisper models, it can produce text for non-speech audio. Use a voice detector to skip silence.
- Coverage: much of the training audio is read speech (FLEURS, for example). Expect higher error rates on spontaneous conversation, strong regional accents, children's speech and far-field recordings.
- Quantisation: an int8 CTranslate2 export runs much faster on CPU but was clearly less accurate on Khmer in a spot check. Use the float model when accuracy matters.
- Use: do not use it for surveillance or to transcribe people without their consent. Review transcripts before relying on them for high-stakes decisions.
License and acknowledgements
The weights are released under the MIT license. The base model and OpenAI Whisper are released under Apache-2.0; check each training dataset's license before using this model commercially.
Thanks to OpenAI for Whisper, to PhanithLIM for the Khmer Whisper models this work starts from, and to the authors of the speech datasets listed above.
Citation
@misc{tha_asr_2026,
title = {Tha-ASR: Khmer and English speech recognition},
author = {Thareah},
year = {2026},
howpublished = {\url{https://huggingface.co/Thareah/Tha-ASR}}
}
- Downloads last month
- 19
Model tree for Thareah/Tha-ASR
Base model
openai/whisper-smallDatasets used to train Thareah/Tha-ASR
seanghay/km-speech-corpus
rinabuoy/khm-asr-open
Evaluation results
- CER on FLEURS (Khmer)test set self-reported12.570
- CER on khm-asr-opentest set self-reported12.350
- WER on FLEURS (English)test set self-reported8.270
- CER on FLEURS (English)test set self-reported3.720