Skip to content

Skip room-tone tail chunks; collapse punctuated repetition loops - #135

Merged
alexkroman merged 1 commit into
mainfrom
inference-output-guards
Oct 9, 2026
Merged

alexkroman merged 1 commit into
mainfrom
inference-output-guards

Conversation

@alexkroman

Copy link
Copy Markdown
Owner

Two inference-time fixes that came out of auditing the 2026-10-09 RunPod served eval (12 datasets × n=1000, plus full AMI / AMI-SDM / Loquacious / Earnings22 / GigaSpeech).

1. Quiet tail chunks hallucinate (audible_chunks)

Clips over 18 s are chunked (chunk_bounds). The tail chunk after the talker stops is room tone, and room tone passes is_silent's absolute 1e-5 RMS check. Decoded, it comes back as a memorized sentence or a stray word:

Clip Before After
CV 450 Her hair flowed down her back. The film was directed by the director of the same name. Her hair flowed down her back.
CV 533 It's usually customary to bring the money with you. The first of the series was "The Man Who Would Be King". …with you.
Loquacious 1311 …the old sculptor, Euphranor. Okay. …the old sculptor, Euphranor.
Earnings22 477 …the operational performance. The …the operational performance.

This costs about 0.7 WER on CommonVoice, which is the whole served-vs-local gap there (7.3 vs 6.6).

audible_chunks now empties a chunk when its loudest 100 ms frame is more than 30 dB below the clip's 95th-percentile frame. The empty chunk then transcribes as "" and never reaches the model. A one-chunk clip is never emptied.

Threshold, measured on the cached eval clips (datasets_cache/eval_samples, every clip over 18 s in the first 3,000 rows of 9 datasets, 957 chunks):

  • Noise-only chunks: ≤ −36 dB
  • Speech chunks: ≥ −17.5 dB

−30 dB leaves the wider margin on the speech side.

Real model run (MPS) on every clip where the gate fires:

  • 9 clips: 8 lose the hallucinated tail, 1 is unchanged.
  • No real word is dropped.

Not fixed: tails that contain real background speech (e.g. Loquacious 2209, CV 66). A level gate can't tell that apart from the target speaker.

2. Punctuated repetition loops (_truncate_repetitions)

The old rule matched repeats exactly, so loops the model punctuates got through. Example: "Yeah Yeah Yeah … Yeah. Yeah. Yeah," in GigaSpeech.

My first version ignored punctuation at 3 or more repeats. That hurt: 3–5 punctuated repeats are real speech ("No, no, no,", "Practice, practice, practice."), and collapsing them cost 40 errors over 47 rows. So the original rule is unchanged, and a second, punctuation-insensitive pass collapses only runs of 6 or more.

Replayed over all 53,755 served eval predictions:

  • 7 change, all of them loops.
  • Errors on those rows go from 124 to 102.

Refactor

The chunking helpers move to asr_processing.py, and stream_chunks moves to diarization.py next to pack_spans. This keeps asr_pipeline.py under the 600-line cap. Both files are already in the Hub bundle and in save_pretrained's copy list, and I checked that the flat-layout import works.

Not in this PR

Test plan

  • New unit tests: room-tone tail emptied, quiet word in the tail kept, single chunk never gated; punctuated loops collapse, short punctuated repeats are kept
  • Full suite: 1252 passed
  • Pre-commit gate (ruff, black, pyright, file-length, vulture, bandit)
  • Real-model A/B on the eval clips where the gate fires
  • Redeploy pod and re-run CV / Loquacious served eval

🤖 Generated with Claude Code

Clips over 18 s are chunked, and the tail chunk after the talker stops is
room tone that passes the digital-silence check (abs 1e-5 RMS). Decoded,
it comes back as a memorized sentence ("The film was directed by the
director of the same name.") or a stray "the"/"ok": ~0.7 WER on the
served CommonVoice eval. `audible_chunks` empties a chunk whose loudest
100 ms frame is 30 dB under the clip's 95th-percentile frame. On the
cached eval clips noise-only chunks sat at <= -36 dB and speech chunks
at >= -17.5 dB; on the 9 clips where it fires, 8 lose the hallucinated
tail and none loses a real word.

`_truncate_repetitions` missed loops the model punctuates ("Yeah Yeah
Yeah. Yeah. Yeah,"). Punctuation is now ignored for runs of 6+; at 3-5
punctuated repeats are real speech ("No, no, no,"), and collapsing those
cost 40 errors over 47 rows. Replayed over all 53,755 served eval
predictions: 7 change, all loops, 124 -> 102 errors on those rows.

The chunking helpers move to asr_processing (stream_chunks to
diarization, beside pack_spans) to keep asr_pipeline under the
file-length cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alexkroman
alexkroman merged commit c6cb9b7 into main Oct 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants