NeLF S2T ONNX β€” Flemish Dutch ASR

ONNX export of the NeLF Speech-to-Text PyTorch model. Full Flemish/Dutch ASR with dual verbatim + subtitle output, running via ONNX Runtime β€” no PyTorch needed.

Model Architecture

  • Encoder: STFT β†’ LogMel (80) β†’ GlobalMVN β†’ Conv2dSubsampling6 β†’ 12Γ— Conformer (512-dim, 8 heads)
  • Subtitle Encoder: 6Γ— Transformer (cascaded from verbatim encoder)
  • Decoders: Dual transformer decoders with swapped cross-attention (verbatim primary / subtitle primary)
  • CTC head: Linear projection to 5000 tokens
  • Params: 180M

Files

File Size Description
encoder.onnx 348 MB Audio waveform β†’ verbatim encoder features (B, T, 512)
encoder_sub.onnx 83 MB Verbatim features β†’ subtitle encoder features
ctc.onnx 9.8 MB Encoder features β†’ CTC logits (B, T, 5000)
decoder_step.onnx 150 MB Autoregressive decoder step (verbatim)
decoder_sub_step.onnx 150 MB Autoregressive decoder step (subtitle)
bpe.model 314 KB SentencePiece BPE tokenizer
tokens.txt 42 KB Token vocabulary (5000 tokens)

Usage

ONNX Runtime (Python)

import onnxruntime as ort
import numpy as np
import soundfile as sf
from sentencepiece import SentencePieceProcessor

# Load models
enc = ort.InferenceSession("encoder.onnx")
enc_sub = ort.InferenceSession("encoder_sub.onnx")
ctc = ort.InferenceSession("ctc.onnx")

# Load tokenizer
tokenizer = SentencePieceProcessor()
tokenizer.Load("bpe.model")
with open("tokens.txt") as f:
    token_list = [line.strip() for line in f]

# Transcribe
audio, sr = sf.read("speech.wav")
audio = audio.mean(axis=1) if audio.ndim > 1 else audio

wav = audio[np.newaxis, :].astype(np.float32)
wav_len = np.array([wav.shape[1]], dtype=np.int64)

enc_out, enc_len = enc.run(None, {"wav": wav, "wav_len": wav_len})
logits = ctc.run(None, {"enc_out": enc_out})[0]

# Greedy CTC decode
preds = logits[0].argmax(axis=-1)
tokens = []
prev = -1
for p in preds[:int(enc_len[0])]:
    if p != prev and p != 0:
        tokens.append(int(p))
    prev = int(p)

text = tokenizer.DecodePieces([token_list[i] for i in tokens])
print(text)

Autoregressive Decoding

dec = ort.InferenceSession("decoder_step.onnx")

tokens = [1]  # <sos/eos>
for _ in range(225):
    t = np.array([tokens], dtype=np.int64)
    logits = dec.run(None, {
        "tokens": t,
        "encoder_out": enc_out,
        "enc_len": enc_len,
        "sub_out": enc_out,  # or encoder_sub output for subtitle decoder
        "sub_len": enc_len,
    })[0]
    next_t = int(logits[0, -1].argmax())
    if next_t == 1:
        break
    tokens.append(next_t)

Input / Output Shapes

Model Inputs Outputs
encoder.onnx wav: (B, T_wav), wav_len: (B,) enc_out: (B, T_enc, 512), enc_len: (B,)
encoder_sub.onnx enc_in: (B, T, 512), enc_len: (B,) sub_out: (B, T, 512), sub_len: (B,)
ctc.onnx enc_out: (B, T, 512) logits: (B, T, 5000)
decoder_step.onnx tokens: (B, L), encoder_out: (B, T, 512), enc_len: (B,), sub_out: (B, T, 512), sub_len: (B,) logits: (B, L, 5000)

All axes are dynamic (variable batch size, time, sequence length).

Training Details

Trained on 300 hours of verbatim Flemish CGN (3Γ— noise augmented), 700 hours of Netherlands Dutch CGN, and 14,000 hours of weakly-supervised Flemish broadcast subtitles. See the original model card for full details.

License

CC-BY-NC-4.0 (same as the original NeLF model).

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support