Vocal Burst Locator

A Whisper-based model that detects and localizes vocal bursts (laughs, coughs, sneezes, sighs, gasps, cries, screams, etc.) in audio, returning precise start/end timestamps for each event.

⭐ Start here: use model_v2.pt

The recommended default checkpoint is model_v2.pt (972 MB), fine-tuned on real in-the-wild audio. The original model.pt (v1) is trained on synthetic soundscapes only and is superseded β€” it is kept for reproducibility, documented under Previous version β€” v1.

⚠️ Two things are easy to get wrong, so they are stated up front:

  1. inference.py still auto-downloads model.pt when you do not pass a checkpoint. Pass model_v2.pt explicitly.
  2. inference.py's built-in post-processing defaults are still the v1-era values (threshold=0.65, merge_gap=0.3, min_dur=0.5). Pass the v2 values explicitly β€” they dominate the measured F1 (see below).

Recommended post-processing (v2)

threshold    = 0.50   # was 0.65 in v1
merge_gap    = 0.10   # was 0.30 in v1
min_duration = 0.10   # was 0.50 in v1   <-- the one that matters

Ground-truth bursts have a median duration of ~180 ms. A min_duration of 0.5 s therefore discards ~96 % of real bursts before matching. On one identical checkpoint, only changing post-processing moved event F1 from 0.243 to 0.598 β€” a larger effect than any training change made for v2. If you read older instructions in this card recommending 0.65 / 0.3 / 0.5, those are the v1 numbers and are not recommended any more.

Copy-pasteable usage

from huggingface_hub import hf_hub_download
from inference import load_model, detect_vocal_bursts   # inference.py from this repo

# 1. Download the recommended checkpoint
ckpt = hf_hub_download("laion/vocalburst-locator", "model_v2.pt")

# 2. Load it (v1 would be loaded if you omit `checkpoint`)
model, fe, device = load_model("cuda", checkpoint=ckpt)   # or "cpu"

# 3. Detect, with the v2 post-processing values
events = detect_vocal_bursts(
    "audio.mp3",
    model=model, fe=fe, device=device,
    threshold=0.50,
    merge_gap=0.10,
    min_dur=0.10,
)

for ev in events:
    print(f"{ev['start']:.2f}s - {ev['end']:.2f}s  (confidence: {ev['confidence']:.2f})")

Command line equivalent:

python inference.py audio.mp3 \
  --checkpoint "$(python -c 'from huggingface_hub import hf_hub_download; print(hf_hub_download("laion/vocalburst-locator","model_v2.pt"))')" \
  --threshold 0.50 --merge-gap 0.10 --min-dur 0.10 --device cuda

Raw state dict (if you build the model yourself β€” same WhisperSegmenter state dict as v1, 485 tensors, LoRA already merged):

import torch
sd = torch.load("model_v2.pt", map_location="cpu")
model.load_state_dict(sd)     # same keys as model.pt

Why v2 β€” measured on real audio

Re-measured on a held-out set of 992 real, in-the-wild expressive-speech clips, each checkpoint given a post-processing sweep to find its best possible operating point:

event F1 @ IoU 0.5 precision recall best threshold
model.pt (v1, synthetic) 0.152 0.469 0.207 0.80
model_v2.pt 0.607 0.678 0.669 0.50

4.0x higher F1 on real audio. Note also how v1 fails: it only reaches usable precision at threshold 0.80, where recall collapses to 0.21 β€” on real recordings it is very unsure, and buying precision costs it four fifths of the events. v2 operates at 0.50 with recall 0.67.

Which checkpoint to pick

Your audio Checkpoint
Expressive speech, in-the-wild (default choice) model_v2.pt
In-the-wild audio that also contains music, SFX or non-speech backgrounds model_v2_mixed.pt
Synthetic soundscapes / reproducing the original results model.pt (v1, superseded)

