Speech Recognition with Wav2Vec2

When Whisper isn't enough for your accent or domain, fine-tune Wav2Vec2 on your own audio. This guide explains self-supervised pretraining, the fine-tuning recipe (freezing, learning rates, XLSR for multilingual), CTC decoding with n-gram language models, honest WER evaluation, and data preparation pitfalls.

Written by Projectech6 min readPublished
For B.E./B.Tech Computer Science and AI/ML students who need speech recognition tuned to a specific domain, accent, or vocabulary — beyond what generic Whisper gives Topics: Wav2Vec2, Hugging Face, PyTorch, CTC
Illustration of Wav2Vec2 speech recognition showing audio waveforms being encoded by a transformer and decoded into text transcripts with word error rate metrics.
Illustration generated for this guide.
In this guide

Whisper transcribes general speech remarkably well with zero training. But point it at heavy regional accents, domain jargon (medical, legal, technical terms), or a low-resource language, and the errors pile up. Wav2Vec2 is the alternative path: a self-supervised speech model you fine-tune on your own labeled audio — often just tens of hours — to beat generic models on your specific data.

This guide explains how Wav2Vec2 works, when fine-tuning beats using Whisper, how to prepare audio data, the fine-tuning recipe, and how to evaluate honestly with word error rate.

How Wav2Vec2 works: learn representations first, transcribe later

Wav2Vec2 (Baevski et al., 2020) has two phases:

  1. Self-supervised pretraining. The model learns from raw audio alone — no transcripts. It masks spans of the audio (like BERT masks words) and learns to predict the masked representations contrastively. From thousands of hours of unlabeled speech, it learns a rich representation of phonetics, speaker variation, and acoustic structure.
  2. Supervised fine-tuning. A small CTC (Connectionist Temporal Classification) head is added, and the model trains on your labeled audio-transcript pairs. Because the representations are already excellent, fine-tuning needs far less labeled data than training from scratch — the original paper showed strong results with as little as 10 minutes to 100 hours of labeled audio depending on the target quality.

The architecture: a CNN feature encoder turns raw waveform into latent frames, then a transformer (the same architecture as in NLP) builds contextualized representations. CTC handles the alignment problem — mapping frame-level predictions to character sequences without needing word-level timestamps in the training data.

Note: The magic is the pretraining. You are not training speech recognition from nothing; you are adapting a model that already understands the structure of speech to your specific audio.

When to fine-tune Wav2Vec2 vs just using Whisper

Situation Better choice
General transcription, many languages Whisper (see the Whisper guide)
Specific accent Whisper mangles Wav2Vec2 fine-tuned on that accent
Domain vocabulary (medical, technical) Wav2Vec2 + custom language model
Low-resource language Wav2Vec2 (multilingual XLSR variant) fine-tuned
You have 10+ hours of labeled audio Wav2Vec2 becomes very attractive
You have <1 hour of labeled audio Whisper, or Whisper + prompt tricks
Real-time streaming Neither is ideal; Wav2Vec2 with chunking is workable

The decision hinges on labeled data: fine-tuning needs it, Whisper does not. If you can collect or label 10–50 hours of representative audio, Wav2Vec2 will typically surpass Whisper on that domain.

Preparing audio data

