VoiceClap Attribute-Regression Heads (61 dimensions)

61 tiny MLP regression heads on top of the frozen laion/voiceclap-commercial 768-d speech embedding. One head per attribute; each head reads a single 768-d embedding and emits that attribute's continuous score directly — no calibration step, no bucket decoding.

The heads cover 55 perceptual/emotional voice dimensions (Anger, Valence, Arousal, Warm_vs._Cold, …), 4 audio-quality scores, plus Age, Gender, duration and talking_speed.

Headline results (held-out validation, 10 % stratified split)

band count
strong (Pearson r > 0.6) 40
medium (0.3 ≤ r ≤ 0.6) 21
weak (r < 0.3) 0
median r across 61 dims 0.683

Best: duration 0.998 (see caveat 1 — this one is trivial), score_overall_quality 0.949, Gender 0.940, score_background_quality 0.935, score_content_enjoyment 0.933, Monotone_vs._Expressive 0.901, Serious_vs._Humorous 0.896, High-Pitched_vs._Low-Pitched 0.894, Recording_Quality 0.893, Amusement 0.890, Arousal 0.822, Age 0.792, talking_speed 0.726, Valence 0.645. Weakest: Awe 0.338, Relief 0.355, Fear 0.390.

The full 61-row table is further down, and also as report/results.csv / report/results.json. An interactive report with per-dimension scatter plots is in report/attrdistill_report.html.

External benchmarks are reported below — these are validation numbers on the training distribution, and they do not transfer unchanged.


Read this before you use the numbers

These four caveats are not footnotes; they change how the table should be read.

1. duration r = 0.998 is trivial and is not evidence of embedding quality

Waveform length is directly visible to the encoder, so predicting it is close to reading it off. It also saturates at 30 s, because that is the encoder window used everywhere in this project (the training target was clipped to 30 s as well). It is included as a pipeline sanity check, nothing more. Ignore it when judging how good the representation is.

2. Bucket-balanced training pushes the predicted mean up on rare emotions

Training sampled inversely to bucket frequency so that rare high-intensity examples were not drowned out. On zero-inflated dimensions this systematically shifts the predicted level upward. The worst offenders (see the bias = mean(pred) − mean(true) column): Thankfulness_Gratitude +0.65, Relief +0.49, Distress +0.44, Impatience_and_Irritability +0.42, Awe +0.41, Astonishment_Surprise +0.40, Infatuation +0.40, Disappointment +0.39, Anger +0.39, Triumph +0.38, Affection +0.38, Sadness +0.37, Fear +0.35.

Ranking within a dimension is good; the absolute level runs high. If you need a calibrated absolute value, subtract the bias column, or (better) fit a one-off affine map on a small sample of your domain. Do not threshold a raw score at "0.5 means present" without recalibrating.

3. On sparse emotions, Spearman ρ is the stricter and more honest read

Pearson r on a zero-inflated target is inflated by the easy separation of "lots of zeros" from "a few large values". Where r and ρ disagree, trust ρ: Anger r = 0.728 but ρ = 0.516; Malevolence_Malice 0.679 → 0.466; Distress 0.481 → 0.289; Pain 0.392 → 0.199; Sadness 0.503 → 0.345.

4. talking_speed is characters per second, not words per second

It reproduces the source dataset's talking_speed_5.00_to_25.00 bucket definition. Typical English conversational speech lands around 12–17 chars/s. Divide by ~5.5 for a rough words-per-second figure.


Reproducibility note that matters more than any hyperparameter: de-duplicate before you split

The training dataset files each clip under one WebDataset tar per dimension, so a single clip appears in up to 15 different tars. The raw tar-entry count is 504,007; the number of unique clips is 296,422.

If you build the train/val split on raw tar entries, the same clip lands in both train and validation, and every metric in every table becomes inflated — the model is being asked to recall an embedding it has already memorised. De-duplication is done here by WebDataset key, before the split, and it is the single most important step to reproduce these numbers rather than better-looking fake ones.

(Related quirk handled the same way: the Jealousy___Envy_* and Jealousy_and_Envy_* tars both carry the single score key Jealousy_&_Envy, so those two near-duplicate tar dimensions merge into one head. That is why 328 tars over ~15 dimension families yield 61 — not 62 — heads.)


Usage

Both files below are in this repo: voiceclap_heads.py is a ~180-line reference implementation, example_inference.py is the demo whose real output is pasted underneath.

pip install torch torchaudio transformers huggingface_hub numpy

Single clip

from voiceclap_heads import AttributeScorer

scorer = AttributeScorer()          # laion/voiceclap-commercial + heads.pt
s = scorer.score("clip.wav")        # dict: 61 dimension name -> float

print(s["Valence"], s["Arousal"], s["Gender"], s["Recording_Quality"])

Batched (one encoder pass for many clips)

paths = ["a.wav", "b.wav", "c.wav"]

# all 61 heads, or a subset:
out = scorer.score(paths, dims=["Valence", "Arousal", "Anger"], batch_size=32)
# {'Valence': array([...]), 'Arousal': array([...]), 'Anger': array([...])}

# or keep the embeddings and re-run heads later (they are the expensive part):
import numpy as np
from voiceclap_heads import load_audio
emb = scorer.embed([load_audio(p) for p in paths], batch_size=32)   # (N, 768)
scores = scorer.score_embeddings(emb)                               # 61 x (N,)

If you already have VoiceClap embeddings

import torch
from voiceclap_heads import build_head

