Speaker Verification, Spoofing and Watermarks
Enroll, score and threshold speakers, detect spoofed audio, and mark every generation with a watermark and C2PA.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
Verify and mark#
From Lesson 06.06, Lesson 06.16
Tasks in code#
| Task | Code |
|---|---|
| Verify a speaker | verify(enroll, |
| EER and its threshold | eer(same_scores, |
| Diarize a meeting | Pipeline.from_pretrained("pyannote/ |
| Load the watermark generator | AudioSeal.load_generator("audioseal_wm_16bits") |
| Detect a watermark | detector.detect_watermark(watermarked, |
| Toy spoof feature | spectral_rolloff(spec, |
| Toy text watermark | watermarked_sample(n, |
| Green-token z-score | detect(tokens) |
Verify with ECAPA#
from speechbrain.pretrained import EncoderClassifierclf = EncoderClassifier.from_hparams(source="speechbrain/spkrec-ecapa-voxceleb")enroll = torch.stack([clf.encode_batch(load(x))3-5 clean samples for x in enrollment_clips]).mean(0)average themscore = clf.similarity(enroll, clf.encode_batch(load("test.wav"))).item()verdict = score > 0.25tune on your dataFrom Lesson 06.06
Embed and detect AudioSeal#
generator = AudioSeal.load_generator("audioseal_wm_16bits")detector = AudioSeal.load_detector("audioseal_detector_16bits")audio = load_wav("generated.wav", sr=16000)[None, None, :]payload = torch.tensor([[1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0]])watermark = generator.get_watermark(audio, sample_rate=16000, message=payload)watermarked = audio + watermarkresult, decoded_payload = detector.detect_watermark(watermarked, sample_rate=16000)From Lesson 06.16
Formulas#
- EER
- the threshold where False Accept Rate equals False Reject Rate.
- AAM-softmax
- \cos(\theta + m) for the correct class. Typical m = 0.2, s = 30.
- Verification
- 1:1. Identification: 1:N. Open-set: unenrolled speakers in the test set.
- Green list
- hash the previous K tokens, add \delta to green logits.
- z-score
- (green count - expected) / \sqrt{n p (1 - p)}, p = 0.5.
- Bit Recovery Accuracy
- fraction of payload bits recovered after an attack.
From Lesson 06.06, Lesson 18.23, 18.23 code/main.py, Lesson 06.16
Watermark families#
- AudioSeal
- localized, per frame. Survives MP3, AAC, EQ, ±10% speed, +10 dB SNR noise.
- WavMark
- 32 bits/sec. Gaussian noise or MP3 compression removes it.
- WaveVerify
- FiLM generator, Mixture-of-Experts detector. Handles reversal and speed.
- Stable Signature
- fine-tuned image decoder. Decoder fine-tuning removes it.
- SynthID-text
- biased next-token sampling. Paraphrase destroys it.
- Pitch shift
- Bit Recovery Accuracy below 0.6 for all watermarks.
From Lesson 06.16, Lesson 18.23
Numbers#
| Setting | Default | Note |
|---|---|---|
| ECAPA embedding | 192-d | WavLM-large is 256-d |
| ECAPA threshold | 0.25 | SpeechBrain typical, tune it |
| Enrollment samples | 3-5 | Clean samples, averaged |
| ECAPA on VoxCeleb1-O | 0.87% | EER, 15 M params |
| ASVspoof 5 SOTA | ~7.23% | EER. In the wild expect 5-10% |
| AudioSeal payload | 16-bit | Per-frame at 16 kHz |
| AudioSeal detector | 485× realtime | 1000× faster than WavMark |
| Text watermark z | 4 | z >= 4 is very strong evidence |
Ship a generation#
From Lesson 06.16
Abbreviations#
- ECAPA-TDNN
- 1D conv, squeeze-excitation, attention pooling to 192-d.
- PLDA
- Probabilistic LDA. Likelihood-ratio scoring on top of cosine.
- AS-norm
- normalizes each score against an imposter cohort.
- CM
- countermeasure. Real speech or synthetic.
- SASV
- speaker verification plus CM in one biometric system.
- AASIST
- graph attention on spectral features. Anti-spoofing SOTA.
- C2PA
- cryptographically signed, tamper-evident provenance metadata.
- SynthID
- watermark for text, image, audio and video.
From Lesson 06.06, Lesson 06.16, Lesson 18.23
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| EER rises on phone calls | Trained on VoxCeleb web video | Evaluate on the target channel |
| EER degrades sharply | Test audio under 3 seconds | Get longer test audio |
| Anchor fails for one speaker | One noisy enrollment | Average 3 or more clean samples |
| Magnitude dominates the score | Embeddings not normalized | L2-normalize first |
| Detector fails in the real world | AASIST overfits ASVspoof LA | Calibrate on your domain |
| Watermark gone after an edit | Aggressive pitch shift | Keep a detection fallback |
| Manifest missing on a rehost | Metadata strip and re-encode | Add a watermark too |
| Text watermark gone | Paraphrase | Do not rely on it alone |
From Lesson 06.06, Lesson 06.16, Lesson 18.23
Use X when#
- Closed-set 1:1 on edge: ECAPA-TDNN plus a cosine threshold.
- Open-set in the cloud: WavLM-SV plus AS-norm.
- Meetings and podcasts:
pyannote/speaker-diarization-3.1. - Shipping TTS or cloning: AudioSeal on every output.
- Voice unlock: AASIST and ECAPA ensemble plus a liveness challenge.
- Call-center fraud: AASIST on a 20% sample of calls.
From Lesson 06.06, Lesson 06.16
Questions#
- Watermark or detector?
- Both. Pitch shift removes most watermarks.
- Does a liveness phrase stop clones?
- It stops replay, not real-time cloning.
- No SynthID signal means real?
- No. Other models do not add it.
- Why C2PA and a watermark?
- Metadata is rich but strippable. Watermarks persist but carry bits.
- What do you report with EER?
- The EER and the threshold at the EER.
From Lesson 06.16, Lesson 18.23, Lesson 06.06