| # Balochi STT (Whisper) |
|
|
| Fine-tuned **Whisper-small** speech-to-text model for **Balochi (Latin script)**. |
|
|
| | Item | Value | |
| | --- | --- | |
| | Task | Automatic speech recognition (ASR / STT) | |
| | Language | Balochi (Latin orthography) | |
| | Base model | Whisper-small | |
| | Sample rate | 16 kHz, mono | |
| | Best eval WER | ~4.5% | |
| | Training data | 5,237 clips (~3 hours) from `wavs/wavs` + `wavs/wavs.txt` | |
|
|
| --- |
|
|
| ## Folder layout |
|
|
| ```text |
| balochi_whisper/ |
| ├── README.md |
| ├── best_model/ |
| │ ├── model/ # Whisper weights + config |
| │ ├── processor/ # tokenizer + feature extractor |
| │ └── eval_metrics.txt |
| └── checkpoints/ # training checkpoints (optional) |
| ``` |
|
|
| Use **`best_model/`** for inference. |
| |
| --- |
| |
| ## Requirements |
| |
| ```bash |
| source ~/venvs/torch/bin/activate |
| ``` |
| |
| Needs: `torch`, `transformers`, `soundfile`, `torchaudio`, `numpy`. |
| |
| GPU is recommended (tested on NVIDIA RTX 3060). |
| |
| --- |
| |
| ## Quick inference (Python) |
| |
| ```python |
| from pathlib import Path |
| import numpy as np |
| import soundfile as sf |
| import torch |
| import torchaudio |
| from transformers import WhisperForConditionalGeneration, WhisperProcessor |
| |
| ROOT = Path("balochi_whisper/best_model") |
| device = "cuda" if torch.cuda.is_available() else "cpu" |
| |
| processor = WhisperProcessor.from_pretrained(ROOT / "processor") |
| model = WhisperForConditionalGeneration.from_pretrained(ROOT / "model").to(device) |
| model.eval() |
| model.config.forced_decoder_ids = None |
| model.generation_config.forced_decoder_ids = None |
| model.generation_config.pad_token_id = processor.tokenizer.pad_token_id |
| |
| def load_16k(path: str) -> np.ndarray: |
| wav, sr = sf.read(path, always_2d=False) |
| if wav.ndim > 1: |
| wav = wav.mean(axis=1) |
| wav = np.asarray(wav, dtype=np.float32) |
| if sr != 16000: |
| wav = ( |
| torchaudio.functional.resample( |
| torch.from_numpy(wav).unsqueeze(0), sr, 16000 |
| ) |
| .squeeze(0) |
| .numpy() |
| ) |
| return wav |
| |
| wav = load_16k("your_audio.wav") |
| inputs = processor( |
| wav, sampling_rate=16000, return_tensors="pt", return_attention_mask=True |
| ) |
| with torch.no_grad(): |
| ids = model.generate( |
| inputs.input_features.to(device), |
| attention_mask=inputs.attention_mask.to(device), |
| max_new_tokens=224, |
| ) |
| text = processor.batch_decode(ids.cpu(), skip_special_tokens=True)[0].strip() |
| print(text) |
| ``` |
| |
| --- |
| |
| ## CLI (from project root) |
| |
| ```bash |
| cd ~/Balochi_tts |
| source ~/venvs/torch/bin/activate |
| python infer_stt.py /path/to/audio.wav |
| ``` |
| |
| Desktop GUI: |
| |
| ```bash |
| python stt_gui.py |
| ``` |
| |
| --- |
| |
| ## Training data format |
| |
| ```text |
| wavs/wavs/1.wav … N.wav |
| wavs/wavs.txt # line i → transcript for (i+1).wav |
| ``` |
| |
| Transcripts use Balochi **Latin** script (`á`, `é`, `ó` allowed). |
| |
| Retrain / resume from project root: |
| |
| ```bash |
| python train_stt.py |
| ``` |
| |
| Checkpoints are saved under `balochi_whisper/checkpoints/`. The best model (lowest WER) is copied to `balochi_whisper/best_model/`. |
| |
| --- |
| |
| ## Hugging Face |
| |
| Upload this model: |
| |
| ```bash |
| # from Balochi_tts project root |
| bash scripts/push_models_to_hf.sh YOUR_HF_USER |
| ``` |
| |
| That publishes `YOUR_HF_USER/balochi-whisper-stt` with `model/` and `processor/`. |
| |
| Load from the Hub: |
| |
| ```python |
| from transformers import WhisperForConditionalGeneration, WhisperProcessor |
| |
| repo = "YOUR_HF_USER/balochi-whisper-stt" |
| processor = WhisperProcessor.from_pretrained(repo, subfolder="processor") |
| model = WhisperForConditionalGeneration.from_pretrained(repo, subfolder="model") |
| ``` |
| |
| If you upload files at the repo root (no subfolders), omit `subfolder=...`. |
| |
| --- |
| |
| ## Notes |
| |
| - Input audio is converted to **16 kHz mono** before recognition. |
| - Audio longer than **30 seconds** should be chunked (the project CLI/GUI do this). |
| - Output is Balochi **Latin** text, not Arabic script. |
| - Do not force an English language token; Balochi is not a built-in Whisper language. |
| |
| --- |
| |
| ## Files to ship |
| |
| Minimum files for inference: |
| |
| ```text |
| best_model/model/config.json |
| best_model/model/generation_config.json |
| best_model/model/model.safetensors |
| best_model/processor/ # full processor directory |
| ``` |
| |
| `checkpoints/` is only needed to resume training. |
| |