b = torch.load("heads.pt", map_location="cpu", weights_only=False)
head = build_head(b["heads"]["Arousal"])
x = (emb - b["emb_mu"]) / b["emb_sd"]      # emb: (N, 768) raw encoder output
arousal = head(x).squeeze(-1)              # the score, directly

Inference contract (must match, or the numbers do not transfer)

  1. mono, resampled to 16 kHz
  2. truncated to 30 s (480,000 samples) — the encoder window
  3. batch padded to that batch's max length, not a fixed 30 s (voiceclap_heads.AttributeScorer.embed sorts by length and does this for you; padding policy has a small but real effect on the embedding, so keep it identical)
  4. VoiceClap.encode_waveform(...)(N, 768)
  5. x = (emb - emb_mu) / emb_sd — both vectors ship inside heads.pt
  6. head(x) → the score. The y-normalisation affine is already folded into each head's last Linear, so there is nothing to de-standardise afterwards.

Score scales and polarity

Scores are on the source annotation scale, which is roughly 0–7 for emotions (0 = not present) — but each dimension has its own empirical range. report/results.csv carries label_min, label_max, label_mean, label_p50, label_p99 and frac_below_0p5 per dimension; config.json carries y_min/y_max/y_mean/y_std per head. Heads are unbounded regressors — clip to the label range if you need it.

Polarity of the non-obvious dimensions, determined empirically (not assumed) by correlating our heads against the independent laion/voicenet-dimension-predictors-commercial predictors on 61 held-out clips:

dimension direction evidence
Gender higher = more feminine r = −0.90 vs VoiceNet GEND (whose level 0 = "hyper-feminine", level 6 = "hyper-masculine")
Age higher = older r = +0.52 vs VoiceNet AGEV (level 0 = infant → 6 = elderly)
X_vs._Y names higher = more Y e.g. High-Pitched_vs._Low-Pitched high ⇒ lower-pitched; Monotone_vs._Expressive high ⇒ more expressive
duration seconds, capped at 30
talking_speed characters/second
Background_Noise higher = more noise r = −0.29 with score_background_quality, −0.46 with Recording_Quality; ρ = +0.60 against emolia's BKGN rubric (whose level 6 = "noise overpowers the voice")
Vulnerable_vs._Emotionally_Detached higher = more detached ρ = +0.30 against VoiceNet VULN after sign flip (level 0 = "impenetrable, heavily armored", level 6 = "profoundly raw")

Worked example — real output

Run on this machine with python example_inference.py examples/clip_a.mp3 examples/clip_b.mp3 (CPU, ~2.7 s for both clips after model load). The two clips ship in examples/. They are LAION-generated studio-style speech and were not in the training set.

  • clip_a.mp3 — generated from the direction "A 35-year-old female with a warm, resonant, slightly husky timbre … relaxed, a subtle smile playing on her lips", 22.15 s
  • clip_b.mp3 — generated from the direction "A 78-year-old man with a gravelly, slightly strained voice … weary but resolute", 24.07 s
loaded 61 heads on cpu

==============================================================================
examples/clip_a.mp3
==============================================================================
-- speaker / voice
   Gender                                  -0.390
   Age                                      2.587
   High-Pitched_vs._Low-Pitched             1.749
   Monotone_vs._Expressive                  2.584
   Soft_vs._Harsh                           0.213
   Warm_vs._Cold                            0.685
   Confident_vs._Hesitant                   1.470
   Submissive_vs._Dominant                  0.758
   Serious_vs._Humorous                     1.695
   Vulnerable_vs._Emotionally_Detached      1.016
   talking_speed                            9.016
   duration                                22.266
-- recording quality
   Recording_Quality                        2.650
   Background_Noise                         0.958
   Authenticity                             3.255
   score_overall_quality                    2.941
   score_speech_quality                     1.861
   score_background_quality                 3.653
   score_content_enjoyment                  5.271
-- core affect
   Valence                                  0.574
   Arousal                                  3.210
-- top 8 emotion dimensions
   Elation                                  2.375
   Interest                                 2.352
   Hope_Enthusiasm_Optimism                 2.210
   Pleasure_Ecstasy                         1.831
   Amusement                                1.719
   Triumph                                  1.544
   Astonishment_Surprise                    1.540
   Distress                                 1.450

==============================================================================
examples/clip_b.mp3
==============================================================================
-- speaker / voice
   Gender                                  -0.910
   Age                                      3.199
   High-Pitched_vs._Low-Pitched             2.130
   Monotone_vs._Expressive                  1.945
   Soft_vs._Harsh                           0.301
   Warm_vs._Cold                            0.314
   Confident_vs._Hesitant                   0.934
   Submissive_vs._Dominant                  0.465
   Serious_vs._Humorous                     1.115
   Vulnerable_vs._Emotionally_Detached      1.863
   talking_speed                            8.629
   duration                                24.243
-- recording quality
   Recording_Quality                        2.528
   Background_Noise                         0.652
   Authenticity                             2.830
   score_overall_quality                    3.045
   score_speech_quality                     1.892
   score_background_quality                 3.823
   score_content_enjoyment                  5.025
-- core affect
   Valence                                  0.146
   Arousal                                  1.645
-- top 8 emotion dimensions
   Interest                                 2.210
   Concentration                            1.747
   Contemplation                            1.131
   Confusion                                1.089
   Astonishment_Surprise                    1.034
   Amusement                                1.005
   Impatience_and_Irritability              0.839
   Disappointment                           0.809

batched: {'Valence': [0.574, 0.146], 'Arousal': [3.21, 1.645], 'Gender': [-0.39, -0.91], 'Age': [2.587, 3.199]}

