ASR fine-tuning (v0.71.32)

soup train with task: asr fine-tunes OpenAI Whisper speech-recognition models on your own audio, locally. Data is plain JSONL rows of {"audio": "clip.wav", "text": "the transcript"}: clips decode to 16 kHz mono log-mel input features, transcripts become the decoder labels, and the trainer wraps Hugging Face Seq2SeqTrainer + WhisperProcessor. whisper-tiny (39M) and whisper-base (74M) train on a 4 GB GPU.

Config

yaml
base: openai/whisper-tiny
task: asr
data:
  train: ./data/train.jsonl
  format: asr                 # rows: {"audio": "clip.wav", "text": "hello world"}
  audio_dir: ./data/audio     # audio paths resolve here (containment-checked)
training:
  epochs: 3
  lr: 1e-4
  batch_size: 2
  asr_language: en            # optional; pins + persists the decoder prefix
  asr_task: transcribe        # transcribe | translate
  asr_lora: true              # LoRA on q/v projections; default is full fine-tune
  lora: { r: 16, alpha: 32, target_modules: [q_proj, v_proj] }
output: ./out
bash
pip install 'soup-cli[train,audio]'
soup recipes use whisper-tiny-asr   # or whisper-base-asr / whisper-large-v3-asr
soup train

Config fields

FieldDefaultMeaning
asr_language(none)Decoder language prefix (e.g. en). Persists to an asr_generation.json sidecar next to the weights, so inference restores it automatically.
asr_tasktranscribetranscribe or translate. Also persisted to the sidecar.
asr_lorafalsetrue trains LoRA on the q/v projections instead of full fine-tuning.

The cross-validator requires backend: transformers (so mlx / unsloth are rejected) and footgun-rejects asr_* fields when the task is not asr; a separate trainer-side gate rejects a non-Whisper base before any weight download.

Inference + WER/CER

bash
soup infer --task asr --model ./out --input eval.jsonl --output preds.jsonl \
    --audio-dir ./data/audio [--asr-language en] [--asr-task transcribe]

--model loads a full Whisper model or a PEFT/LoRA adapter dir. Input rows are {"audio": path} with an optional "text" reference; when references are present, each output row carries transcription, wer and cer, plus a corpus WER summary (sum of edits over sum of reference words, not a mean of per-row rates). The metrics are pure-Python word- and char-level Levenshtein with no new dependency, and word accuracy (1 - WER) plugs into soup ship as a higher-is-better task metric, so the SHIP / DON'T-SHIP verdict works for speech models too.

WER/CER use a light normalizer (casefold, strip surrounding punctuation, collapse whitespace), deliberately not the full Whisper normalizer: good for before/after deltas, not leaderboard-comparable absolutes.

Recipes

RecipeBaseSizeStatus
whisper-tiny-asropenai/whisper-tiny39MLive, validated on a 4 GB RTX 3050
whisper-base-asropenai/whisper-base74MLive, fits a 4 GB GPU
whisper-large-v3-asropenai/whisper-large-v31.5BParse-tested; needs a 16 GB+ GPU

A smolvlm-256m-sft tiny-VLM recipe ships alongside (parse-tested, target_modules pinned to q/v); live vision SFT for Idefics3-style processors is tracked in issue #302.

Honesty

Proof-of-mechanism only. The live validation is a memorization run on a single RTX 3050: WER 1.000 to 0.000 and loss 7.2 to 0.0005 at 0.4 of 4 GB VRAM. That proves the loop trains end to end; real accent or domain gains need real audio. The release also fixed the hardware-fit gate mis-sizing Whisper checkpoints as 7B models, which would have wrongly blocked ASR training on consumer GPUs.

Security

Audio decodes only through the hardened loader (a soundfile pre-probe before read, symlink rejection, O_NOFOLLOW, byte caps), never through datasets auto-decode. data.audio_dir is containment-checked (realpath + commonpath); UNC paths and traversal are rejected. A missing [audio] extra, a bad audio path, or a non-Whisper base all fail with a friendly error before a GPU hour.

See also

  • Vision & Audio — the audio-understanding (Qwen2-Audio) and vision paths.
  • Modality II — TTS, the audio-out counterpart to ASR's audio-in.
  • soup ship — gate a speech model on word accuracy plus no forgetting.
  • Recipes — all 142 ready-made configs.