Views
No views yet
1pip install -U torch torchaudio transformers pyctcdecode kenlm huggingface_hub
2Note: After installing the packages in a notebook environment, restart the kernel before running the inference code.
1import torch
2import torchaudio
3from transformers import AutoModelForCTC, AutoProcessor
4
5MODEL_ID = "kingabzpro/wav2vec2-large-xls-r-300m-Urdu"
6DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
7INFERENCE_DTYPE = torch.float16 if DEVICE.type == "cuda" else torch.float32
8
9processor = AutoProcessor.from_pretrained(MODEL_ID)
10model = AutoModelForCTC.from_pretrained(MODEL_ID).eval().to(
11 device=DEVICE, dtype=INFERENCE_DTYPE
12)
13
14waveform, sample_rate = torchaudio.load("audio.wav")
15
16# Convert stereo (or multi-channel) audio to mono and resample to 16 kHz.
17waveform = waveform.mean(dim=0)
18if sample_rate != 16_000:
19 waveform = torchaudio.functional.resample(waveform, sample_rate, 16_000)
20
21inputs = processor(
22 waveform.numpy(), sampling_rate=16_000, return_tensors="pt", padding=True
23).input_values.to(device=DEVICE, dtype=INFERENCE_DTYPE)
24
25with torch.inference_mode():
26 predicted_ids = model(inputs).logits.argmax(dim=-1)
27
28transcription = processor.batch_decode(predicted_ids)[0]
29print(transcription)Why use it? The included 5-gram KenLM language model reduces the reported full-test WER from 56.07% (greedy CTC) to 39.89%.
1import json
2import torch
3import torchaudio
4from huggingface_hub import hf_hub_download
5from pyctcdecode import build_ctcdecoder
6from transformers import AutoModelForCTC, AutoProcessor
7
8MODEL_ID = "kingabzpro/wav2vec2-large-xls-r-300m-Urdu"
9DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10INFERENCE_DTYPE = torch.float16 if DEVICE.type == "cuda" else torch.float32
11
12processor = AutoProcessor.from_pretrained(MODEL_ID)
13model = AutoModelForCTC.from_pretrained(MODEL_ID).eval().to(
14 device=DEVICE, dtype=INFERENCE_DTYPE
15)
16
17kenlm_path = hf_hub_download(MODEL_ID, "language_model/5gram.bin")
18unigrams_path = hf_hub_download(MODEL_ID, "language_model/unigrams.txt")
19attrs_path = hf_hub_download(MODEL_ID, "language_model/attrs.json")
20
21with open(unigrams_path, encoding="utf-8") as file:
22 unigrams = [line.strip() for line in file if line.strip()]
23with open(attrs_path, encoding="utf-8") as file:
24 attrs = json.load(file)
25
26# Keep only acoustic tokens. The matching ID list is then applied to logits.
27vocab_items = sorted(processor.tokenizer.get_vocab().items(), key=lambda item: item[1])
28blank_id = processor.tokenizer.pad_token_id
29delimiter = processor.tokenizer.word_delimiter_token
30decoder_pairs = [
31 (token, token_id)
32 for token, token_id in vocab_items
33 if token_id == blank_id or token == delimiter or len(token) == 1
34]
35kept_token_ids = [token_id for _, token_id in decoder_pairs]
36labels = [
37 "" if token_id == blank_id else " " if token == delimiter else token
38 for token, token_id in decoder_pairs
39]
40decoder = build_ctcdecoder(
41 labels,
42 kenlm_model_path=kenlm_path,
43 unigrams=unigrams,
44 alpha=attrs.get("alpha", 0.5),
45 beta=attrs.get("beta", 1.0),
46)
47
48waveform, sample_rate = torchaudio.load("audio.wav")
49waveform = waveform.mean(dim=0)
50if sample_rate != 16_000:
51 waveform = torchaudio.functional.resample(waveform, sample_rate, 16_000)
52
53inputs = processor(
54 waveform.numpy(), sampling_rate=16_000, return_tensors="pt"
55).input_values.to(device=DEVICE, dtype=INFERENCE_DTYPE)
56with torch.inference_mode():
57 logits = model(inputs).logits[0].float().cpu().numpy()
58
59transcription = decoder.decode(logits[:, kept_token_ids])
60print(transcription)fixie-ai/common_voice_17_0 (ur, test).1from datasets import Audio, load_dataset
2
3stream = load_dataset(
4 "fixie-ai/common_voice_17_0", "ur", split="test", streaming=True
5).cast_column("audio", Audio(sampling_rate=16_000))
6
7example = next(iter(stream))
8audio = example["audio"]
9samples = audio.get_all_samples().data if hasattr(audio, "get_all_samples") else audio["array"]
10waveform = samples.detach().cpu().numpy() if torch.is_tensor(samples) else samples
11if waveform.ndim == 2:
12 waveform = waveform.mean(axis=0 if waveform.shape[0] <= waveform.shape[-1] else 1)
13
14inputs = processor(waveform, sampling_rate=16_000, return_tensors="pt")
15with torch.inference_mode():
16 logits = model(inputs.input_values.to(device=DEVICE, dtype=INFERENCE_DTYPE)).logits[0]
17
18prediction = decoder.decode(logits.float().cpu().numpy()[:, kept_token_ids])
19print("Reference: ", example["sentence"])
20print("Prediction:", prediction)1Reference: بے ذوق نہیں اگرچہ فطرت
2Prediction: بھی ذوق نہیں اگھرچے فطرت| Sample | Duration (s) | WER | CER |
|---|---|---|---|
| 1 | 2.92 | 0.00% | 0.00% |
| 2 | 2.88 | 0.00% | 0.00% |
| 3 | 5.40 | 22.22% | 3.03% |
| 4 | 4.36 | 33.33% | 12.50% |
| 5 | 5.69 | 42.11% | 24.00% |
| Mean | — | 19.53% | 7.91% |
Important: This is a five-sample smoke test—not a benchmark. Do not compare it directly with the full Common Voice 8.0 test-set results below.
| Decoder | Test WER | Test CER |
|---|---|---|
| Greedy CTC | 56.07% | 23.70% |
| 5-gram language model | 39.89% | 16.70% |
python eval.py --model_id kingabzpro/wav2vec2-large-xls-r-300m-Urdu --dataset mozilla-foundation/common_voice_8_0 --config ur --split testfacebook/wav2vec2-xls-r-300m on Urdu Mozilla Common Voice 8.0.| Hyperparameter | Value |
|---|---|
| Learning rate | 1e-4 |
| Train batch size | 32 |
| Evaluation batch size | 8 |
| Gradient accumulation | 2 |
| Effective train batch size | 64 |
| Epochs | 200 |
| LR scheduler | Linear, 1,000 warm-up steps |
| Optimizer | Adam (β₁=0.9, β₂=0.999, ε=1e-8) |
| Training loss | Epoch | Step | Validation loss | WER | CER |
|---|---|---|---|---|---|
| 3.6398 | 30.77 | 400 | 3.3517 | 1.0000 | 1.0000 |
| 2.9225 | 61.54 | 800 | 2.5123 | 1.0000 | 0.8310 |
| 1.2568 | 92.31 | 1,200 | 0.9699 | 0.6273 | 0.2575 |
| 0.8974 | 123.08 | 1,600 | 0.9715 | 0.5888 | 0.2457 |
| 0.7151 | 153.85 | 2,000 | 0.9984 | 0.5588 | 0.2353 |
| 0.6416 | 184.62 | 2,400 | 0.9889 | 0.5607 | 0.2370 |