Views
No views yet
1import torch
2import soundfile as sf
3import numpy as np
4from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC
5
6# =========================================================
7# CONFIG
8# =========================================================
9
10CHECKPOINT_PATH = "GaborMadarasz/wav2vec2-large-xlsr-53-hungarian1"
11WAV_PATH = "sample.wav"
12
13DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
14
15# =========================================================
16# MODEL LOAD
17# =========================================================
18
19print("Loading model...")
20
21processor = Wav2Vec2Processor.from_pretrained(CHECKPOINT_PATH)
22
23model = Wav2Vec2ForCTC.from_pretrained(CHECKPOINT_PATH)
24model.to(DEVICE)
25model.eval()
26
27# =========================================================
28# INFERENCE ENGINE
29# =========================================================
30
31class RobustInferenceEngine:
32
33 def __init__(self, model, processor, device="cpu"):
34 self.model = model
35 self.processor = processor
36 self.device = device
37
38 self.special_tokens = set([
39 "[PAD]", "[UNK]",
40 "<pad>", "<unk>",
41 "<s>", "</s>"
42 ])
43
44 self.tokenizer = processor.tokenizer
45
46 @torch.no_grad()
47 def decode_tokens(self, pred_ids: torch.Tensor) -> str:
48
49 tokens = self.tokenizer.convert_ids_to_tokens(
50 pred_ids.tolist()
51 )
52
53 prev_token = None
54 output_chars = []
55
56 for token in tokens:
57
58 if token in self.special_tokens:
59 prev_token = token
60 continue
61
62 if token == prev_token:
63 continue
64
65 if token.startswith("▁"):
66 output_chars.append(" ")
67 output_chars.append(token[1:])
68 else:
69 output_chars.append(token)
70
71 prev_token = token
72
73 text = "".join(output_chars)
74 text = text.replace("▁", " ")
75 return text.strip()
76
77 @torch.no_grad()
78 def transcribe_file(self, wav_path: str) -> str:
79
80 audio_input, sr = sf.read(wav_path)
81
82 # Mono conversion
83 if len(audio_input.shape) > 1:
84 audio_input = audio_input.mean(axis=1)
85
86 inputs = self.processor(
87 audio_input,
88 sampling_rate=sr,
89 return_tensors="pt",
90 padding=True
91 )
92
93 inputs = {k: v.to(self.device) for k, v in inputs.items()}
94
95 logits = self.model(**inputs).logits
96 pred_ids = torch.argmax(logits, dim=-1)
97
98 return self.decode_tokens(pred_ids[0])
99
100# =========================================================
101# RUN SAMPLE INFERENCE
102# =========================================================
103
104engine = RobustInferenceEngine(
105 model=model,
106 processor=processor,
107 device=DEVICE
108)
109
110print("Transcribing sample.wav ...")
111
112text = engine.transcribe_file(WAV_PATH)
113
114print("\nTranscription:")
115print(text)| Model | Architecture | Parameters | Decoding | Hungarian Adaptation | WER (CV HU) | Evaluation Source |
|---|---|---|---|---|---|---|
| This model (XLSR fine-tuned) | Wav2Vec2-CTC (encoder-only) | ~300M | Greedy CTC | Fine-tuned on CV 24.0 HU | 0.1647 | Measured (this work) |
| Whisper-Large | Encoder-Decoder (seq2seq Transformer) | ~1.55B | Beam search | Multilingual pretraining | ~0.08–0.12 | Reported (public benchmarks) |
| Google Speech-to-Text | Proprietary hybrid DNN/Transformer | Not disclosed | Internal LM + beam | Production-scale multilingual | ~0.07–0.12 | Reported (vendor benchmarks) |
| XLSR (base, not fine-tuned) | Wav2Vec2-CTC (encoder-only) | ~300M | Greedy CTC | None | ~0.35+ | Reported (zero-shot HU) |
@misc{GaborMadarasz/wav2vec2-large-xlsr-53-hungarian1,
title={Hungarian ASR model fine-tuned on Common Voice 24.0},
author={Gabor Madarasz},
year={2026},
howpublished={Hugging Face Model Hub},
}