paprika-whisper-lt-v3 - 🌶️ Lithuanian ASR (LIEPA-3 fine-tune)

Third generation of a Lithuanian fine-tune of whisper-large-v3-turbo. Trained on ~3,281 h of LIEPA-3, warm-started from paprika-whisper-lt.

Ready-to-run pipelines for real-time subtitles and long-file transcription with punctuation and speaker labels: https://github.com/kristijonasatpro/paprika

Read this before you use it

Use long-form decoding. Do not use chunk_length_s.

The chunked pipeline cuts audio at a fixed stride, transcribes each window independently, then merges by matching text in the overlaps — and where the two sides disagree it discards the span it cannot align. Measured 2026-08-15 on clean audio, it silently dropped 30 words from one recording and 52 from another, both at a seam. The output reads perfectly. There is no marker that anything is missing.

It also invents text on non-speech. On 60 s of digital silence, 60 s of faint hiss and 60 s of room tone, the chunked pipeline produced 24–164 characters of confident Lithuanian; native long-form produced zero characters on all three. This is a property of the chunked decoder, not of the weights — the previous generation behaves the same way.

import torch
from transformers import WhisperForConditionalGeneration, WhisperProcessor

m = "kristijonas/paprika-whisper-lt-v3"
proc = WhisperProcessor.from_pretrained(m, language="lithuanian", task="transcribe")
model = WhisperForConditionalGeneration.from_pretrained(m, dtype=torch.float16).to("mps").eval()

feats = proc(audio, sampling_rate=16000, return_tensors="pt",
             truncation=False, padding="longest", return_attention_mask=True)
ids = model.generate(feats.input_features.to("mps", torch.float16),
                     attention_mask=feats.attention_mask.to("mps"),
                     language="lithuanian", task="transcribe",
                     return_timestamps=True, condition_on_prev_tokens=False,
                     temperature=(0.0, 0.2, 0.4, 0.6, 0.8, 1.0),
                     logprob_threshold=-1.0, compression_ratio_threshold=1.35,
                     no_speech_threshold=0.6)
print(proc.batch_decode(ids, skip_special_tokens=True)[0])

Native long-form holds the whole feature sequence in memory (~18 GB for 22 minutes with word timestamps). For long recordings, cut into pause-aligned blocks under 30 s and decode each independently — chunk_longform.py in the repo above does this in bounded memory (5.4 GB flat regardless of duration).

Output has no punctuation and no casing. That is by design: the LIEPA-3 labels have neither, and a separate tagger does the job better. The repo ships one with a word-preservation contract (comma 84.7 / period 88.5 / casing 91.7 F1).

Results

v1 v2 v3
gold-11 WER (chunked) 15.87 15.50 15.29
gold-11 WER (long-form) 17.94 17.68 17.25
heldout-39 WER (chunked) 5.45 5.13 5.16
heldout-39 WER (long-form) 8.44 7.67 6.42
valid timestamp share 1.00

The long-form column is where this generation earns its keep. v1's card advised chunked-only inference because its long-form decoding was broken (+23 WER gap); v3's gap is +1.26 to +1.96, so long-form is now the correct default.

Both benchmarks are in-domain — same sources as training. There is no valid out-of-domain number: the sealed FLEURS set built for it turned out to be 44/44 digital silence, and every figure derived from it was withdrawn. The honest out-of-domain evidence is A/B comparison against a commercial API on real recordings (press conference, two-person call, phone recordings), where v3 was competitive and visibly better on dialect speech.

Training

Warm-started from v2 (itself from v1, from svogunas/whisper-large-v3-turbo-lt). 37,500 steps, effective batch 32, one L40S, ~29 GPU-hours.

Mix: 50% spontaneous, 30% read, 12% phonetic, 5% dialect, 3% VoxPopuli LT. The dialect slice spans all four regions (Aukštaitija, Žemaitija, Dzūkija, Suvalkija). Its transcripts carry stress marks and non-standard vowels (ɜ ə ɘ), which would teach the model to emit them, so they were normalised to standard orthography before training — conservatively, leaving any word the normaliser could not confidently map. That dialect data, not the raw volume, is what this generation actually bought: tripling the hours moved WER ~0.2 points.

Limitations

  • Lowercase, unpunctuated output (see above).
  • Realized-speech convention: transcribes turim, not normative turime, because that is what LIEPA-3 labels do.
  • 16 kHz mono. Parliamentary and spontaneous speech dominate the training mix.
  • No out-of-domain benchmark. Test on your own audio before relying on it.

Attribution

  • Data: LIEPA-3 garsynas (CC BY 4.0, VU / raštija.lt) — dėkojame. VoxPopuli (Meta AI).
  • Base lineage: svogunas/whisper-large-v3-turbo-lt (CC BY 4.0).
  • Built for kalamo.ai — Lithuanian speech tooling.
Downloads last month
1,076
Safetensors
Model size
0.8B params
Tensor type
BF16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for kristijonas/paprika-whisper-lt-v3