norwegian-parakeet

Norwegian (Bokmål) speech-to-text: moondream/parakeet-ultra (a post-trained NVIDIA Parakeet TDT 0.6B v3) fine-tuned only on speech with open licences, about 1,770 hours of unique audio. Every source, its licence and where it came from is listed in docs/DATA.md. The model writes cased, punctuated text and decodes greedily, with no language model.

Code, training recipe and data preparation: https://github.com/ahdrage/norwegian-parakeet (Apache-2.0). Weights: CC BY 4.0.

It is a sibling of norsk-asr and uses its text normalization and scoring, so numbers are scored the same way.

Results

WER (%) with norsk-asr's normalize() (lowercase, no punctuation) on the full test sets, greedy decoding, over all utterances including those with digits.

Test set Clips Hours WER CER
Tuva (3 held-out speakers) 482 0.5 3.1 0.9
NST validation 1,500 2.7 4.2 1.2
NPSC test 5,518 11.0 6.1 2.2
FLEURS Norwegian test 357 1.3 7.4 2.3
Stortinget validation 697 5.0 11.7 6.8
NorGovPCC (held-out) 1,157 8.0 12.5 6.9
NB Samtale (spontaneous conversation, held-out speakers) 4,137 8.2 17.7 8.8

Some caveats on reading these:

  • The reference text is not always what was said. Stortinget and NorGovPCC transcripts are edited (hesitations and some small words are left out), so a model that hears them correctly is still scored as wrong. This sets a floor on those sets.
  • Tuva is small (0.5 h, 3 speakers), so its number moves a lot between runs.
  • NorGovPCC's test split was not filtered; the training split was.
  • The model is evaluated on clips of up to 30 s. Longer recordings need to be cut first; this has not been tested here.

Where the errors are

On NB Samtale most of the remaining errors are in casual speech: dialect forms ("korsen" heard as "hvordan"), "også" heard as "og så", dropped small words and laughter marked as "heh" in the reference. On FLEURS they are mostly foreign names and loanwords and reference spellings (fram/frem, "i følge" / "ifølge"). Both sets contain speech that is rare in the training data.

Each pass

The model is trained in four passes, each continuing from the last at a lower learning rate. WER (%):

Test set Pass 1 Pass 2 Pass 3 Pass 4 (final)
Tuva 3.2 3.1 3.1 3.1
NST 4.6 4.2 4.2 4.2
NPSC 7.3 6.3 6.2 6.1
FLEURS 8.1 7.9 7.8 7.4
Stortinget 12.0 11.8 11.7 11.7
NorGovPCC 13.0 12.6 12.5 12.5
NB Samtale 19.3 18.1 17.8 17.7

Passes 1–3 were scored on the first 5,000 NPSC clips; pass 4 on all 5,518.

Things that were tried on top of this and gave no gain (so are not in the final model): averaging the weights of passes 1–3, rescoring n-best lists with a word trigram model trained on the training transcripts, and speed and noise augmentation in pass 4 (--wav-aug, still in train.py).

Usage

import torch
from transformers import AutoProcessor, ParakeetForTDT

processor = AutoProcessor.from_pretrained("ahdrage/norwegian-parakeet")
model = ParakeetForTDT.from_pretrained("ahdrage/norwegian-parakeet").eval()
# audio: 16 kHz mono float32 numpy array, up to ~30 s per clip
inputs = processor(audio, sampling_rate=16000, return_tensors="pt")
with torch.no_grad():
    out = model.generate(**inputs)
print(processor.batch_decode(out.sequences, skip_special_tokens=True)[0])

How it is trained

  • Targets: the original transcripts, cased and punctuated (NPSC's <ee>-style markers removed), since that is what Parakeet writes. Scoring normalizes both sides.
  • Passes (scripts/run_open.sh, mixes in scripts/mix.py): pass 1 is one epoch over everything at LR 5e-5; pass 2 goes at 1.5e-5 and repeats the smaller, cleaner sources (NPSC, NorGovPCC, Tuva ×2, NB Samtale ×2) against a quarter of Stortinget; pass 3 at 5e-6 does the same with half of NST and an eighth of Stortinget; pass 4 at 3e-6 is a short pass weighted towards conversational speech (NB Samtale ×4, FLEURS ×3).
  • Everything trains: all 0.6B parameters, AdamW, cosine decay with 500 warm-up steps, 64 s of audio per batch, bf16 autocast. BatchNorm keeps its pretrained statistics and layer-drop is off: with small batches, batch statistics blew the loss up from ~5 to ~3,000. No SpecAugment.
  • Digit boundaries: the tokenizer loses the word boundary before a word that starts with a digit, which glues numbers to the previous word. encode_targets in train.py adds the boundary token explicitly.
  • Filtering: clips over 30 s, and clips whose transcripts cannot fit their audio (over 30 or under 2 characters per second), are left out. NorGovPCC and Tuva clips are also checked against a reference model (CER ≤ 0.3, or 0.4 for clips with digits, and at most one of the first or last three words unheard). Tuva's speakers read punctuation aloud ("komma", "punktum", "nytt avsnitt"); those words are cut out using the reference model's word times, so the model does not learn dictation commands. See src/norsk_parakeet/clean_pack.py.
  • Memory-lean TDT loss (src/norsk_parakeet/loss.py). transformers' TDT loss materializes the joint output (frames × tokens × 8,193) in float32 several times and runs out of memory on a 24 GB card at useful batch sizes. The loss here computes the joint in time chunks under activation checkpointing and keeps only what the recursion needs: blank, next-label and duration log-probs. The backward pass uses alpha–beta posteriors instead of autograd through the recursion, and on the GPU both recursions are Triton kernels (src/norsk_parakeet/tdt_triton.py), one program per utterance walking all anti-diagonals. For a batch of two 30 s clips that is 1.8 ms against 2.2 s for the PyTorch loop. tests/test_loss.py checks the gradients against autograd and the kernels against the PyTorch recursion.
  • Resumable: a checkpoint (weights, optimizer, batch position) every 30 minutes, written atomically (about 7 GB each); a restart with the same command continues with the same batch order.

Hardware: one RTX PRO 4000 Blackwell (24 GB), shared with other jobs. The four passes took about 35 hours together.

Reproducing

See the GitHub repository for the data preparation, mixes and training commands.

Licences and attribution

Code: Apache-2.0. The weights are CC BY 4.0, as the base model is (NVIDIA's parakeet-tdt-0.6b-v3, via moondream/parakeet-ultra), with attribution to NVIDIA and Moondream. Training data attribution:

  • Stortinget speech and transcripts (the National Library of Norway's Stortinget subset)
  • NST, NPSC, NB Samtale: National Library of Norway, Språkbanken (CC0)
  • NorGovPCC: National Library of Norway, NLOD 2.0
  • Tuva Speech Database: National Library of Norway, created by Max Manus AS, CC BY 4.0
  • FLEURS: Google, CC BY 4.0

Details, links and checksums are in docs/DATA.md. Two points are not settled and should be read before relying on the model commercially:

  • NST is distributed by the National Library as CC0, but the Hugging Face mirror used here carries no licence tag.
  • Stortinget: the subset carries a CC0 tag on its mirror. Stortinget's own terms for its recordings were being updated in June 2026, and whether they reach the audio in this subset is unresolved.

This is not legal advice and no lawyer has reviewed it.

Downloads last month
35
Safetensors
Model size
0.6B params
Tensor type
F32
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for ahdrage/norwegian-parakeet

Finetuned
(24)
this model

Datasets used to train ahdrage/norwegian-parakeet