Wav2Vec2 expects 16 kHz mono WAV. Data preparation checklist:

  • Resample everything to 16 kHz mono. Mixed sample rates are a classic silent bug — verify, do not assume.
  • Segment into utterances. Training examples should be single utterances, roughly 1–20 seconds. Long files must be split (on silence or using existing timestamps).
  • Clean the transcripts. Normalize text: lowercase (or match the model's vocab convention), expand numbers to words ("42" → "forty two"), remove punctuation the model is not trained to predict. Transcript normalization mismatches are a top cause of bad WER.
  • Train/dev/test splits by speaker. If the same speaker appears in train and test, your WER is optimistic. Split speakers across sets for an honest number.
  • Check audio quality. Clip a random 20 files and listen. Corrupted files, wrong transcripts, and misaligned segments poison training disproportionately.

A manifest (CSV/JSONL mapping audio path → transcript) is the standard format; Hugging Face datasets handle it natively.

The fine-tuning recipe

Using Hugging Face transformers:

from transformers import Wav2Vec2ForCTC, TrainingArguments, Trainer

model = Wav2Vec2ForCTC.from_pretrained(
    "facebook/wav2vec2-base-960h",  # or xlsr variant for multilingual
)
# Freeze the CNN feature encoder; fine-tune the transformer + CTC head
model.freeze_feature_encoder()

args = TrainingArguments(
    output_dir="./wav2vec2-ft",
    per_device_train_batch_size=8,
    learning_rate=3e-4,
    num_train_epochs=30,
    evaluation_strategy="epoch",
    save_total_limit=2,
)

Key practices:

  • Freeze the feature encoder (the CNN layers) — fine-tuning it rarely helps and often hurts on small data.
  • Learning rate around 1e-4 to 3e-4 with a warmup; CTC training is sensitive to LR.
  • Gradient accumulation to simulate larger batches on limited GPU memory.
  • SpecAugment-style masking (time/frequency masking of the spectrogram) is usually enabled by default and helps generalization.
  • Start from a checkpoint already fine-tuned on a related language if one exists (e.g., an XLSR model fine-tuned on Hindi before adapting to your Hindi-accented data).

For multilingual/low-resource targets, use the XLS-R variant (pretrained on 128 languages) instead of the English-only base — it transfers dramatically better.

Decoding: greedy vs language models

CTC outputs character probabilities per frame; decoding turns them into text:

Decoding Quality Cost
Greedy Baseline Free
Beam search Better, fixes obvious errors Moderate compute
Beam search + n-gram language model Strongest — injects domain vocabulary knowledge Needs a text corpus for the LM

The language model is the secret weapon for domain adaptation: train a simple n-gram LM on domain text (medical textbooks, technical manuals — text is cheap, audio is expensive) and shallow-fuse it during decoding. This fixes vocabulary errors without any additional labeled audio. The pyctcdecode library implements this pipeline.

Evaluating with Word Error Rate

WER is the standard metric: (substitutions + insertions + deletions) / total words in the reference. Compute it on your speaker-disjoint test set:

from jiwer import wer

reference = "the quick brown fox"
hypothesis = "the quick brown box"
print(f"WER: {wer(reference, hypothesis):.2%}")

Reporting guidance:

  • Report WER on the test set, with the decoding method named (greedy vs beam+LM numbers are not comparable).
  • Compare against a baseline: Whisper on the same test set, or the pretrained model before fine-tuning. The improvement is your result.
  • Break down errors by category (proper nouns? numbers? specific phonemes?) — the breakdown tells you what to fix next.
  • Never tune on the test set. Tune on dev, report on test, once.

Common mistakes

  • Sample rate mismatch. 8 kHz audio fed to a 16 kHz model (or vice versa) silently destroys accuracy. Verify every file.
  • Transcript normalization mismatch. Training on "Hello, world!" while the vocab expects "hello world" wastes capacity on punctuation.
  • Speaker leakage across splits. Same speakers in train and test → flattering, meaningless WER.
  • Unfreezing everything on small data. Fine-tuning the feature encoder with 5 hours of audio usually degrades the pretrained representations.
  • No language model in decoding. Leaving the cheapest accuracy win on the table, especially for domain vocabulary.
  • Evaluating on clean audio only. Test on audio matching deployment conditions — your microphone, your noise, your speakers.
  • Expecting miracles from 30 minutes of data. 10 minutes can work for adapting to a similar domain; genuinely new domains/languages need tens of hours.

Where to go from here

For zero-training transcription, start with the Whisper guide and only reach for fine-tuning when Whisper falls short on your data. For collecting that data well, read data labeling strategies; to label efficiently, active learning. Free GPU training is covered in the Google Colab guide. More speech AI in the AI & Machine Learning branch hub.