Reading it honestly: duration is recovered to within 0.12 s / 0.17 s; Age and Gender order the two speakers the right way (older & more masculine for clip_b); the older, weary clip gets much lower Arousal (1.65 vs 3.21) and lower Valence. Age 2.587 vs 3.199 is a 7-point scale, not years — it is not claiming 35 vs 78.

A caution on that example. The prompt text is a generation direction, not a measurement of the produced audio. On a 61-clip sample of the same pool, our Gender head correlates r = 0.09 with the gender stated in the prompt and Age correlates r = 0.05 with the stated age — while agreeing strongly with VoiceNet's independent predictors on the same audio (|r| = 0.90 and 0.52). The synthesis simply does not reliably follow the prompt's speaker description on this pool, so prompts are not usable as ground truth. Use the examples to check that your pipeline is wired correctly, not as an accuracy claim.

Training

  • Data: TTS-AGI/Emotion-Voice-Attribute-Reference-Snippets-DACVAE-Wave — 328 WebDataset tars, 504,007 raw entries → 296,422 unique clips after key de-duplication (18,592 from the podcast-conditioned source, 277,830 from the emotion-attribute source).
  • Targets: every sample's JSON carries the full 59-score empathic_insight_scores / annotation_scores vector, so every clip labels every dimension and the regression targets are exact continuous scores — not bucket midpoints reconstructed from the tar name. That is why n_train is ~266.8 k for essentially every head. Plus duration and talking_speed derived from the JSON.
  • Embeddings: computed once with the frozen encoder into a single (296422, 768) float16 array; the heads then train in minutes.
  • Loss: Huber (δ tuned per dimension over {0.5, 1.0}).
  • Split: 10 % validation, stratified per score bucket, taken after de-duplication.
  • Sampling: bucket-balanced (weight ∝ 1/bucket count) — see caveat 2.
  • Feature standardisation: per-dimension mean/std over a 200 k random subsample, shared by all heads (emb_mu, emb_sd in heads.pt).
  • Sweep: 19 runs per dimension — {mlp1_h64, mlp1_h128, mlp2_h96_64, mlp2_h64_32} × lr {1e-3, 3e-3} × wd {1e-4, 1e-2} (16 runs), then 3 dropout / Huber-δ refinement runs on the winning architecture. Selected by validation Pearson r, with cosine schedule, 200-step warmup, early stopping (patience 8 evals).
  • Training script as run: train_heads.py.

Architectures

kind topology
mlp1 (mlp1_h64, mlp1_h128) Linear(768,H) → GELU → Dropout → Linear(H,1) — same topology as VoiceNet's MLPHead
mlp2ln (mlp2_h96_64, mlp2_h64_32) Linear(768,H) → LayerNorm → GELU → Dropout → Linear(H,H2) → GELU → Dropout → Linear(H2,1)

Selected per dimension: mlp2_h96_64 ×30, mlp2_h64_32 ×23, mlp1_h128 ×7, mlp1_h64 ×1.

Files

path what
heads.pt the bundle: {"heads": {dim: state_dict}, "emb_mu": (768,), "emb_sd": (768,)} — 61 heads, 17 MB
heads_per_dim/<Dimension>.pt the same heads individually, each with {"state_dict", "kind", "arch", "meta"}
config.json architecture kinds, per-dimension hyperparameters + metrics + label ranges, preprocessing contract, I/O spec
voiceclap_heads.py reference implementation (AttributeScorer, build_head, load_audio)
example_inference.py the demo above
examples/clip_a.mp3, clip_b.mp3 the two clips used in the demo
report/results.md, results.csv, results.json the full 61-row result table
report/attrdistill_report.html interactive report, per-dimension scatter plots
train_heads.py the training script, as run
bench/emolia/ emolia-bench evaluation: endpoint server, run script, analysis scripts, the harness's own report + summary + per-item predictions
provenance/MANIFEST.json embedding-matrix manifest: n samples, label column order, source counts, de-dup notes
bench/emonet/ EmoNet Voice Bench evaluation: script, per-row predictions, full metrics JSON, label table, data manifest
provenance/meta_all.parquet one row per unique clip: key, tar, dim, bucket, src, dur, nchar, nword — enough to reproduce the de-duplication and the split

The 296,422 × 768 embedding matrix and the 296,422 × 61 label matrix are not uploaded (0.5 GB). Regenerate them from the dataset with the contract above, or ask.

Intended use and limits

Fast, cheap attribute tagging, dataset filtering/curation, TTS-output QA, retrieval and reward shaping over large speech corpora — anywhere you want 61 numbers per clip at roughly the price of one embedding.

Limits.

  • Training labels are model-generated (Empathic Insight annotations), not human ratings. These heads distil an annotator model; they inherit its biases, and agreement with human raters is an open question — see the benchmark section.
  • Training audio is largely synthetic / TTS-generated English studio-style speech. Expect degradation on real-world noisy recordings, on non-English speech, and on spontaneous conversational audio.
  • Medium-band emotions (r 0.3–0.6) are usable for ranking and coarse filtering, not for per-clip assertions about a speaker's emotional state.
  • Do not use these to make consequential judgements about individuals (hiring, policing, clinical, insurance). Gender and Age are perceived-voice attributes, not identity claims, and are wrong often enough to be harmful if treated otherwise.

Citation

@misc{voiceclap_attribute_heads_2026,
  title  = {VoiceClap Attribute-Regression Heads: 61 linear-probe dimensions over a frozen commercial speech encoder},
  author = {LAION},
  year   = {2026},
  url    = {https://huggingface.co/laion/voiceclap-commercial-attribute-heads}
}

Base encoder: laion/voiceclap-commercial. Training data: TTS-AGI/Emotion-Voice-Attribute-Reference-Snippets-DACVAE-Wave.


Benchmarks

Two external benchmarks were run against these heads. Neither is a regression benchmark shaped exactly like our training task, so read the methodology before the numbers.

1. EmoNet Voice Bench — human-expert emotion-intensity regression

Dataset: t1a5anu-anon/emonet-voice-bench (public, ungated) — 12,600 items, 12,397 unique clips, 35.8 h. Paper: EmoNet-Voice, arXiv:2506.09827.

Task, verbatim from the dataset. Each row carries exactly one target emotion and an intensity rated 0 = Not Present / 1 = Mildly Present / 2 = Intensely Present by 2–4 of 6 psychology experts. It is not a 40-way argmax and not multi-label. The paper maps the averaged human intensity to a 0–10 scale (0 → 0, 1 → 5, 2 → 10) and reports MAE, RMSE, Pearson r and Spearman ρ.

Our protocol. For each row we take the single head named by that row's emotion and score the clip with it — no argmax, no head selection. 42 of 42 benchmark classes map 1:1 onto a head, with only cosmetic renames (Astonishment→Astonishment_Surprise, Fatigue→Fatigue_Exhaustion, Hope→Hope_Enthusiasm_Optimism, Intoxication→Intoxication_Altered_States_of_Consciousness, Malevolence→Malevolence_Malice, Pleasure→Pleasure_Ecstasy, Thankfulness→Thankfulness_Gratitude, Emotional Numbness, Jealousy & Envy, Sexual Lust, Impatience and Irritability). The remaining 19 heads are unused. All 12,600 rows were scored; refusal rate 0 %.

Results

aggregation Pearson r Spearman ρ
pooled over all 12,600 rows 0.304 0.323
macro-averaged over the 42 emotions 0.386 0.374
macro, restricted to the 2,912 rows with unanimous annotators 0.548 0.488

Published baselines (paper Table 5), for orientation:

model Spearman ρ Pearson r MAE RMSE refusal
EmpathicInsight-Voice Large 0.415 0.421 2.995 3.756 0 %
EmpathicInsight-Voice Small 0.418 0.414 2.997 3.757 0 %
Gemini 2.5 Pro 0.417 0.416 3.008 3.785 0 %
Gemini 2.0 Flash 0.355 0.350 3.608 4.453 0.01 %
GPT-4o Audio Preview 0.337 0.336 3.432 4.247 27.6 %
GPT-4o Mini Audio Preview 0.326 0.327 3.320 4.124 2.3 %
Hume Voice 0.274 0.231 4.744 5.474 39.2 %
these heads (pooled) 0.323 0.304 see below see below 0 %

Honest reading: on the fair, scale-free comparison these 61-head probes land below Gemini 2.0 Flash and the EmpathicInsight-Voice models, above Hume Voice, and roughly level with GPT-4o Mini Audio Preview — while being a 50 k-parameter MLP on a frozen embedding rather than a large audio LLM. The paper does not state whether its Table 5 aggregates pooled or macro-over-emotions; we give both, and we quote our pooled figure in the table above because it is the less flattering of the two.

MAE / RMSE need calibration and are therefore not comparable

Our heads emit the Empathic-Insight 0–7 scale, not 0–10, and the benchmark's rows are heavily emotion-present (gold mean 5.26 on the 0–10 scale) while our raw predictions average 1.13. Raw MAE is dominated by that scale mismatch, not by ranking quality:

variant MAE RMSE fair to compare?
fixed rescale clip(score/7×10, 0, 10), no fitting 3.884 4.587 yes, but it is mostly measuring the scale gap
one global affine, 2-fold cross-fitted on the benchmark 2.289 2.786 no — uses benchmark labels
per-emotion affine, 2-fold cross-fitted on the benchmark 2.142 2.607 no — uses benchmark labels
per-emotion affine fit on all data (oracle) 2.124 2.579 no — upper bound only

The calibrated rows would "beat" every model in Table 5. They are not a win. The LLM baselines are zero-shot and receive no in-domain calibration; we do. We report them only to show that most of the raw MAE gap is an offset/scale artefact rather than a ranking failure. Use the correlation table for comparisons. This is caveat 2 (the bucket-balanced bias) showing up in a second domain, in the opposite direction: our absolute level is far too low here because the benchmark over-samples present-emotion clips relative to our training marginal.

Presence detection (a secondary, non-official metric)

Reframing as "is this emotion present at all?" — clips all annotators rated 0 vs clips all annotators rated > 0 — gives a macro ROC-AUC of 0.810 over the 38 emotions with ≥ 10 clips on both sides. This is not the benchmark's defined metric; it is reported because it is the shape most downstream users actually want (filtering a corpus), and because it is threshold-free.

Contamination check

Identifier spaces are disjoint: benchmark clips are named <8-hex>_enhanced*.mp3, our training keys are cond_podcastt_* / emo_<dim>_b<bucket>_batch*_chunk*. Zero overlap on exact stems and zero overlap on 8-hex tokens. That is evidence of separate provenance, not proof of zero audio overlap — no audio-fingerprint dedup was run.

A lineage caveat that is more important than the filename check: our training labels are Empathic Insight model annotations, and the EmpathicInsight-Voice models were themselves trained on EmoNet-Voice data. So our teacher may have seen clips from the same parent corpus as this benchmark. Treat these numbers as distillation transfer measured against human experts, not as a clean held-out generalisation test against an unrelated corpus. The gap between our 0.30 and EmpathicInsight-Voice's 0.42 is roughly the cost of distilling that annotator into a 50 k-parameter probe.

Per-emotion results

presence AUROC is blank where one side had < 10 clips.

emotion n Pearson r Spearman ρ r (unanimous) presence AUROC
Teasing 300 0.652 0.643 0.762 0.938
Impatience_and_Irritability 300 0.651 0.640 0.806 0.940
Malevolence_Malice 300 0.582 0.559 0.787 0.922
Authenticity 300 0.577 0.464 0.819 0.939
Anger 300 0.567 0.572 0.720 0.876
Amusement 300 0.535 0.508 0.799 0.903
Pain 300 0.499 0.478 0.676 0.826
Distress 300 0.495 0.497 0.613 0.829
Sexual_Lust 300 0.485 0.457 0.596 0.847
Contempt 300 0.461 0.453 0.666 0.895
Disgust 300 0.457 0.460 0.701 0.865
Helplessness 300 0.454 0.438 0.631 0.856
Sadness 300 0.440 0.383 0.650 0.820
Elation 300 0.438 0.446 0.605 0.820
Fear 300 0.413 0.402 0.675 0.836
Jealousy_&_Envy 300 0.406 0.381 0.556 0.791
Fatigue_Exhaustion 300 0.397 0.428 0.586 0.836
Pride 300 0.396 0.368 0.625 0.811
Embarrassment 300 0.380 0.379 0.407 0.752
Arousal 300 0.370 0.339 0.552 0.823
Astonishment_Surprise 300 0.368 0.357 0.488 0.744
Confusion 300 0.367 0.364 0.623 0.869
Bitterness 300 0.360 0.330 0.514
Infatuation 300 0.358 0.377 0.367 0.782
Pleasure_Ecstasy 300 0.355 0.344 0.552 0.745
Longing 300 0.351 0.363 0.544 0.820
Affection 300 0.342 0.287 0.553 0.789
Intoxication_Altered_States_of_Consciousness 300 0.342 0.357 0.446 0.795
Sourness 300 0.340 0.350 0.539
Shame 300 0.335 0.302 0.507 0.792
Doubt 300 0.315 0.324 0.382 0.735
Disappointment 300 0.309 0.289 0.465 0.763
Thankfulness_Gratitude 300 0.309 0.250 0.505 0.721
Interest 300 0.289 0.261 0.485 0.843
Contentment 300 0.284 0.303 0.452 0.786
Concentration 300 0.277 0.276 0.334
Relief 300 0.277 0.263 0.452 0.735
Triumph 300 0.274 0.290 0.441 0.760
Contemplation 300 0.262 0.238 0.547
Awe 300 0.177 0.153 0.281 0.663
Emotional_Numbness 300 0.171 0.217 0.139 0.754
Hope_Enthusiasm_Optimism 300 0.108 0.134 0.151 0.569

Run with bench/emonet/eval_emonet.py; raw per-row predictions and the full metrics JSON are in bench/emonet/.

2. EmoIA / emolia-bench — binary "is this attribute present?" judgement

Benchmark: LAION-AI/emolia-bench (commit 1a48a7a). Two subsets, both binary classification of (audio, text-prompt) pairs against majority_present from 2–4 human raters:

  • emolia-emo — 7,988 items over 3,944 clips, 40 emotions, 5 sampling strata.
  • emolia-dim — 18,632 items over the 58-dimension VoiceNet rubric (58 dims × 7 levels × {positive, negative}).

Official metric: balanced accuracy vs majority_present (benchmark.py::binary_metrics, bal = (sensitivity + specificity)/2); secondary metric positive-class F1. We ran the benchmark's own harness through its --endpoint path — a local server returns the relevant head's score as the "similarity" — with the README's recommended filter --min-raters 2 --exclude-flagged.

2a. emolia-emo — ran in full, 40/40 emotions map to a head

n = 7,986 after filtering (2 items dropped for having < 2 raters; --exclude-flagged dropped 0, because this subset's benchmark_labels.csv has no flagged column at all — that filter is a silent no-op here, not evidence of clean audio). Positive rate 0.578. 0 missing audio, 0 evaluation errors. Only one name needed mangling: the benchmark's Jealousy / Envy → head Jealousy_&_Envy. 21 of the 61 heads are unused.

Threshold. The harness defaults to --threshold 0.0, which assumes a cosine-style score centred on zero. Our heads emit a non-negative 0–7 intensity, so that default is degenerate (balanced accuracy 0.515 — it calls almost everything present). We used --threshold 1.0, chosen a priori as the Empathic-Insight "mildly present" boundary, with no reference to benchmark labels. For transparency: the oracle-tuned threshold is 0.919 and yields 0.696, so the a-priori choice cost ~0.002.

balanced accuracy F1
all 7,986 items, threshold 1.0 (headline) 0.694 0.696
unanimous-rater subset (n = 2,614) 0.822 0.867
harness default threshold 0.0 0.515 0.734
oracle-tuned threshold 0.919 (not a headline) 0.696 0.713

Baselines the benchmark itself computes on the identical task:

reference balanced accuracy
random / always-majority 0.500
single human, pairwise 0.562
single human, leave-one-out vs the majority of the others (n = 13,208) 0.572
these heads 0.694

By the benchmark's own rubric that is the "Medium — above single-human, useful training target" band.

The 0.694 is inflated, and here is the measurement that shows it

emolia-emo's item pool was selected using an earlier version of these very heads: every sidecar JSON under dataset/emolia-emo/data/<Emotion>_best/ carries 55 <Dimension>_best columns from this head family, and the folder name means "top-scoring clips for that head". The human labels are independent, so this is selection bias, not label leakage — but it is home turf, and the pooled number is not a clean estimate.

The benchmark's 5 task_type strata let us measure how much. Within a stratum the selection confound is held roughly constant:

task_type n balanced acc AUROC
affirmative 3,999 0.629 0.706
contrastive_1 1,000 0.535 0.559
contrastive_2 1,000 0.539 0.556
penultimate 992 0.526 0.562
ultimate 995 0.501 0.576
pooled 7,986 0.694 0.748
mean within stratum 0.546 0.592

Roughly half the pooled signal is the selection confound. The honest headline is the mean within-stratum AUROC of 0.592 — modest, above chance, and far below what the pooled 0.748 suggests. On the hard contrastive/ultimate strata — where the negatives are near-misses rather than random other emotions — these heads are close to chance.

A useful control: scoring the same items with the sidecar's own older head values gives pooled AUROC 0.749 and mean within-stratum AUROC 0.573, versus 0.748 / 0.592 for the heads published here. The released heads are marginally better and behave essentially like the selector, which is exactly what the selection-bias story predicts.

Note also that the benchmark's own inter-rater agreement is low (Fleiss κ ≈ 0.086 binary on emolia-emo; single-human LOO balanced accuracy 0.572), so there is little headroom above ~0.6 for anyone on the within-stratum reading.

2b. emolia-dimnot run as a headline number, and here is why

We deliberately do not report a balanced accuracy for emolia-dim. Three independent reasons, any one of which would be disqualifying:

  1. Half the benchmark has no corresponding head. 30 of 58 dimensions — 9,360 rows, 50.2 % — have no head at all: ARSH, ATCK, CHNK, DARC, DFLU, EMPH, EXPL, FULL, LANG, METL, RESP, R_CHST, R_HEAD, R_MASK, R_MIXD, R_NASL, R_ORAL, R_THRT, SMTH, STRU, S_CONV, S_MONO, S_NARR, S_NEWS, S_STRY, S_TECH, VALS, VFLX, VOLT, WARM.
  2. Some are structurally unreachable, not merely missing. The 7 resonance dimensions (R_CHST/THRT/ORAL/MASK/NASL/HEAD/MIXD) and the 6 within-clip dynamics dimensions (VOLT, VFLX, DARC, ARSH, VALS, ATCK) describe trajectory inside the clip. Our heads emit one clip-level scalar. No calibration fixes that; it needs a windowed head.
  3. The task shape does not fit a monotone scalar. emolia-dim asks "does this clip sit at level L?", not "how much of D?". A monotone score thresholded once globally cannot answer bucket membership. (This is the same reason CLAP baselines struggle on this subset — the harness was built for cosine similarity.)

WARM deserves a specific flag: it is a false friend. The rubric defines it as spectral warmth (200–500 Hz low-mid energy); our Warm_vs._Cold is affective / interpersonal warmth. Same word, different construct — so we list it as "no head" rather than claim the match.

What we do report — a diagnostic, not the benchmark's metric. For the 8 dimensions that genuinely share a construct with a head, Spearman ρ between the head score and the queried rubric level, restricted to items humans agreed sit at that level. This measures monotone agreement with the rubric's ordering:

VoiceNet dim head sign n Spearman ρ
GEND Perceived Gender Gender 66 0.681
BKGN Background Noise Background_Noise + 79 0.597
VALN Valence Valence + 89 0.589
STNC Stance Submissive_vs._Dominant + 97 0.518
AROU Arousal Arousal + 75 0.450
TEMP Tempo talking_speed + 64 0.441
RCQL Recording Quality Recording_Quality + 78 0.430
VULN Vulnerability Vulnerable_vs._Emotionally_Detached 89 0.302
macro mean 0.501

Sign conventions were read off the rubric text, not fitted: GEND level 6 = hyper-masculine while our Gender rises toward feminine; VULN level 0 = "impenetrable, heavily armored" and level 6 = "profoundly raw, naked", while our head rises toward Emotionally Detached. One trap worth recording: emolia's BKGN rubric runs opposite to the one in voicenet .../dimensions.py — here level 0 is a "dead acoustic vacuum" and level 6 is "noise overpowers the voice", so +1 is correct for this rubric and would be wrong for the other. Sample sizes are small (64–97 items per dimension); treat these as indicative.

As an additional sanity figure only: applying a label-free quantile-matching calibration (map each head score onto 0–6 by matching its empirical quantiles to the level marginal, then predict "yes" iff the mapped level equals the queried level) gives a macro balanced accuracy of 0.548 over those 8 dimensions. It covers 8 of 58 dimensions and is not comparable to a full-benchmark number.

Artifacts, scripts and the harness's own report.md / summary.json are in bench/emolia/.

Benchmarks — what to take away

  • On human-rated emotion-intensity regression (EmoNet Voice Bench) these probes reach pooled r = 0.304 / ρ = 0.323 with a 0 % refusal rate: below Gemini 2.0 Flash and the EmpathicInsight-Voice models, above Hume Voice, at ~50 k parameters per dimension.
  • On binary attribute presence (emolia-emo) the pooled 0.694 balanced accuracy looks strong and beats the single-human ceiling, but roughly half of it is a selection artefact; the defensible figure is a mean within-stratum AUROC of 0.592.
  • emolia-dim is not a task these heads can do, and we report no number for it.
  • Across both: ranking is decent, absolute calibration is not. Recalibrate on your own domain before thresholding.

Full results (all 61 dimensions)

Held-out validation, 10 % bucket-stratified split, taken after key de-duplication. bias = mean(prediction) − mean(target) on validation (caveat 2). Sorted by Pearson r.

# dimension band arch params n_train n_val MAE RMSE Pearson r Spearman ρ bias label range label mean
1 duration strong mlp2_h96_64 80,289 266,780 29,642 0.387 0.586 0.998 0.997 +0.025 3.0 … 30.0 13.344
2 score_overall_quality strong mlp2_h96_64 80,289 266,779 29,643 0.088 0.114 0.949 0.941 -0.005 1.29 … 3.66 2.792
3 Gender strong mlp2_h96_64 80,289 266,779 29,643 0.26 0.373 0.94 0.907 +0.036 -2.666 … 2.291 -0.096
4 score_background_quality strong mlp2_h96_64 80,289 266,780 29,642 0.105 0.141 0.935 0.911 +0.003 1.523 … 4.523 3.463
5 score_content_enjoyment strong mlp2_h96_64 80,289 266,780 29,642 0.073 0.095 0.933 0.906 +0.022 3.098 … 5.883 4.877
6 Monotone_vs._Expressive strong mlp2_h96_64 80,289 266,780 29,642 0.214 0.288 0.901 0.888 -0.030 0.408 … 4.527 2.402
7 Serious_vs._Humorous strong mlp1_h128 98,561 266,779 29,643 0.266 0.359 0.896 0.876 +0.032 -0.274 … 5.016 1.507
8 High-Pitched_vs._Low-Pitched strong mlp2_h96_64 80,289 266,780 29,642 0.108 0.147 0.894 0.882 +0.011 0.544 … 4.461 1.782
9 Recording_Quality strong mlp1_h128 98,561 266,781 29,641 0.182 0.234 0.893 0.896 +0.024 0.757 … 4.656 2.471
10 Amusement strong mlp2_h96_64 80,289 266,780 29,642 0.338 0.441 0.89 0.859 +0.153 -0.01 … 4.672 0.865
11 Concentration strong mlp1_h128 98,561 266,781 29,641 0.26 0.344 0.888 0.881 +0.074 -0.003 … 4.562 0.862
12 Vulnerable_vs._Emotionally_Detached strong mlp2_h96_64 80,289 266,621 29,625 0.229 0.301 0.849 0.837 +0.041 -0.049 … 4.074 1.46
13 Interest strong mlp2_h96_64 80,289 266,779 29,643 0.25 0.351 0.834 0.817 -0.060 -0.051 … 3.65 2.024
14 Confident_vs._Hesitant strong mlp2_h96_64 80,289 266,781 29,641 0.251 0.343 0.824 0.789 +0.089 0.085 … 4.156 1.281
15 Arousal strong mlp2_h96_64 80,289 266,780 29,642 0.296 0.395 0.822 0.816 +0.024 -0.015 … 5.019 1.897
16 score_speech_quality strong mlp2_h96_64 80,289 266,779 29,643 0.045 0.057 0.807 0.721 +0.017 1.801 … 2.361 1.924
17 Embarrassment strong mlp2_h64_32 51,457 266,780 29,642 0.248 0.329 0.799 0.76 +0.138 -0.095 … 2.988 0.392
18 Submissive_vs._Dominant strong mlp2_h96_64 80,289 266,781 29,641 0.174 0.244 0.795 0.77 +0.047 -0.656 … 2.389 0.483
19 Age strong mlp2_h96_64 80,289 266,780 29,642 0.178 0.274 0.792 0.794 -0.036 0.077 … 5.418 2.961
20 Teasing strong mlp2_h64_32 51,457 266,780 29,642 0.308 0.379 0.777 0.753 +0.137 -0.012 … 3.662 0.548
21 Soft_vs._Harsh strong mlp2_h96_64 80,289 266,779 29,643 0.223 0.323 0.754 0.721 -0.062 -1.956 … 1.758 0.439
22 Background_Noise strong mlp1_h128 98,561 266,782 29,640 0.18 0.234 0.753 0.746 -0.010 -0.036 … 2.131 0.549
23 Contemplation strong mlp2_h96_64 80,289 266,780 29,642 0.357 0.483 0.748 0.726 +0.241 -0.039 … 4.184 0.504
24 Anger strong mlp2_h96_64 80,289 266,780 29,642 0.491 0.6 0.728 0.516 +0.388 -0.02 … 6.141 0.371
25 talking_speed strong mlp1_h128 98,561 266,781 29,641 2.592 3.683 0.726 0.75 -0.472 0.124 … 100.694 14.908
26 Warm_vs._Cold strong mlp1_h128 98,561 266,562 29,617 0.314 0.438 0.724 0.699 -0.001 -2.215 … 2.738 0.476
27 Authenticity strong mlp1_h128 98,561 266,780 29,642 0.132 0.169 0.718 0.701 +0.026 1.594 … 4.176 2.918
28 Impatience_and_Irritability strong mlp2_h96_64 80,289 266,780 29,642 0.563 0.691 0.718 0.598 +0.419 -0.075 … 5.707 0.533
29 Intoxication_Altered_States_of_Consciousness strong mlp2_h96_64 80,289 266,780 29,642 0.383 0.53 0.696 0.61 +0.279 -0.111 … 4.562 0.249
30 Pleasure_Ecstasy strong mlp2_h64_32 51,457 266,780 29,642 0.333 0.427 0.696 0.706 +0.181 -0.014 … 4.793 0.53
31 Sexual_Lust strong mlp2_h96_64 80,289 266,780 29,642 0.353 0.458 0.683 0.637 +0.250 -0.083 … 4.293 0.295
32 Malevolence_Malice strong mlp2_h64_32 51,457 266,781 29,641 0.386 0.463 0.679 0.466 +0.314 -0.042 … 3.603 0.263
33 Elation strong mlp2_h96_64 80,289 266,779 29,643 0.453 0.597 0.667 0.676 +0.277 -0.024 … 5.539 0.689
34 Valence strong mlp2_h96_64 80,289 266,780 29,642 0.588 0.841 0.645 0.624 -0.176 -4.555 … 4.106 0.572
35 Hope_Enthusiasm_Optimism strong mlp2_h64_32 51,457 266,780 29,642 0.598 0.777 0.64 0.611 +0.357 -0.014 … 6.184 0.93
36 Contempt strong mlp2_h64_32 51,457 266,779 29,643 0.41 0.486 0.638 0.519 +0.325 -0.013 … 4.734 0.269
37 Astonishment_Surprise strong mlp2_h64_32 51,457 266,781 29,641 0.516 0.661 0.632 0.561 +0.398 -0.029 … 5.133 0.446
38 Contentment strong mlp2_h64_32 51,457 266,779 29,643 0.309 0.404 0.63 0.655 +0.135 0.0 … 3.961 0.551
39 Bitterness strong mlp2_h96_64 80,289 266,781 29,641 0.344 0.402 0.612 0.54 +0.250 -0.032 … 4.254 0.204
40 Longing strong mlp2_h64_32 51,457 266,779 29,643 0.305 0.374 0.607 0.498 +0.233 -0.062 … 3.967 0.18
41 Doubt medium mlp2_h64_32 51,457 266,779 29,643 0.361 0.423 0.593 0.484 +0.271 -0.019 … 4.391 0.236
42 Confusion medium mlp2_h64_32 51,457 266,780 29,642 0.447 0.545 0.567 0.475 +0.354 -0.015 … 4.527 0.273
43 Affection medium mlp2_h64_32 51,457 266,779 29,643 0.511 0.639 0.55 0.465 +0.383 -0.023 … 5.215 0.399
44 Disgust medium mlp2_h64_32 51,457 266,779 29,643 0.399 0.459 0.543 0.39 +0.313 -0.026 … 3.543 0.216
45 Emotional_Numbness medium mlp2_h64_32 51,457 266,780 29,642 0.308 0.404 0.543 0.397 +0.242 -0.021 … 4.051 0.154
46 Sourness medium mlp2_h96_64 80,289 266,780 29,642 0.41 0.47 0.528 0.389 +0.316 -0.031 … 3.982 0.232
47 Triumph medium mlp2_h64_32 51,457 266,780 29,642 0.477 0.558 0.51 0.403 +0.381 -0.053 … 4.832 0.217
48 Sadness medium mlp2_h64_32 51,457 266,780 29,642 0.433 0.542 0.503 0.345 +0.372 -0.01 … 4.836 0.155
49 Pride medium mlp2_h96_64 80,289 266,778 29,644 0.397 0.49 0.502 0.522 +0.280 -0.009 … 4.629 0.298
50 Thankfulness_Gratitude medium mlp2_h96_64 80,289 266,780 29,642 0.762 0.916 0.495 0.411 +0.652 -0.056 … 4.832 0.425
51 Helplessness medium mlp2_h64_32 51,457 266,780 29,642 0.383 0.479 0.485 0.557 +0.321 -0.019 … 3.705 0.129
52 Distress medium mlp2_h64_32 51,457 266,781 29,641 0.501 0.626 0.481 0.289 +0.436 -0.0 … 4.699 0.159
53 Fatigue_Exhaustion medium mlp2_h64_32 51,457 266,780 29,642 0.326 0.441 0.478 0.374 +0.271 -0.092 … 5.379 0.104
54 Disappointment medium mlp2_h96_64 80,289 266,779 29,643 0.502 0.595 0.465 0.434 +0.393 -0.0 … 4.152 0.289
55 Infatuation medium mlp2_h64_32 51,457 266,779 29,643 0.455 0.553 0.44 0.365 +0.395 -0.059 … 4.676 0.128
56 Jealousy_&_Envy medium mlp2_h96_64 80,289 266,781 29,641 0.356 0.43 0.425 0.356 +0.293 -0.052 … 4.078 0.169
57 Shame medium mlp2_h64_32 51,457 266,781 29,641 0.408 0.48 0.408 0.36 +0.348 -0.023 … 5.066 0.131
58 Pain medium mlp2_h96_64 80,289 266,780 29,642 0.214 0.321 0.392 0.199 +0.178 -0.02 … 5.07 0.046
59 Fear medium mlp2_h64_32 51,457 266,780 29,642 0.405 0.464 0.39 0.255 +0.349 -0.052 … 4.137 0.094
60 Relief medium mlp1_h64 49,281 266,778 29,644 0.594 0.709 0.355 0.317 +0.491 -0.057 … 5.191 0.297
61 Awe medium mlp2_h64_32 51,457 266,780 29,642 0.461 0.534 0.338 0.235 +0.413 -0.026 … 4.731 0.087

(Rows with bias above +0.35 are the ones caveat 2 is about. Fear +0.349 and Confusion +0.354 sit just under.)

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for laion/voiceclap-commercial-attribute-heads

Finetuned
(1)
this model

Dataset used to train laion/voiceclap-commercial-attribute-heads

Paper for laion/voiceclap-commercial-attribute-heads