On real audio the two v2 weights are statistically indistinguishable; they differ only on the synthetic-soundscape domain. Both use the same post-processing values above. Details in the model_v2_mixed.pt section.

πŸ”— Ensemble: pair this detector with the captioner laion/vocalburst-captioning-whisper β€” locate bursts here, then caption each detected segment with that model. See the threshold study below.

Installation

pip install torch transformers soundfile librosa huggingface_hub

Expected output

Detected 3 vocal burst(s) in audio.mp3:

  1. 2.14s - 3.82s  (duration: 1.68s, confidence: 0.89)
  2. 8.50s - 9.12s  (duration: 0.62s, confidence: 0.74)
  3. 15.30s - 16.94s  (duration: 1.64s, confidence: 0.92)

JSON output (--json):

{
  "file": "audio.mp3",
  "events": [
    {"start": 2.14, "end": 3.82, "confidence": 0.89, "duration": 1.68},
    {"start": 8.5, "end": 9.12, "confidence": 0.74, "duration": 0.62},
    {"start": 15.3, "end": 16.94, "confidence": 0.92, "duration": 1.64}
  ]
}

Model Description

This model performs binary frame-level segmentation on audio: for each 20ms frame in a 30-second audio clip, it predicts whether a vocal burst is occurring. Post-processing then groups these frame-level predictions into discrete events with timestamps and confidence scores.

Architecture

Audio (16kHz, 30s) β†’ Whisper-small Encoder (LoRA rank-8 merged) β†’ 1500 frame embeddings
    β†’ Linear(768β†’384) + GELU + Dropout
    β†’ Conv1d(384, kernel=7) + GELU + Dropout   (temporal smoothing)
    β†’ Linear(384β†’1) β†’ sigmoid β†’ 1500 probabilities
    β†’ Post-processing β†’ [(start, end, confidence), ...]

The model uses OpenAI's Whisper-small encoder as the audio feature backbone. During training, the encoder was adapted using LoRA (rank 8, alpha 16) on the q_proj and v_proj attention matrices. The LoRA weights have been merged into the base weights, so no adapter library is needed at inference time. All three checkpoints (model.pt, model_v2.pt, model_v2_mixed.pt) share this architecture and load with identical code.

Files

File Size Description
model_v2.pt 972 MB Recommended. Fine-tuned on real in-the-wild expressive speech
model_v2_mixed.pt 972 MB v2 trained on a mix of real speech + synthetic soundscapes (keeps the synthetic domain)
model.pt 972 MB v1, synthetic-only training. Superseded β€” see Previous version
head_only.pt 5.3 MB v1 segmentation head weights only (use with your own Whisper-small encoder)
inference.py - Standalone inference script with CLI and Python API
train.py - Full training script (supports frozen/LoRA/fine-tuning modes)
generate_dataset.py - Synthetic training data generator
download_sources.py - Downloads source audio from HuggingFace datasets
config.json - Model configuration and training hyperparameters
vocalburst_threshold_report.html - Interactive ensemble threshold study report

Inference Parameters

Parameter Recommended (v2) inference.py built-in default Description
threshold 0.50 0.65 Detection confidence threshold (0-1). Higher = fewer false positives, lower = fewer missed events.
merge_gap 0.10 0.3 Merge predicted segments closer than this (seconds). Prevents a single event from being split into fragments.
min_dur 0.10 0.5 Discard predicted events shorter than this (seconds). The v1 default of 0.5 discards ~96 % of real bursts.
checkpoint model_v2.pt model.pt (auto-downloaded) Which weights to load.
device auto auto "cpu", "cuda", or "cuda:0" etc. Auto-detects GPU if available.

The "built-in default" column is what the script uses if you pass nothing; it has been left at the v1 values for backwards compatibility. Pass the recommended column explicitly.

Understanding Precision, Recall, and the Threshold Trade-off

Imagine the model is a security guard watching for vocal bursts. It has to make a decision for every moment of audio: "Is this a vocal burst, or not?"

