Download parity.md from Raymxnd/Whisper-Vad-EncDec-ASMR-torch: direct link, hf CLI and curl.
- Browser
- Download file 5.54 kB
-
https://huggingface.co/Raymxnd/Whisper-Vad-EncDec-ASMR-torch/resolve/main/parity.md
- Command line
-
hf download hf://Raymxnd/Whisper-Vad-EncDec-ASMR-torch/parity.md
-
curl -L -o parity.md https://huggingface.co/Raymxnd/Whisper-Vad-EncDec-ASMR-torch/resolve/main/parity.md
Parity against the ONNX reference
A format conversion is only worth publishing if it is provably the same model. Comparing interval counts catches gross breakage and nothing else β every precision setting tested here reproduces all 830 intervals. So the check goes three levels deep: interval counts, then every interval boundary, then the downstream windows those boundaries actually feed.
Method
- Reference: the upstream ONNX model via
onnxruntime1.18, CPU execution provider, 4 worker threads, batch 1 (the export pinned its output to batch 1). - Candidate:
vad_torch.pyfrom this repo loadingmodel.safetensors, CUDA, batch 8. - Both backends are fed the identical preprocessed waveform, so the comparison isolates the model. Chunking (30 s), threshold (0.4, in logit space) and interval merging are the same code path for both.
- Material: 7 tracks, 6129.9 s (102.2 min) of 16 kHz audio, Japanese close-mic speech β much of it quiet or whispered, which is the acoustic case this model was tuned for and the one where a VAD's boundaries are least stable. 2299.1 s of it is speech, so the set is 37.5% active.
- Hardware: RTX 3070 Laptop (8 GB), Windows, torch 2.2.2+cu121.
Track identities are not published; they are numbered in source order. The set is a fixed, ordered corpus so the run is repeatable on the machine that has it.
Result: fp32, TF32 off
| track | audio | mix route | L/R corr | intervals (ref β cand) | boundaries exact |
|---|---|---|---|---|---|
| 01 | 333.7 s | mid | 0.78 | 70 β 70 | 140 / 140 |
| 02 | 728.6 s | mid-blend | 0.49 | 141 β 141 | 282 / 282 |
| 03 | 860.8 s | max-side | 0.10 | 142 β 142 | 284 / 284 |
| 04 | 1187.2 s | max-side | 0.28 | 130 β 130 | 260 / 260 |
| 05 | 621.3 s | mid-blend | 0.59 | 80 β 80 | 160 / 160 |
| 06 | 1151.1 s | max-side | 0.05 | 134 β 134 | 268 / 268 |
| 07 | 1247.3 s | max-side | 0.12 | 133 β 133 | 266 / 266 |
| total | 6129.9 s | 830 β 830 | 1660 / 1660 |
interval counts : identical on all 7 tracks (830 intervals)
boundaries : 1660 compared, 1660 exact (100.0%), worst 0.000s
ASR windows : 559 built, 559 identical (100.0%)
Bit-identical, not merely close. Worst boundary delta is 0.000 s β every one of the 1660 interval endpoints lands on the same 20 ms frame with the same value.
The L/R correlation column spans 0.05 to 0.78, so the set exercises genuinely different stereo material rather than seven takes of one condition.
Result: fp16
fp16 is 2.1Γ faster and is not the default. Why:
| track | boundaries moved | worst delta |
|---|---|---|
| 01 | 2 / 140 | 0.020 s |
| 02 | 3 / 282 | 0.060 s |
| 03 | 1 / 284 | 0.020 s |
| 04 | 1 / 260 | 0.040 s |
| 05 | 1 / 160 | 0.100 s |
| 06 | 2 / 268 | 0.220 s |
| 07 | 2 / 266 | 0.220 s |
| total | 12 / 1660 (99.3% exact) | 0.220 s |
interval counts : identical on every track (830 intervals)
boundaries : 1660 compared, 1648 exact (99.3%), worst 0.220s (11 frames)
ASR windows : 559 built, 8 of 559 moved (98.6% identical), worst 1.620s
Read the three rows in order and note that only the last one is alarming. Interval counts are perfect. Boundaries are 99.3% exact. But 12 moved boundaries become 8 changed ASR windows, because a boundary that shifts 0.220 s can cross a 10 s window-splitting threshold and hand ~1.6 s of audio to a different window β which changes what a downstream ASR model transcribes.
This is the argument for checking the consumer of the intervals rather than the intervals themselves. If nothing downstream of your VAD is sensitive to window placement, fp16 is a good trade.
TF32 is the other half of the default. Ampere and later run fp32 matmul and
convolution through TF32 unless told not to, dropping the mantissa to 10 bits.
With TF32 left on, fp32 lands at 99.8% exact boundaries and 2 of 559 windows
moved β better than fp16, still not exact. load_vad disables it when fp32 is
requested. It measured the same speed either way, so the fidelity is free.
Timing
VAD stage only, same 6129.9 s of audio, same machine:
| backend | VAD stage | speedup | vs. realtime |
|---|---|---|---|
| ONNX, CPU, 4 threads, batch 1 | 88.56 s | 1.0Γ | 69Γ |
| torch, CUDA, fp32, batch 8, TF32 off | 8.26 s | 10.7Γ | 742Γ |
| torch, CUDA, fp16, batch 8 | 3.89 s | 22.8Γ | 1572Γ |
Per-track VAD seconds, ONNX β fp32 β fp16:
| track | ONNX | fp32 | fp16 |
|---|---|---|---|
| 01 | 5.12 | 0.99 | 0.78 |
| 02 | 10.68 | 0.97 | 0.44 |
| 03 | 12.28 | 1.07 | 0.47 |
| 04 | 16.89 | 1.45 | 0.61 |
| 05 | 9.11 | 0.79 | 0.33 |
| 06 | 16.66 | 1.44 | 0.62 |
| 07 | 17.82 | 1.55 | 0.64 |
Two caveats on these figures. The ONNX side is CPU, because the dependency conflict described in the README is the reason this conversion exists β it is not a GPU-to-GPU comparison and does not claim to be. And track 01 barely improves (5.12 β 0.99) compared to the rest, because at 333.7 s it is short enough that fixed costs dominate; the ratio grows with track length.
Reproducing this
model.safetensors is checked against its source on conversion: all 136
tensors are read back out of the written file and compared bit-for-bit against
the arrays extracted from the ONNX graph. sha256 of the published file:
39e5e22218d89647afb926163a4ee5f7989e1cfe840d657c7cb226997b9e48e0
To re-derive the weights from scratch rather than trusting this repo, run
extract_weights.py against the upstream model.onnx and compare.