Commit Graph
1 Commits
Author SHA1 Message Date
osobhandClaude Opus 4.7 209279c13e rtx-csm: Phase 13.9 — wav2vec2 candle port (slices 1+2+3, real ASR working)
Full port of facebook/wav2vec2-base-960h (94.4 M params, MIT) closing
the WhisperX-class word-alignment gap from the audio-ML survey. Same
staged-scaffolding pattern that worked for emotion2vec — but landed
slices 1+2+3 in one session.

src/wav2vec2.rs ships:
  - Wav2Vec2Config::base_960h
  - FeatureExtractor — 7 Conv1d (1→512, total stride 320). Layer 0
    uses GroupNorm with num_groups=num_channels=512 (HF's wav2vec2
    feat_extract_norm: "group"). Critical: state-dict key is
    layer_norm.* but the OP is GroupNorm — loading as LayerNorm
    produces empty CTC output.
  - FeatureProjection — LayerNorm(512) + Linear(512→768)
  - ConvPosEmbedding — kernel 128 grouped Conv1d, materialized at
    load time from upstream weight_g + weight_v (fairseq's weight_norm
    on dim=2; eps-guarded division for numerical stability)
  - Block — POST-norm transformer with separate Q/K/V (vs emotion2vec's
    fused QKV), uses (B*H, T, D) Metal 3D-matmul workaround from
    Phase 8.8 Moonshine
  - Encoder — pos_conv + initial LayerNorm + 12 Blocks
  - Wav2Vec2 top-level — load_from_safetensors via mmap'd VarBuilder
  - ctc_greedy_decode + VOCAB_960H constant for the 32-char alphabet

examples/wav2vec2_inspect.rs (slice 1): dumps tensor layout + config
examples/wav2vec2_smoke.rs (slice 3): real-weight load + ASR forward

Verified on Metal:
  loaded model in 0.28 s
  forward in 9 ms for 10.42 s audio (~1150× realtime)
  transcript: "HE HOPED THERE WOULD BE STEW FOR DINNER TURNIPS AND
              CARROTS AND BRUISED POTATOES AND FAT MUTTON PIECES TO
              BE LADLED OUT IN THICK PEPPERED FLOWER FAT AND SAUCE"

Numerical parity with upstream Python — the FLOWER-for-FLOUR typo is
the known wav2vec2-base-960h failure mode, matches HF reference exactly.

7 new unit tests; lib suite 127/127 (was 120).

Slice 4 remaining: Viterbi forced alignment given known transcript,
to emit (token, frame_start_ms, frame_end_ms) for word-boundary cuts.
The ASR path itself is now production-ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-28 03:33:35 -07:00