rlx-whisper
OpenAI Whisper ASR for RLX: compiled mel encoder, bucketed autoregressive decoder, and a native Rust subtitles pipeline (segment timestamps, word alignment, VAD chunking, diarization) — no Python runtime.
Quick start
# Plain greedy transcript
# Subtitles (SRT + DTW word times + Silero VAD)
Weights: HuggingFace openai/whisper-tiny (or any compatible model.safetensors + config.json + tokenizer.json).
Subtitles pipeline
| Stage | API / module |
|---|---|
| ASR + segment times | WhisperPipeline, timestamp_parse |
| Word alignment (DTW) | WordAlignMode::Dtw, cross_attn_align |
| Word alignment (CTC) | WordAlignMode::Wav2Vec2 + rlx-wav2vec2-asr |
| Silero VAD chunking | silero_vad |
| Speaker labels | diarize + rlx-diarize |
| Export | subtitles — SRT, VTT, TSV, JSON |
use ;
let runner = builder
.weights
.device
.timestamps
.build?;
let mut pipeline = new;
let pcm = load_wav_mono_f32?;
let transcript = pipeline.run?;
println!;
CLI flags
| Flag | Purpose |
|---|---|
--timestamps |
Structured WhisperTranscript |
--word-align dtw|wav2vec2 |
Word-level times |
--silero-vad |
Long-audio chunking via rlx-vad Silero |
--diarize |
Speaker labels (diarize feature) |
--max-region-batch N |
Batched region encode width |
--output PATH |
SRT / VTT / TSV / JSON (from extension or --output-format) |
Device routing
When --device metal (or CUDA for encoder):
| Stage | Typical device | Notes |
|---|---|---|
| Mel encoder | Metal / CUDA | whisper_encoder_device |
| Cross, prefill, decode | CPU | whisper_decoder_device — parity gate |
| DTW align-hidden | Same as encoder | Compiled graph through alignment layer |
Call WhisperRunner::prepare_pcm_geometry (or mel_frames_for_pcm on the builder) so encoder graphs match utterance length instead of padding to 30 s.
Performance (JFK, whisper-tiny, ~11 s)
Approximate timestamps+dtw on Apple Silicon (1 warmup run):
| Backend | ASR ms | Align ms | Total ms | RTF |
|---|---|---|---|---|
| Metal | ~3200–3400 | ~120–130 | ~3300–3600 | ~0.30–0.32 |
| CPU | ~3850 | ~585 | ~4400 | ~0.40 |
GPU DTW align-hidden replaces ~800 ms CPU decoder forward with ~120 ms Metal graph + batched QK.
Batched region decode
- Energy VAD (
transcribe_structured_vad): full batched cross + prefill + decode per chunk. - Silero VAD: batched encode; decode is serial when a chunk has multiple regions (correctness); single-region chunks use full batch decode.
- Batched greedy decode indexes logits with
dec_seq = prompt.len()on prefill, thendec_seq = 1on each decode step (batched_logits_row).
Features
| Feature | Enables |
|---|---|
tokenizer |
Greedy/beam decode, CLI --wav |
timestamps (default) |
Segment parse, pipeline, subtitle export |
word-dtw |
Cross-attention + DTW word alignment |
word-w2v |
Wav2Vec2 CTC forced alignment |
silero-vad |
Silero VAD chunking |
diarize |
ECAPA-TDNN speaker labels via rlx-diarize |
metal, cuda, … |
Forwarded to rlx-runtime |
Facade feature whisper-subtitles on rlx-models enables the full stack for examples and tests.
Tests
Related crates
rlx-wav2vec2-asr— CTC forced alignment (WhisperX-style)rlx-diarize— speaker embedding + clusteringrlx-vad— Silero VAD used by--silero-vad