Model Card for Silero VAD v6 (IB-Robot)
Silero VAD v6 β a small streaming voice-activity detector β packaged for the IB-Robot framework. It consumes one 576-sample chunk plus a carried LSTM state and returns a per-frame speech probability and the next state. It is the gate in front of the STT stage: the wake word opens a session, this model decides where the utterance ends.
This revision replaces an incorrect model card. The previously published card on this repo was a copy of the ZipVoice-Distill card (title, TTS tags and
pipeline_tag: text-to-speech) and described a different model. See Changelog β the 310P artifact was also corrected.
Deployments
| deployment | backend | artifact | notes |
|---|---|---|---|
ascend_310p |
Ascend ACL (Ascend310P1) | silero_vad_v6_310p_mixed16.om |
recommended, mixed-precision build |
ascend_310b |
Ascend ACL (Ascend310B1) | silero_vad_v6_310b_fp16.om |
310B board-side build |
torch_cpu |
ONNX Runtime CPU | assets/silero_vad.onnx |
host-side, dynamic shapes, takes an sr input |
Two further 310P1 builds ship in the repo without their own deployment entry, matching the convention across this organisation that one hardware target carries one deployment and the precision variant lives in the filename:
| file | ATC precision flag | notes |
|---|---|---|
silero_vad_v6_310p_fp16.om |
--precision_mode_v2=fp16 |
pure fp16 build |
silero_vad_v6_310p.om |
--precision_mode=allow_mix_precision |
a second mixed-precision mode; not a true fp32 baseline, which would need --precision_mode=must_keep_origin_dtype |
Both are declared in bundle.files and load by pointing an ACL session at the
file directly. Accuracy for all three is reported below; the short version is
that they differ by ~1e-3 in carried state and by nothing that reaches the VAD
decision.
Shared contract: tensor_model/silero_vad/vad
(host.silero.audio [1,576] + host.silero.sample_rate [] -> host.silero.prob [1,1]),
preprocessing mono-16khz-float32-chunk576-lstm-state-v1, output
speech-probability-float32-per-frame-v1.
Tensor contract
All four OM builds are compiled to fixed shapes and drop the sr input
(they are 16 kHz only):
inputs input float32 [1, 576] 576 = 512-sample frame + 64-sample left context
state float32 [2, 1, 128] carried LSTM state, zeros at stream start
outputs output float32 [1, 1] speech probability in [0, 1]
stateN float32 [2, 1, 128] feed back as `state` on the next chunk
The caller advances by frame_size = 512 samples per step and keeps the
trailing 64 samples as the next chunk's left context. state must be
carried across chunks; resetting it every chunk changes the output.
assets/silero_vad.onnx (the torch_cpu deployment) is the dynamic-shape
upstream export and takes a third input sr (int64 scalar); pass 16000.
Repository Structure
inference_manifest.jsonβ deployment routing (schema v3)assets/adapter.jsonβ adapter identity (silero_vad/vad)assets/silero_vad.onnxβ upstream dynamic-shape ONNX exportassets/silero_vad_openvino_16k_sim.onnxβ the 16 kHz-specialised, shape-fixed, onnx-simplified fp32 graph that the OMs were actually compiled from, and the reference the accuracy numbers below are measured againstartifacts/ascend/ascend_310p/*.omβ three Ascend 310P1 buildsartifacts/ascend_310b/*.omβ Ascend 310B1 build
Source Model
Upstream is Silero VAD v6.2. The manifest's logical revision is
silero-vad@v6-openvino-16k: it names the 16 kHz OpenVINO graph the OMs are
actually compiled from, not the upstream release tag.
assets/silero_vad.onnx is byte-identical to the file shipped in the
upstream repository at tags v6.2 and v6.2.1
(src/silero_vad/data/silero_vad.onnx, verified by sha256):
| file | bytes | sha256 | upstream |
|---|---|---|---|
assets/silero_vad.onnx |
2,327,524 | 1a153a22f4509e292a94e67d6f9b85e8deb25b4988682b7e174c65279d8788e3 |
snakers4/silero-vad@v6.2 β identical bytes |
assets/silero_vad_openvino_16k_sim.onnx |
1,251,290 | 94b26dfea7b8fdfb2524e291a3a7014be9dbf336c341af35fa48998892e92eb2 |
derived from silero_vad_openvino_16k.onnx (see below) |
(The same file at v6.0/v6.1 has sha256 597d30b3β¦, so this bundle is
specifically β₯ v6.2.)
assets/silero_vad_openvino_16k_sim.onnx is the 16 kHz-specialised,
shape-fixed graph the OMs were actually compiled from β sr folded away and
[1,576] / [2,1,128] pinned, which is what ATC requires. It is derived from
upstream src/silero_vad/data/silero_vad_openvino_16k.onnx
(commit 1a26f187,
"add openvino model", 1,288,203 bytes,
sha256 7776b81ad1b0350c15d7f1555943b9232eb53e9ca5d989c6d0cea9ebc8664d87),
with the LSTM lowered to MatMul and the graph simplified: 167 nodes with 98
inline Constant tensors become 32 nodes with 27 initializers. Both graphs
report producer_name: spox, opset 16, and the identical IO signature.
The derivation is verified at weight level, not asserted:
- 17 of our 27 initializers are bit-identical to an upstream
Constant; - the remaining ones match after removing a leading unit axis, except the two LSTM weight matrices and the bias;
- each
(1,512,128)LSTM matrix is an exact 128-row gate-block permutation of its upstream(512,128)counterpart β the same permutation[0,2,3,1]for both, i.e. the ONNX-LSTM gate order rewritten for the fused MatMul form, with every value preserved; - the
(1,1024)bias is the concatenation of the two upstream(512,)biases.
No upstream weight is altered; the transformation is structural only.
Compiled artifacts (ATC, --soc_version=Ascend310P1 unless noted):
| file | bytes | sha256 |
|---|---|---|
silero_vad_v6_310p_mixed16.om |
2,993,746 | e53992ea55de81900f236220b951a2e595d134ddbb7f4ee6292b6b1055e5cc28 |
silero_vad_v6_310p_fp16.om |
2,975,416 | 4ac1d447ab95afd99f473d25c73e80a164f436cfc52959964b39ecde5b1c1446 |
silero_vad_v6_310p.om |
2,993,101 | 808c426f6dcfbce243c90d618c8dda8680d4c39496a18aed06b51fbb1537dd3a |
silero_vad_v6_310b_fp16.om (Ascend310B1) |
3,000,931 | 74893fe18a9258b73c53e4d46f540ed1722fc4f632dbb2bc33a975c55e21a694 |
Validation
Measured on a real Ascend 310P1, ONNX Runtime fp32 reference and OM running on the same board.
Streaming β 20 consecutive chunks with the OM's own stateN fed back:
output cosine min 1.000000 max 1.000000
stateN cosine min 0.999999 max 1.000000
first chunk 12.25 ms
steady state 3.10 ms mean
Single-step, five synthetic inputs (threshold_cosine = 0.999), on
silero_vad_v6_310p_mixed16.om:
| case | input | output (om / ref) | stateN cosine | verdict |
|---|---|---|---|---|
| silence | zeros | 0.00186 / 0.00167 | 0.999379 | pass |
| noise | gaussian Γ0.1 | 0.01610 / 0.01612 | 1.000000 | pass |
| tone160 | 160 Hz Γ0.2 | 0.21277 / 0.19426 | 0.999641 | pass |
| speech_like | mixed tones + noise | 0.09076 / 0.09085 | 1.000000 | pass |
| loud | 440 Hz Γ5.0 | 0.00067 / 0.03803 | 0.338508 | fail |
The suite reports all_passed: false because of loud. Two things about that
case are worth stating precisely rather than leaving as a bare failure:
- Its input is outside the model's domain.
loudis a sine at amplitude 5.0. Audio decoded from int16 PCM is bounded in [-1, 1], so no real capture path β including the robot's β can produce this input. It is a synthetic overflow probe, not a reachable operating point. - The reported
output cosine = 1.000000for every case is a degenerate metric, not evidence of accuracy: the output is a single scalar[1,1], and the cosine of two 1-element vectors of the same sign is always exactly 1. The meaningful output column is the om/ref pair above. On the four in-domain cases those agree to β€0.019 absolute (worst case tone160); onloudthey do not (0.0007 vs 0.038), and the carried state diverges hard βstateNcosine 0.34 with max_abs 1.9995, i.e. a value saturated to +1 in one graph and β1 in the other, which is the signature of a fp16 range overflow inside the LSTM.
So the practical reading is: the four in-domain cases pass and the one failure is an out-of-domain input.
Full-scale / clipping retest, all three precision builds
The gap left by the suite above β does a real, reachable, full-scale input
break it? β has since been measured on the 310P1. Five in-domain worst cases,
each run against all three precision builds, ONNX Runtime fp32 as reference,
judged by absolute output error (β€0.02, well inside the 0.5 decision
threshold) and stateN cosine (β₯0.999):
| case | input | output (om / ref) | abs err | stateN cosine | verdict |
|---|---|---|---|---|---|
| fullscale_sine | 440 Hz Γ1.0 | 0.00410 / 0.00375 | 3.5e-4 | 0.999745 | pass |
| clipped_sine | 440 Hz Γ3.0 hard-clipped to Β±1 | 0.00368 / 0.00365 | 3.2e-5 | 0.999993 | pass |
| fullscale_noise | gaussian Γ0.5 clipped to Β±1 | 0.00329 / 0.00328 | 4.8e-6 | 0.999999 | pass |
| step | DC step 0 β 1.0 | 0.00080 / 0.00080 | 3.0e-6 | 0.999998 | pass |
| fullscale_warmstate | 440 Hz Γ1.0, non-zero initial state | 0.00871 / 0.00850 | 2.1e-4 | 0.999832 | pass |
| loud Γ5.0 | unreachable, kept for reference | 0.00067 / 0.03803 | 3.7e-2 | 0.338508 | out of domain |
Clipping is not a problem. The hardest reachable input β a hard-clipped sine, which is what an overloaded microphone actually produces β is the second most accurate case in the table. The suspicion recorded in earlier revisions of this card, that full-scale input might sit close to an overflow, is not borne out.
The out-of-domain divergence is not a precision problem. On the amplitude-5
case the fp32 build diverges from the ONNX reference by exactly the same
0.0374, with the same stateN cosine 0.3385, as mixed16 and fp16. If this
were the fp16 range overflow that earlier revisions of this card assumed, the
fp32 build would have fixed it. It does not, so the cause is in the
ATC-compiled graph, not in storage precision.
How much do the three builds actually differ? Over 50 randomised in-domain inputs (random amplitude 0.01β1.0, random non-zero initial state):
| pair | output identical | state identical | state max abs diff |
|---|---|---|---|
fp32 vs mixed16 |
yes, bit-exact on all 50 | no | 4.9e-4 |
fp16 vs mixed16 |
no | no | 9.8e-4 |
So the builds are not interchangeable bit-for-bit, but they differ by ~1e-3
in the carried state and by nothing that reaches the VAD decision (threshold
0.5, in-domain output error β€3.5e-4 against the fp32 ONNX reference for every
build). Choose a build on size and latency, not on accuracy β and note
that the allow_mix_precision build buys no extra headroom on the loud case.
A caveat on the labels: neither extra build is a true fp32 reference.
silero_vad_v6_310p.om was compiled with
--precision_mode=allow_mix_precision, so the "fp32 vs mixed16 is
bit-exact" row above compares two mixed-precision modes, and does not by
itself show that reducing precision is lossless. The evidence for that is the
comparison against the fp32 ONNX reference in the tables above.
Usage
Select a deployment through the IB-Robot unified inference runtime:
from inference_manifest import load_inference_manifest
validated = load_inference_manifest("models/silero-vad", "ascend_310p")
Per chunk: feed input and the carried state, read output as the speech
probability, and store stateN as the next state. Zero the state at the
start of each stream.
Changelog
revision 2
- Replaced the model card, which previously described ZipVoice-Distill.
- Corrected the 310P artifact. The file published as
silero_vad_v6_310p_mixed16.omhad sha2564ac1d447β¦, which is the fp16 build, not the mixed16 build. All three 310P1 builds are now shipped under their own names, each listed with its sha256, so the precision variant in use is unambiguous. Anyone who pinned the old sha256 was running fp16. - Added
assets/silero_vad_openvino_16k_sim.onnx, the graph the OMs were compiled from β previously the bundle shipped only the dynamic-shape ONNX, which cannot reproduce the OMs. - Kept all three 310P1 builds in the repo, declared in
bundle.files, with their ATC precision flags documented. They do not get separate deployment entries: every other model in this organisation exposes exactly one deployment per hardware target and distinguishes builds by filename.
License
Code and packaging: Apache-2.0. Silero VAD weights follow the upstream snakers4/silero-vad license (MIT).
Citation
@misc{Silero VAD,
author = {Silero Team},
title = {Silero VAD: pre-trained enterprise-grade Voice Activity Detector (VAD), Number Detector and Language Classifier},
year = {2024},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/snakers4/silero-vad}},
commit = {be95df9152c0d7618fa1edfeb296fc3dae32376f}
}
@software{ib_robot,
title = {IB-Robot: Intelligence Boom Robot},
url = {https://atomgit.com/openeuler/IB_Robot},
license = {Apache-2.0}
}