There are four possible outcomes:

                        REALITY
                   Vocal Burst    Not a VB
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  MODEL    Yes   β”‚ True Pos βœ“  β”‚ False Pos βœ— β”‚  ← "False alarm"
  SAYS:          β”‚ (correct!)  β”‚ (oops)      β”‚
                 β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
           No    β”‚ False Neg βœ— β”‚ True Neg βœ“  β”‚  ← "Missed it"
                 β”‚ (missed!)   β”‚ (correct!)  β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Precision = Of everything the model flagged, how many were real? TP / (TP + FP)

    • High precision β†’ when the model says "vocal burst!", it's almost always right
    • Low precision β†’ lots of false alarms (the model is trigger-happy)
  • Recall = Of all real vocal bursts, how many did the model catch? TP / (TP + FN)

    • High recall β†’ the model rarely misses a real event
    • Low recall β†’ the model is too conservative, missing real events
  • F1 Score = The harmonic mean of precision and recall β€” balances both into one number.

How Each Parameter Affects Results

threshold β€” The confidence cutoff

The model outputs a confidence score (0 to 1) for every 20ms frame. The threshold decides: "How confident must the model be before we call it a vocal burst?"

low threshold   β†’  Model flags almost everything
                   βœ“ High recall (catches most VBs)
                   βœ— Low precision (many false alarms)
                   Think: paranoid security guard

high threshold  β†’  Model only flags when very sure
                   βœ“ High precision (almost no false alarms)
                   βœ— Low recall (misses quieter/ambiguous VBs)
                   Think: lazy security guard

For model_v2.pt the swept best operating point on real audio is 0.50. (For v1 on synthetic data it was 0.65; for v1 on real audio it was 0.80, where recall collapses β€” see Previous version.)

min_dur β€” Minimum event duration

After grouping confident frames into events, discard any event shorter than min_dur.

min_dur = 0.1s  β†’  Recommended for v2 on real audio
                   βœ“ Keeps short coughs/gasps and the ~180 ms median real burst
                   βœ— Slightly more short false positives

min_dur = 0.5s  β†’  The old v1 default
                   βœ“ Filters noise spikes in synthetic soundscapes
                   βœ— Discards ~96 % of real bursts

min_dur = 1.0s  β†’  Only keeps long events
                   βœ— Misses almost everything on real audio

This is the single most impactful knob. On synthetic soundscapes, mixed-in bursts are long (0.5–3 s) and a large min_dur cheaply removes false positives β€” which is why v1 shipped 0.5. On real recordings the ground-truth median burst is ~180 ms, so the same setting throws away the majority of true events.

merge_gap β€” Gap tolerance for merging

If two detected segments are separated by less than merge_gap, merge them into one event.

merge_gap = 0.0s  β†’  No merging. A laugh with a brief pause becomes 2 events.
                     Result: Over-counting (more events than expected)

merge_gap = 0.1s  β†’  Recommended for v2. Bridges frame-level dropouts without
                     swallowing neighbouring bursts.

merge_gap = 1.0s  β†’  Even 1-second gaps get bridged.
                     Result: Separate nearby events might merge into one big event

Because real bursts are short and can occur close together, a large merge_gap fuses distinct events; 0.10 s is the swept-best value for v2.

