Segment boundaries are systematically late at speech_pad_ms=0 (onset P50 ≈ +40 ms with a heavy tail to +1.4 s, offset P50 ≈ +50 ms); the two ends need corrections in opposite directions, so speech_pad_ms cannot compensate
Summary
When tagging keyword-spotting training data (multilingual headset recordings, 16 kHz), we measured get_speech_timestamps (non-streaming, ONNX) boundaries against an objective, annotation-free acoustic reference on 8,966 files. At the library-default-style setting speech_pad_ms=0:
| boundary | lag vs. objective acoustic boundary (P50) | P90 | max |
|---|---|---|---|
| onset | +39 to +43 ms (98-99% of files positive) | +130 to +140 ms | +1036 to +1415 ms |
| offset | +47 to +58 ms | +79 to +94 ms | — |
Both boundaries are late, but they need opposite corrections: recovering the onset requires extending the segment earlier (positive pad), while recovering the offset requires trimming the segment earlier (negative pad). speech_pad_ms moves both ends outwards symmetrically, so it can fix the onset only by making the offset error grow 1:1 (verified below: pad=50 ms reproduces a manual onset annotation within 4 samples while pushing the offset +49 ms further out).
Edit note (2026-09-18): the first version of this report defined the acoustic reference as the first/last envelope frame above floor+6 dB, which single-frame clicks contaminated (inflated onset P50 to ~+79 ms and produced a spurious heavy tail). All numbers above use the click-robust definition (first/last frame of a run of ≥3 consecutive frames, i.e. 15 ms, above floor+6 dB). Figures and the example audio are attached in a comment below.
Environment
- silero-vad:
torch.hub.load('snakers4/silero-vad', model='silero_vad', onnx=True), master branch cache (model filesilero_vad.onnx) - Python 3.11, PyTorch 2.1.1+cu121 (CPU inference)
- Params:
threshold=0.5, window_size_samples=512, speech_pad_ms=0, other args at library defaults - Audio: 16 kHz mono (one channel extracted from multichannel headset recordings), preprocessed with a 100 Hz high-pass and peak normalization (standard VAD preprocessing; the bias persists without it)
Single-file evidence (manual ground truth available)
One zh command utterance ("上一曲", 1.85 s; mono extract attached in the comment below). Manual annotated onset = sample 7908; objective energy onset (click-robust) = 8160; energy offset = 21520.
| threshold | speech_pad_ms | window | detected onset | onset vs. manual GT | detected offset | offset vs. energy offset |
|---|---|---|---|---|---|---|
| 0.5 | 0 | 512 | 8704 | +796 (+50 ms) | 21504 | −1 ms |
| 0.5 | 30 | 512 | 8224 | +316 (+20 ms) | 21984 | +29 ms |
| 0.5 | 50 | 512 | 7904 | −4 (≈ GT) | 22304 | +49 ms |
| 0.3 | 0 | 512 | 8704 | +796 (threshold does not move onset) | 22016 | +31 ms |
| 0.2 | 0 | 512 | 8192 | +284 | 22528 | +63 ms |
| 0.5 | 0 | 1024 | 8704 | +796 (window size does not move onset) | 21504 | −1 ms |
| 0.5 | 0 | 1536 | 8704 | +796 | 21504 | −1 ms |
Observations:
- Lowering
thresholdor changingwindow_size_samplesdoes not reliably recover the onset; onlyspeech_pad_msshifts it, and it shifts the offset outwards by the same amount (offset error grows from −1 ms to +49 ms as pad goes 0→50 ms). - For reference, FireRedVAD (DFSMN, FireRedTeam/FireRedVAD) on the same file errs in the opposite direction at the onset (7040, −54 ms) while also over-extending the offset (24160, +164 ms), i.e. boundary placement is model-specific and worth improving on both sides.
Large-scale evidence (n = 8,966, annotation-free)
Methodology: per file we compute a 5 ms RMS envelope of the preprocessed signal and estimate the noise floor as the 30th percentile of frame dB levels. The acoustic onset/offset are the first/last frame of a run of ≥3 consecutive frames (15 ms) above floor+6 dB; the run-length requirement rejects single-frame clicks (without it, a −45 dB one-frame click at sample 3200 of the example file masquerades as the onset). This reference is conservative: on the manually annotated file above it yields 8160 vs. manual 7908, i.e. the proxy is itself ~16 ms later than a human annotator, so the reported onset lag is if anything underestimated.
Results (zh headset commands, two loudness classes):
| class | n | onset lag P50 | onset lag P90 | onset lag max | offset lag P50 | offset lag P90 |
|---|---|---|---|---|---|---|
| comfortable | 300 | +43 ms | +140 ms | +1036 ms | +47 ms | +79 ms |
| soft | 8,666 | +39 ms | +130 ms | +1415 ms | +58 ms | +94 ms |
Onset lag is positive in 98-99% of files. The onset heavy tail (up to +1.4 s) corresponds to files where a weak initial syllable never raises the frame probability above threshold; examples available on request. (Detection recall itself is fine: only 5/8,671 soft files yielded no segment, so this report is not about misses.)
Minimal reproduction
import torch, soundfile as sf
model, utils = torch.hub.load('snakers4/silero-vad', model='silero_vad', onnx=True)
(get_speech_timestamps, _, _, _, _) = utils
wav, sr = sf.read("silero_issue_example_mono16k.wav", dtype="float32") # attached in comment
for pad in (0, 30, 50):
ts = get_speech_timestamps(wav, model, sampling_rate=sr,
threshold=0.5, window_size_samples=512,
speech_pad_ms=pad)
print(pad, ts[0]["start"], ts[-1]["end"])
# 0 -> 8704 21504 (onset +50 ms vs manual GT 7908)
# 30 -> 8224 21984
# 50 -> 7904 22304 (onset ≈ GT, offset +49 ms late)Questions for the maintainers
- Is the systematic lateness of both raw boundaries (onset P50 ~+40 ms, offset P50 ~+50 ms at pad=0) known and intended? The onset in particular appears to be emitted where frame probability crosses the threshold on soft consonant onsets, without back-tracing to the acoustic onset.
- Would you consider hysteresis-style back-tracing (extend segment start backwards while frame probability stays above a lower threshold, and trim the offset symmetrically), so that boundary placement no longer depends on
speech_pad_ms, which can only move both ends outwards? - For boundary-accurate tagging use cases (KWS/ASR data cutting, subtitle alignment), is there a recommended parameter set other than symmetric
speech_pad_ms?
Why this matters
VAD timestamps are widely used to cut/label training data for KWS and ASR and for subtitle alignment. A systematic +40-50 ms shift trims initial consonants and appends decay tails to every cut segment, and because the two ends need opposite corrections, the documented compensation (speech_pad_ms) necessarily corrupts one end while fixing the other.
Source: snakers4/silero-vad