Speaker verification calibration

SPARC

Frozen encoders. Calibrated scores.

A small residual on top of a frozen context-affine anchor turns speaker-verification scores into calibrated log-likelihood ratios, using duration, voice-activity and language context.

Better calibrated.
Across the board.

Tested on four corpora, six frozen encoders and their fusion — 28 conditions in all.

Panels improved
8 of 8

Lower Cllr than the context-affine baseline in every panel, and in 26 of 28 conditions.1

Largest gain
9.0%

Lower Cllr than context affine on NISP fusion. TidyVoice fusion: 7.0%.1

Against Variance-Gamma
18.7%

Lower Cllr on the TidyVoice single-encoder panel, with multiplicity-adjusted support.2

Subgroups
43 of 44

Improved when trials are split by duration, mismatch, language match and anchor confidence.3

Noisy context
32 of 32

Simulated VAD and language-ID error settings that keep the fusion gain.3

Speed
1.6×

Faster than Variance-Gamma on the same CPU, with one thread.4

Test Cllr · lower is betterContext affineBaselineSPARCChange
TidyVoice single0.25180.2468−2.0%
TidyVoice fusion0.09260.0861−7.0%
NISP single0.17520.1679−4.2%
NISP fusion0.03710.0337−9.0%
LibriSpeech single0.10690.1062−0.6%
LibriSpeech fusion0.03680.0350−4.9%
VoxCeleb2 single0.21440.2112−1.5%
VoxCeleb2 fusion0.06440.0627−2.6%

Single is the mean of six single-encoder conditions. SPARC values average the selected family's seeds.1

Anchor first.
Then correct.

SPARC learns only what a strong affine reference misses — and keeps the reference when a correction does not help.

1 · Fit

A frozen anchor.

A source-affine map and a context-affine anchor are fitted on labeled calibration data, then frozen. Every residual starts at zero.

2 · Select

Earned capacity.

Validation chooses among 17 families — the anchor itself, 8 polynomial and 8 small neural residuals — only if Cllr and EER do not get worse.

3 · Deploy

One small file.

A JSON bundle of about 15 KB with at most 289 residual parameters. Prediction checks encoder order and context schema.

Up and running
in a minute.

The synthetic example fits the full procedure, saves a bundle and reloads it. No audio, pretrained weights or datasets needed.

Terminal
pip install -r requirements.txt
python -m examples.synthetic_demo --output-dir outputs/synthetic
Python
from delivery import Plugin, Q_COLUMNS

names = ("encoder_a", "encoder_b")
Plugin.fit(calibration, validation, names, output_path="sparc.json")
llr = Plugin.load("sparc.json").predict(scores, context, names, context_names=Q_COLUMNS)