The Precision-Recall Trade-off (Why You Can't Have Both at 100%)

Making the model more cautious (↑ precision) always means it will miss more real events (↓ recall), and vice versa. You can't eliminate false positives without also losing some true positives.

             ← More conservative        More aggressive β†’

  Precision: β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘  (goes DOWN as you lower threshold)
  Recall:    β–‘β–‘β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ  (goes UP as you lower threshold)
                       ↑
               Sweet spot (F1 max)

Choose your trade-off based on your application:

  • Automatic subtitling: Prefer high precision (don't annotate noise as laughter)
  • Safety monitoring: Prefer high recall (don't miss a scream or cry for help)
  • Research/counting: Use balanced F1 (minimize both types of errors)

v2 β€” how it was trained

Same architecture, initialised from model.pt, then fine-tuned end-to-end (encoder unfrozen, encoder LR 1e-5, head LR 5e-4, linear schedule, BCE with pos_weight 2) on 98,296 real 30 s clips with CrisperWhisper-derived burst timestamps. An intermediate stage over ~1M additional windows was run and discarded β€” see below.

Post-processing matters more than the weights

The defaults published with v1 (threshold 0.65, merge_gap 0.3, min_duration 0.5) are badly mismatched to real data: ground-truth bursts have a median duration of 180 ms, so min_duration = 0.5 discards ~96 % of them before matching. On the identical checkpoint, sweeping post-processing moved event F1 from 0.243 to 0.598 β€” a larger effect than any training change we made. Recommended for v2:

threshold = 0.50      # was 0.65
merge_gap = 0.10      # was 0.30
min_duration = 0.10   # was 0.50  <-- the one that matters

A negative result worth recording

An intermediate fine-tuning stage over 1,044,713 windows cut from the same corpus hurt: F1 fell from 0.598 to 0.482. Cause: the window extractor kept only windows that contained at least one burst, so 100 % of that training set was positive. Without burst-free examples the detector learns that bursts are everywhere β€” precision fell from 0.649 to 0.578 and binary detection accuracy from 0.913 to 0.853. A subsequent stage on the balanced set recovered it to 0.607. If you train on your own data, keep negatives in.

model_v2_mixed.pt β€” broader domain coverage

A third weight, for the case where the audio is not only expressive speech. Same architecture and same loading code as the others.

model_v2.pt is fine-tuned on real expressive speech only and, in the process, forgot the synthetic-soundscape domain v1 was trained on β€” music beds, sound effects, non-speech backgrounds. model_v2_mixed.pt is trained on a mix: the regenerated v1 soundscape corpus (33,012 clips, 50 % burst-free by construction) plus 40,000 classifier-confirmed DramaBox clips.

Measured, each checkpoint at its own swept-best post-processing

real speech (992) real, relabelled held-out real (500) synthetic soundscapes
model.pt (v1) 0.162 0.170 0.186 0.740
model_v2.pt 0.607 0.607 0.625 0.513
model_v2_mixed.pt 0.597 0.609 0.617 0.726

Event F1 @ IoU 0.5.

Which to use. On real audio the two v2 weights are statistically indistinguishable β€” every difference sits inside the bootstrap confidence interval and the sign flips between validation sets. Do not read 0.607 vs 0.597 as a ranking. The one difference that is robust is the synthetic column: +0.21, CI [+0.16, +0.27].

  • annotating in-the-wild audio that includes music, SFX or non-speech β†’ model_v2_mixed.pt
  • expressive speech only, and you want the weight that has been in use longest β†’ model_v2.pt

Same post-processing recommendation for both: threshold 0.50, merge_gap 0.10, min_duration 0.10.

What did NOT work, so you don't repeat it

Three attempts to beat 0.607 on real audio failed. Training on 1,044,713 edge-case windows that were 100 % positive dropped F1 to 0.482; precision fell first, as a detector with no negatives learns that bursts are everywhere. A 100k positive / 100k negative "mirror" set β€” negatives made by excising the burst from the same clip β€” reached only 0.458, so simply restoring the positive/negative balance was not the fix either. The mix above is the first variant that does not lose ground, and it still does not gain any on real speech.

A hypothesis we tested and discarded: that the training labels were heavily contaminated, because a classifier pass rejected 50.41 % of the source burst detections. Controls showed that figure is mostly an artefact of the 300 ms cut length β€” feeding the same classifier 3,000 certainly real bursts truncated to 300 ms yields 51.3 % "no burst", against 13.7 % at full length. On the actual labels the rejection rate is 7.76 %. A paired control (identical clips and schedule, only the labels cleaned) moved F1 by βˆ’0.007 / +0.004 / +0.003 across three validation sets, every interval straddling zero. Label cleaning changed nothing measurable.

Honest limits

The real-audio validation sets are 992 and 500 clips, which cannot resolve differences below roughly Β±0.03. Their labels come from an ASR model, not from human annotation, so the achievable ceiling is unknown β€” a model cannot score above the labels' own agreement rate. Whether 0.61 is near that ceiling or far below it has not been measured.


Previous version β€” v1 (model.pt)

Superseded by model_v2.pt. Kept for reproducibility and for the synthetic-soundscape domain; on real in-the-wild audio it scores event F1 0.152 versus 0.607 for v2.

v1 performance (synthetic evaluation)

Evaluated on 300 held-out synthetic soundscapes with the v1 inference settings (threshold=0.65, merge_gap=0.3s, min_dur=0.5s):

Metric Value
Event F1 0.752
Event Precision 0.897
Event Recall 0.781
Binary Detection Accuracy 0.810
Frame Accuracy (all) 0.928

On that synthetic test set the model catches ~78% of vocal burst events with ~90% precision. That number does not transfer to real recordings β€” see the real-audio comparison.

v1 usage

from inference import load_model, detect_vocal_bursts

# omitting `checkpoint` auto-downloads model.pt (v1)
model, fe, device = load_model("cuda")
events = detect_vocal_bursts("audio.mp3", model=model, fe=fe, device=device)
python inference.py audio.mp3                       # v1 weights + v1 defaults
python inference.py audio.mp3 --checkpoint ./model.pt --threshold 0.7 --min-dur 0.3
python inference.py audio.mp3 --json

v1 threshold behaviour (validation set, synthetic)

Threshold Precision Recall F1 False Positives Missed Events
0.40 0.62 0.89 0.73 Many Few
0.65 0.90 0.78 0.75 Few Some
0.85 0.95 0.55 0.70 Very few Many

v1 parameter recipes (synthetic-era guidance)

Use Case threshold min_dur merge_gap What changes
Balanced (v1 default) 0.65 0.5 0.3 Good all-around on synthetic data
High precision (no false alarms) 0.80 0.7 0.3 ↑ precision, ↓ recall
High recall (catch everything) 0.45 0.2 0.5 ↑ recall, ↓ precision
Noisy audio (music, crowds) 0.75 0.6 0.3 Reduces noise-triggered FPs
Short events (coughs, gasps) 0.60 0.2 0.2 Catches brief events
Long events only (extended laughs) 0.65 1.0 0.5 Ignores anything <1s

These recipes were tuned on synthetic soundscapes. For real audio with model_v2.pt, start from 0.50 / 0.10 / 0.10.

Using head_only.pt (v1 head)

If you already have Whisper-small loaded or want to use a different Whisper variant:

import torch
from transformers import WhisperModel

# Load your own whisper encoder
whisper = WhisperModel.from_pretrained("openai/whisper-small")
encoder_out = whisper.encoder(input_features=mel_features).last_hidden_state  # [B, 1500, 768]

# Load just the segmentation head
head_sd = torch.load("head_only.pt", map_location="cpu")
# head_sd contains: proj.0.weight, proj.0.bias, temporal.0.weight, temporal.0.bias, out.weight, out.bias
# Apply: proj β†’ permute β†’ temporal β†’ permute β†’ out β†’ squeeze β†’ sigmoid

v1 experiment results

We compared frozen encoder, LoRA rank 2/4/8 with the v1 post-processing (threshold=0.65, merge_gap=0.3s, min_dur=0.5s, pos_weight=2):

Model Trainable Params Event F1 Precision Recall Binary Det
Frozen encoder 295K (0.12%) 0.589 0.786 0.645 0.733
LoRA rank-2 1.55M (0.64%) 0.734 0.886 0.768 0.803
LoRA rank-4 1.77M (0.73%) 0.744 0.878 0.794 0.807
LoRA rank-8 2.21M (0.91%) 0.752 0.897 0.781 0.810

Key findings:

  • Raising detection threshold from 0.5β†’0.65 and tightening post-processing doubled F1 with zero retraining (on synthetic data)
  • LoRA rank-8 provided 3.15Γ— improvement over the original baseline (F1: 0.239 β†’ 0.752)
  • Precision improved from 24% to 90% β€” false positives dropped by ~90%
  • Diminishing returns above rank 8; rank 4 may be the sweet spot for cost/performance

Vocal-burst captioning ensemble & detection-threshold study (v1 post-processing)

This detector is designed to be used as an ensemble with the fine-tuned captioner laion/vocalburst-captioning-whisper: the locator finds where vocal bursts occur (start/end timestamps); each detected segment is then cut and described by the captioner (Whisper-small fine-tuned on vocal-burst captions). Together they turn raw audio into timestamped, captioned vocal-burst events that feed the LAION Universal Audio Annotation Pipeline.

⚠️ This study was run with merge_gap = 0.3 s, min_dur = 0.5 s β€” the v1 post-processing. Its threshold recommendation (0.85–0.89) is tied to those settings and does not carry over to model_v2.pt, where the recommended operating point is threshold 0.50, merge_gap 0.10, min_duration 0.10.

How the study was run

We swept the detector's confidence threshold from 0.85 to 0.92 (1% steps) on 150 audio samples (clean-speech false-positive checks + clips with inserted bursts + isolated bursts), with merge_gap = 0.3 s, min_dur = 0.5 s. For every (sample Γ— threshold) the detector's segments were captioned by laion/vocalburst-captioning-whisper and the audio + (start, end, caption) list was sent to Gemini 3.1 Pro, which rated three axes 0–5 (5 = perfect): caption quality, timestamp accuracy, and completeness (do the detections cover ALL real vocal bursts, penalizing both misses and false positives). That is 1,200 independent LLM judgments; overall = mean of the three axes.

Results β€” average Gemini-3.1-Pro scores per threshold (ranked)

rank threshold overall completeness caption quality timestamp accuracy
πŸ₯‡ 0.88 3.475 3.11 3.24 4.07
πŸ₯ˆ 0.89 3.469 3.15 3.18 4.08
πŸ₯‰ 0.85 3.466 3.11 3.22 4.07
4 0.90 3.445 3.10 3.24 4.00
5 0.86 3.411 3.05 3.14 4.04
6 0.87 3.390 3.07 3.10 4.00
7 0.91 3.364 3.05 3.14 3.91
8 0.92 3.363 3.02 3.15 3.92

Findings: scores are tightly clustered across 0.85–0.92 (the detections change little in that band); threshold β‰ˆ 0.88 is the sweet spot (best overall). Timestamp accuracy is consistently strong (~4.0), caption quality is moderate (3.2), and **completeness is the weakest axis (3.0–3.15)** β€” it degrades at the highest thresholds (0.91–0.92) as real bursts start being missed.

πŸ“Š Full interactive report (stats table + audio players + predictions + per-clip Gemini scores for the top-3 thresholds): vocalburst_threshold_report.html.

Training

Full Pipeline (v1 synthetic recipe)

# 1. Download source audio (~15K vocal bursts, ~13K backgrounds)
python download_sources.py

# 2. Generate synthetic soundscapes (~33K samples)
python generate_dataset.py

# 3. Train with LoRA (best v1 configuration)
CUDA_VISIBLE_DEVICES=0 \
  FREEZE_ENCODER=1 LORA_RANK=8 LORA_ALPHA=16 \
  POS_WEIGHT=2 DET_THRESHOLD=0.65 POST_MERGE_GAP=0.3 POST_MIN_DUR=0.5 \
  EPOCHS=15 LR=5e-4 ENCODER_LR=2e-4 \
  python train.py

For a v2-style run on real audio, initialise from a checkpoint with INIT_WEIGHTS, unfreeze the encoder, and set the eval/post-processing variables to the v2 values (DET_THRESHOLD=0.5 POST_MERGE_GAP=0.1 POST_MIN_DUR=0.1) β€” otherwise the reported eval metrics will be dominated by the mismatched POST_MIN_DUR.

Training Configuration

The training script is controlled entirely via environment variables:

Variable Default Description
FREEZE_ENCODER 0 Set to 1 to freeze Whisper encoder (required for LoRA)
LORA_RANK 0 LoRA rank (0=disabled, 8=recommended)
LORA_ALPHA 0 LoRA alpha (0=auto: rankΓ—2)
POS_WEIGHT 4.0 BCE positive class weight (2.0 recommended for precision)
DET_THRESHOLD 0.5 Detection threshold for eval metrics
POST_MERGE_GAP 0.5 Post-processing merge gap (seconds)
POST_MIN_DUR 0.3 Post-processing min duration (seconds)
LR 2e-4 Head learning rate
ENCODER_LR 0 Encoder/LoRA learning rate (0=same as LR)
EPOCHS 6 Training epochs
MAX_BSZ 0 Max batch size cap (0=unlimited, auto-probed)
INIT_WEIGHTS - Path to checkpoint for weight initialization
RESUME_MODE none Resume training: none, latest, or best
DATA_DIR vb_dataset Path to training data
OUT_DIR vb_output Output directory for checkpoints and logs

Data Generation

The synthetic dataset generator creates audio soundscapes by mixing:

  • Vocal burst sources: ~15,680 clips from HuggingFace (laughs, coughs, sneezes, etc.)
  • Background sources: Music (5,000), AudioSet SFX (5,000), AudioSnippets (3,000)
  • Parameters: Random background type, 0-5 VBs per clip, varied SNR, up to 30s duration
  • Split: 50% positive (with VBs) / 50% negative (background only)

Each sample produces an .mp3 audio file and a .json metadata file:

{
    "events": [
        {"start_time": 3.21, "end_time": 4.85},
        {"start_time": 12.50, "end_time": 13.10}
    ],
    "duration_sec": 24.5,
    "bg_type": "music",
    "n_vocal_bursts": 2
}

Limitations

  • 30-second maximum: The model processes 30s clips. For longer audio, segment into overlapping 30s windows.
  • Vocal burst types: Trained primarily on laughs, coughs, sneezes, sighs, gasps, cries. May not generalize to all vocal burst types.
  • Frame resolution: 20ms per frame (50 fps). Event boundaries are accurate to Β±20ms.
  • Domain: model_v2.pt is fine-tuned on real expressive speech and has lost some of v1's synthetic-soundscape performance (0.513 vs 0.740 event F1 on synthetic); use model_v2_mixed.pt if music/SFX backgrounds matter.
  • Label provenance (v2): v2's real-audio training and validation labels come from an ASR model, not human annotation; the achievable ceiling is unknown.
  • Synthetic training data (v1): v1 was trained on synthetic mixtures only, which is why it scores event F1 0.152 on real in-the-wild clips.

Downstream note: classifier Slap Face false positives

When pairing this locator with laion/vocalburst-classifier-single in a detect-then-classify pipeline, note that the classifier over-predicts Slap Face as top-1 on in-the-wild speech. The recommended mitigation is to skip that label and take the runner-up class. See that model's README for details and a code snippet.

Citation

@misc{vocalburst-locator-2025,
    title={Vocal Burst Locator: Whisper-based Vocal Burst Segmentation},
    author={LAION},
    year={2025},
    publisher={HuggingFace},
    url={https://huggingface.co/laion/vocalburst-locator}
}

License

Apache 2.0

Downloads last month
61
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for laion/vocalburst-locator

Finetuned
(3675)
this model