openslr/librispeech_asr
Viewer β’ Updated β’ 585k β’ 82.1k β’ 253
Voice activity detection for a realtime voice agent. For every 10ms of microphone audio, say whether a human is speaking. Must ignore background noise, coughs, laughter, door slams, keyboard, crying babies and other non-speech human sounds. Runs on-device next to the agent, streaming, in well under 1ms per frame.
A single-purpose System 1 model built with BYOSM: a JEPA-style encoder pretrained with LeJEPA and trained only for this task, with a calibrated
decision policy, shipped as a 0.10M-parameter ONNX bundle that runs on any CPU with onnxruntime.
| task | audio / frame (one decision every 10 ms) |
| labels | non_speech, speech |
| parameters | 101,458 |
| backbone | tiny-crnn Β· embedding dim 96 |
| objective | f1, primary suite ava |
| decision policy | hysteresis, threshold 0.425 (calibrated on ava's calib split) |
| CPU, streaming | 0.186 ms per 30 ms chunk, 1 thread (PyTorch; the ONNX bundle is faster) |
non_speech: silence, noise, music, and non-verbal human sounds (coughing, laughing, breathing, crying)speech: a frame inside an utterance of human speech, including pauses up to ~300ms inside an utteranceEvery model below, this one and the baselines, was scored by the same code on the same frozen test splits, with its decision policy calibrated on the same calib splits. Bold = this model.
| model | params | builtin f1 | ava f1 (primary) | builtin ROC-AUC | ava ROC-AUC |
|---|---|---|---|---|---|
| v3 (this model) | 0.10M | β | 0.8816 | β | 0.942 |
| v2 (BYOSM experiment) | 0.10M | β | 0.8763 | β | 0.939 |
| silero (baseline) | 0.55M | β | 0.8653 | β | 0.923 |
| v1 (BYOSM experiment) | 0.10M | β | 0.8485 | β | 0.900 |
| energy (baseline) | β | β | 0.7308 | β | 0.694 |
| suite | dataset | test items | f1 | 95% CI | precision | recall | ROC-AUC | avg precision | decision threshold |
|---|---|---|---|---|---|---|---|---|---|
| ava | nccratliri/vad-human-ava-speech | 20 | 0.8816 | 0.863-0.899 | 0.8546 | 0.9103 | 0.9424 | 0.9519 | 0.425 |
pip install huggingface_hub numpy onnxruntime soundfile
from huggingface_hub import snapshot_download
import sys
path = snapshot_download("bsye/byosm-vad")
sys.path.insert(0, path)
from byosm_rt import load
m = load(path)
import soundfile as sf
wav, sr = sf.read("clip.wav", dtype="float32") # 16 kHz mono
print(m.predict(wav)["segments"])
emb = m.encode(...) # the learned representation (JEPA-style), for probes / retrieval / other heads
s = m.stream()
for chunk in mic_chunks(): # float32 mono, any size
out = s.step(chunk) # {"probs": [...per 10ms...], "speaking": bool, "events": [{"type": "start"|"end", "t_s": ...}]}
python byosm_rt.py serve . --port 8800
# GET /v1/models Β· POST /v1/vad/predict Β· POST /v1/vad/encode
spec.yaml (included in this repo).openslr/librispeech_asr: role positiveashraq/esc50: role negativenccratliri/vad-human-ava-speech: role labeled, partition trainbyosm improve from the previous board):real-data-ava (from v1): ava: objective 0.848 vs silero 0.855, 0.046 below builtin. The model has never seen this domain; train on the source's train partition (hash-disjoint from the suite's calib/test files).utterance-labels (from v1): ava: calibration had to move the decision threshold to 0.20 (P=0.824, R=0.875) -> the suite's label convention differs from training's. Training labels only voiced frames (gaps > 60ms are negative); segment suites usually label whole utterances. Fill gaps up to 300ms in synthetic labels.manual (from v2): train.ema=true train.holdout_test=autogit clone https://github.com/bsye/BYOSM && cd BYOSM && pip install -e .
# put spec.yaml from this repo at specialists/vad/spec.yaml, then:
byosm build vad && byosm board vad && byosm export vad