CoolFace
Modelpublic

Darveht/zenvion-voice-detector-v0.4

sourceHugging Faceapache-2.0updated 18d agoView on Hugging Face
2likes53downloads
Model Card

πŸŽ™οΈ Zenvion Voice Detector v0.4

Multi-task voice analysis model β€” 8 tasks in a single forward pass. Detects speech activity, gender, emotion, language, age, acoustic noise type, conversational intent, and accent simultaneously from raw audio in real time.

πŸš€ [Try the live demo β†’](https://huggingface.co/spaces/Darveht/zenvion-voice-detector-demo)


πŸ“‹ Table of Contents

  1. 1.Overview
  2. 2.Tasks & Labels
  3. 3.Performance Benchmarks
  4. 4.Quick Start
  5. 5.Installation
  6. 6.Usage Examples
  7. 7.API Reference
  8. 8.Architecture
  9. 9.Training Details
  10. 10.Limitations & Bias
  11. 11.Changelog
  12. 12.Citation
  13. 13.License

Overview

Zenvion Voice Detector v0.4 is a multi-task speech analysis system built on top of [facebook/wav2vec2-base-960h](https://huggingface.co/facebook/wav2vec2-base-960h). A single forward pass produces 8 independent classification outputs, making it efficient for audio pipelines.

FeatureDetail
Base modelfacebook/wav2vec2-base-960h
InputRaw audio waveform (16 kHz, mono)
Output heads8 simultaneous classification tasks
Languages supported50
Min audio duration0.1 s
Max recommended30 s
DeviceCPU + GPU (CUDA / MPS)
PrecisionFP32 / FP16
LicenseApache 2.0

Tasks & Labels

#TaskClassesDescription
1VADSPEECH / NO_SPEECHIs a human speaking?
2GenderMALE / FEMALE / UNKNOWNSpeaker gender
3EmotionANGER / DISGUST / FEAR / HAPPY / NEUTRAL / SAD / SURPRISE / CALM8-class emotion
4Language50 languagesen, es, fr, de, zh, ja, ar, hi …
5AgeCHILD / TEEN / YOUNGADULT / ADULT / MIDDLEAGED / SENIORAge group
6NoiseCLEAN / BABBLE / MUSIC / TRAFFIC / NOISE_OTHERAcoustic environment
7Intent15 classesConversational intent (COMMAND / QUESTION / STATEMENT / … / INTENT_OTHER)
8Accent20 classesRegional accent (… / ACCENT_OTHER)

Full label indexes are in label_mapping.json.


Performance Benchmarks

⚠️ The metrics below are the numbers published by the model author. They are marked verified: false in the model card and have not been independently verified. The checkpoint currently shipped contains a pretrained backbone with freshly initialised task heads β€” run evaluation.py on your own data before relying on these figures.

Voice Activity Detection (VAD)

DatasetAccuracyF1AUC-ROCEER
CommonVoice 16.1 (test)96.8%96.4%98.5%3.9%
FLEURS (test)95.9%95.2%97.8%4.3%
VoxPopuli (test)96.1%95.8%98.1%4.1%
Average96.2%95.8%98.1%4.1%

Emotion Recognition

DatasetAccuracyWeighted F1
RAVDESS (test split)88.2%87.6%
CREMA-D (test split)83.4%82.1%
IEMOCAP (test split)81.9%80.7%
Average84.7%83.1%

Language Identification (50 languages)

DatasetTop-1 AccTop-3 Acc
FLEURS (test)91.3%97.2%
CommonVoice 16.1 (test)90.8%96.9%

Gender Classification

DatasetAccuracyF1 (macro)
VoxCeleb2 (test)94.1%93.8%
CommonVoice 16.193.7%93.2%

Quick Start

Using Hugging Face Inference API

python
import requests

API_URL = "https://api-inference.huggingface.co/models/Darveht/zenvion-voice-detector-v0.4"
headers = {"Authorization": "Bearer YOUR_HF_TOKEN"}

with open("audio.wav", "rb") as f:
    data = f.read()

response = requests.post(API_URL, headers=headers, data=data)
print(response.json())

Using transformers pipeline

python
from transformers import pipeline

pipe = pipeline(
    "audio-classification",
    model="Darveht/zenvion-voice-detector-v0.4",
    trust_remote_code=True,
)
result = pipe("audio.wav")
print(result)

Using the bundled ZenvionPipeline

python
from inference import ZenvionPipeline

pipe = ZenvionPipeline(
    model_id="Darveht/zenvion-voice-detector-v0.4",
    device="cpu",   # or "cuda"
    half_precision=False,  # True for FP16 on CUDA
)

result = pipe("path/to/audio.wav")
print(result)
# {
#   "vad":      {"label": "SPEECH",   "score": 0.982},
#   "gender":   {"label": "MALE",     "score": 0.871},
#   "emotion":  {"label": "NEUTRAL",  "score": 0.763},
#   "language": {"label": "en",       "score": 0.941},
#   "age":      {"label": "ADULT",    "score": 0.802},
#   "noise":    {"label": "CLEAN",    "score": 0.913},
#   "intent":   {"label": "STATEMENT","score": 0.688},
#   "accent":   {"label": "AMERICAN", "score": 0.754},
# }

Installation

bash
pip install -r requirements.txt

Minimum dependencies:

torch>=2.1.0
transformers>=4.37.0
torchaudio>=2.1.0
librosa>=0.10.0
soundfile>=0.12.1
numpy>=1.24.0

Usage Examples

Batch Processing

python
from inference import ZenvionPipeline
from pathlib import Path

pipe = ZenvionPipeline()

audio_files = list(Path("audio_dir").glob("*.wav"))
for f in audio_files:
    res = pipe(str(f))
    print(f"{f.name}: {res['vad']['label']} | {res['emotion']['label']} | {res['language']['label']}")

GPU Inference with FP16

python
from inference import ZenvionPipeline

pipe = ZenvionPipeline(device="cuda", half_precision=True)
result = pipe("audio.wav")

Streaming / Real-time (chunk-based)

python
import numpy as np
from inference import ZenvionPipeline

pipe = ZenvionPipeline()
SAMPLE_RATE = 16000
CHUNK_S = 2  # 2-second windows

# numpy/tensor inputs are expected at 16 kHz mono
chunk = np.random.randn(SAMPLE_RATE * CHUNK_S).astype(np.float32)
result = pipe(chunk)
print(result)

Run only specific tasks

python
from inference import ZenvionPipeline

pipe = ZenvionPipeline(tasks=["vad", "emotion", "language"])
result = pipe("audio.wav")

Using with soundfile

python
import soundfile as sf
import numpy as np
from inference import ZenvionPipeline

pipe = ZenvionPipeline()
audio, sr = sf.read("audio.wav")
if audio.ndim > 1:
    audio = audio.mean(axis=1)
# NOTE: array inputs are expected at 16 kHz mono; resample first if needed,
# e.g. with librosa.resample(audio, orig_sr=sr, target_sr=16000)
result = pipe(audio.astype(np.float32))

API Reference

ZenvionPipeline

python
ZenvionPipeline(
    model_id: str = "Darveht/zenvion-voice-detector-v0.4",
    device: Optional[str] = None,  # auto-detects cuda/cpu
    tasks: Optional[List[str]] = None,  # subset of the 8 tasks; None = all
    half_precision: bool = False,  # FP16 (CUDA only)
    allow_random_init: bool = False,  # True: run with random weights if the checkpoint is missing
)
__call__(audio, return_all_scores=False)
ArgumentTypeDefaultDescription
audiostr or np.ndarray or torch.Tensor or listβ€”File path, array/tensor (16 kHz mono), or a batch list
return_all_scoresboolFalseInclude per-class probabilities for every task

Returns: dict[str, dict] β€” one entry per task with label (str) and score (float 0–1).

ZenvionConfig

python
from config_class import ZenvionConfig

cfg = ZenvionConfig.from_pretrained("Darveht/zenvion-voice-detector-v0.4")
print(cfg.num_labels_emotion)   # 8
print(cfg.num_labels_language)  # 50
print(cfg.num_labels)           # 109 (total across all tasks)

Architecture

Input: raw audio (16 kHz mono)
       |
       v
[Wav2Vec2 Encoder] β€” 12 transformer layers, 768-dim hidden
       |
       v  (learned weighted sum of all 13 hidden states, softmax-normalised)
[AttentivePooling] β€” attention-weighted temporal pooling -> 768-dim
       |
   +---+--------------------------------------------+
   v    v       v       v    v     v     v    v
 VAD Gender Emotion  Lang  Age  Noise  Int  Acc
  2    3      8      50    6     5    15   20   <- output classes (109 total)
  • β€”Total parameters: ~95 M (wav2vec2-base) + ~1.6 M (layer weights, pooling, 8 heads)
  • β€”Inference speed (CPU): ~180 ms per 2-second clip
  • β€”Inference speed (A100 GPU): ~12 ms per 2-second clip

Training Details

Data

DatasetHoursTasks
CommonVoice 16.117,600+VAD, Language, Accent
FLEURS4,000+VAD, Language
VoxPopuli1,800+VAD, Language
VoxCeleb / VoxCeleb22,400+Gender, Speaker
RAVDESS + CREMA-D + SAVEE + TESS + IEMOCAP500+Emotion
GigaSpeech10,000+VAD, Noise
LibriSpeech + LibriLight60,000+VAD
Total~96,300+ hoursβ€”

Hyperparameters

ParameterValue
OptimizerAdamW
Learning rate (backbone)1e-4
Learning rate (heads)5e-4
LR scheduleCosine with warmup
Warmup steps2,000
Batch size32
Gradient accumulation4
Epochs15
FP16Yes
Gradient clipping1.0
Weight decay0.01
LossWeighted CrossEntropy per head

Augmentations

  • β€”Speed perturbation (0.9Γ— – 1.1Γ—)
  • β€”Additive noise (SNR 5 – 30 dB)
  • β€”Room impulse response (RIR) convolution
  • β€”Codec simulation (telephone, mp3)
  • β€”Random gain (βˆ’6 to +6 dB)
  • β€”Time masking (SpecAugment-style)

Limitations & Bias

  • β€”Accent detection is English-centric; accuracy drops significantly for non-English accents.
  • β€”Emotion models trained on acted speech (RAVDESS, CREMA-D) may underperform on spontaneous conversational emotion.
  • β€”Age estimation is coarse (6 buckets) and may be biased toward training demographics.
  • β€”Gender outputs only MALE / FEMALE / UNKNOWN; does not capture the full spectrum of gender expression.
  • β€”Language ID accuracy varies: high for European languages (>95%), lower for low-resource languages such as Tagalog or Malay (~85%).
  • β€”Min duration: clips shorter than 0.5 s may produce unreliable outputs.
  • β€”Music / non-speech: the model may output unpredictable emotion or language labels on pure music β€” check VAD output first.

Changelog

v0.4.1 β€” 2026-09-09 (code & config fixes)

  • β€”Critical β€” weight wipe fixed: post_init() β†’ init_weights() was silently re-initialising the pretrained wav2vec2 backbone on every model construction, destroying the pretrained weights. The backbone is now protected via an _init_weights() override (transformers 4.x) and _is_hf_initialized marking (transformers 5.x); verified byte-identical against facebook/wav2vec2-base-960h.
  • β€”First real checkpoint: the repo previously shipped no weights at all (model.safetensors / pytorch_model.bin were missing), so from_pretrained() could not load a working model. Added model.safetensors with the pretrained backbone + freshly initialised task heads (heads still need training β€” see train.py).
  • β€”Crash fix: forward() passed logits= to ZenvionOutput, which had no such field (TypeError). Field added; logits is the [B, 109] concat.
  • β€”Label maps fixed: config.json had three different classes all named OTHER (noise/intent/accent), collapsing label2id from 109 to 107 entries. Renamed to NOISE_OTHER / INTENT_OTHER / ACCENT_OTHER; 109/109 consistent. ZenvionConfig no longer overwrites num_labels=109 with 2, and normalises id2label keys to ints.
  • β€”NaN guards: AttentivePooling no longer returns NaN on fully-masked rows; multi-task loss skips tasks whose labels are all -100 (was NaN).
  • β€”`predict()` now decodes all 8 tasks (was 5) and honours threshold.
  • β€”`inference.py`: removed the silent fallback to random weights (now raises unless allow_random_init=True); validates task names, empty audio, shapes, and min/max duration; the final partial VAD window is analysed instead of dropped.
  • β€”`train.py`: --amp/--no-amp flags; scheduler is rebuilt when the optimizer is recreated at unfreeze (was bound to the discarded optimizer); global_step now increments; leftover gradient-accumulation steps are applied at epoch end; AMP is CUDA-only; gradient loss is scaled by the accumulation factor; resuming a post-unfreeze checkpoint unfreezes first so optimizer parameter groups line up, and training continues at the next epoch.
  • β€”`masked_spec_embed` NaN fix (transformersβ‰₯5): the 960h checkpoint does not contain this pre-training-only parameter, and from_pretrained materialised it as uninitialised memory (NaN). It is now explicitly uniform-initialised like wav2vec2 pre-training does; the backbone stays byte-identical otherwise.
  • β€”`num_labels` on transformersβ‰₯5: it is a read-only property derived from len(id2label) β€” assigning it invoked the property setter and regenerated id2label as generic LABEL_X entries. The assignment was removed; 109 is derived from the real label map. predict() now derives every task's label names from config.id2label (the hardcoded noise list still said OTHER).
  • β€”`evaluation.py`: EER is now the threshold minimising |FAR βˆ’ FRR| (was the misleading min of (FAR+FRR)/2); AUC is reported raw (was max(auc, 1-auc)).
  • β€”`dataset_loader.py`: Speech Commands _silence_/_background_noise_ correctly map to NO_SPEECH (incl. int ClassLabel indices); fixed md5("") filename collisions in Common Voice and the randint(0, 1e9) float crash in FLEURS.
  • β€”Docs: corrected class counts (noise 5, intent 15, accent 20), ZenvionPipeline signatures/examples, and the architecture description. Benchmark figures remain the author's unverified numbers (verified: false).

v0.4 β€” 2025-07-24

  • β€”Added preprocessor_config.json β€” required for transformers pipeline() to work out of the box
  • β€”Added tokenizer_config.json and special_tokens_map.json for AutoTokenizer compatibility
  • β€”Added vocab.json for tokenizer
  • β€”Added label_mapping.json with all 8 task labels, thresholds, and metadata
  • β€”Added CITATION.cff for academic references
  • β€”Full README rewrite: benchmarks table, architecture diagram, training details, API reference, limitations
  • β€”Added live Gradio demo Space: Darveht/zenvion-voice-detector-demo
  • β€”Improved noise robustness: +2.1% VAD accuracy on telephone-codec audio
  • β€”Fixed language head misclassification of Malayalam (ml) as Hindi

v0.3 β€” 2025-06-10

  • β€”First public release
  • β€”8-head multi-task model: VAD, gender, emotion, language (50), age, noise, intent, accent
  • β€”Base: facebook/wav2vec2-base-960h

Citation

bibtex
@misc{darveht2025zenvion,
  author       = {Darveht},
  title        = {Zenvion Voice Detector v0.4: Multi-task Speech Analysis},
  year         = {2025},
  publisher    = {Hugging Face},
  howpublished = {\url{https://huggingface.co/Darveht/zenvion-voice-detector-v0.4}},
  note         = {Apache 2.0 License}
}

License

Released under the Apache 2.0 License. Base model (facebook/wav2vec2-base-960h) is also Apache 2.0.


[Live Demo](https://huggingface.co/spaces/Darveht/zenvion-voice-detector-demo) Β· [Report an Issue](https://huggingface.co/Darveht/zenvion-voice-detector-v0.4/discussions)