Thomas Piacentini
← Workshop

Cheat sheet

Speaker Verification, Spoofing and Watermarks

Original text · English

Enroll, score and threshold speakers, detect spoofed audio, and mark every generation with a watermark and C2PA.

Verify and mark

real or fakerealanchorsignTest utterance3 s or moreclientCountermeasureAASIST or RawNet2modelSpeaker encoderECAPA-TDNN, 192-dmodelCosine scorethreshold from a dev setprocessTTS outputevery generationmodelAudioSeal16-bit payloadprocessC2PA manifestsigned metadatastoreEnrollment3 to 5 clean clips, meanstore
Nodes and connections
NodeRoleKind
Test utterance3 s or moreclient
CountermeasureAASIST or RawNet2model
Speaker encoderECAPA-TDNN, 192-dmodel
Cosine scorethreshold from a dev setprocess
TTS outputevery generationmodel
AudioSeal16-bit payloadprocess
C2PA manifestsigned metadatastore
Enrollment3 to 5 clean clips, meanstore
FromToConnection
Test utteranceCountermeasurereal or fake
CountermeasureSpeaker encoderreal
Speaker encoderCosine score
EnrollmentCosine scoreanchor
TTS outputAudioSeal
AudioSealC2PA manifestsign
Sources

Tasks in code

TaskCode
Verify a speakerverify(enroll, test, threshold=0.75)
EER and its thresholdeer(same_scores, diff_scores)
Diarize a meetingPipeline.from_pretrained("pyannote/speaker-diarization-3.1")
Load the watermark generatorAudioSeal.load_generator("audioseal_wm_16bits")
Detect a watermarkdetector.detect_watermark(watermarked, sample_rate=16000)
Toy spoof featurespectral_rolloff(spec, percentile=0.85)
Toy text watermarkwatermarked_sample(n, seed_prefix, bias=0.9)
Green-token z-scoredetect(tokens)
Sources

Verify with ECAPA

from speechbrain.pretrained import EncoderClassifier
clf = 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 them
score = clf.similarity(enroll, clf.encode_batch(load("test.wav"))).item()
verdict = score > 0.25tune on your data
Sources

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 + watermark
result, decoded_payload = detector.detect_watermark(watermarked, sample_rate=16000)
Sources

Ship a generation

  1. Consent with a clone reference, verify_consent(user_id, clone_reference) first.
  2. Synthesize tts_model.synthesize(text, voice).
  3. Watermark audioseal_embed(audio, payload=build_payload(user_id, model_id)).
  4. Sign c2pa_sign(audio_with_wm, user_id, timestamp=now()) gives the manifest.
  5. Log keep a retention-policy-compliant audit log.
  6. Check run the detector in your CI.
Sources

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.
Sources

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.
Sources

Numbers

SettingDefaultNote
ECAPA embedding192-dWavLM-large is 256-d
ECAPA threshold0.25SpeechBrain typical, tune it
Enrollment samples3-5Clean samples, averaged
ECAPA on VoxCeleb1-O0.87%EER, 15 M params
ASVspoof 5 SOTA~7.23%EER. In the wild expect 5-10%
AudioSeal payload16-bitPer-frame at 16 kHz
AudioSeal detector485× realtime1000× faster than WavMark
Text watermark z4z >= 4 is very strong evidence
Sources

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.
Sources

Troubleshooting

SymptomCauseFix
EER rises on phone callsTrained on VoxCeleb web videoEvaluate on the target channel
EER degrades sharplyTest audio under 3 secondsGet longer test audio
Anchor fails for one speakerOne noisy enrollmentAverage 3 or more clean samples
Magnitude dominates the scoreEmbeddings not normalizedL2-normalize first
Detector fails in the real worldAASIST overfits ASVspoof LACalibrate on your domain
Watermark gone after an editAggressive pitch shiftKeep a detection fallback
Manifest missing on a rehostMetadata strip and re-encodeAdd a watermark too
Text watermark goneParaphraseDo not rely on it alone
Sources

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.
Sources

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.
Sources
Original source
---
id: voice-security
title: Speaker Verification, Spoofing and Watermarks
code: SV
subtitle: Enroll, score and threshold speakers, detect spoofed audio, and mark every generation with a watermark and C2PA.
hue: 0
sources: phases/06-speech-and-audio/06-speaker-recognition-verification, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa
source_hash: 724639f70381c5ae
---

## Verify and mark
type: architecture
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md

```arch
node | test | 1,1 | Test utterance | 3 s or more | client
node | cm | 2,1 | Countermeasure | AASIST or RawNet2 | model
node | emb | 3,1 | Speaker encoder | ECAPA-TDNN, 192-d | model
node | score | 4,1 | Cosine score | threshold from a dev set | process
node | gen | 1,2 | TTS output | every generation | model
node | wm | 2,2 | AudioSeal | 16-bit payload | process
node | c2pa | 3,2 | C2PA manifest | signed metadata | store
node | enr | 4,2 | Enrollment | 3 to 5 clean clips, mean | store
edge | test | cm | real or fake
edge | cm | emb | real
edge | emb | score |
edge | enr | score | anchor
edge | gen | wm |
edge | wm | c2pa | sign
```

## Tasks in code
type: task-table
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/code/main.py
span: 2

| Task | Code |
|---|---|
| Verify a speaker | `verify(enroll, test, threshold=0.75)` |
| EER and its threshold | `eer(same_scores, diff_scores)` |
| Diarize a meeting | `Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")` |
| Load the watermark generator | `AudioSeal.load_generator("audioseal_wm_16bits")` |
| Detect a watermark | `detector.detect_watermark(watermarked, sample_rate=16000)` |
| Toy spoof feature | `spectral_rolloff(spec, percentile=0.85)` |
| Toy text watermark | `watermarked_sample(n, seed_prefix, bias=0.9)` |
| Green-token z-score | `detect(tokens)` |

## Verify with ECAPA
type: annotated-code
lang: python
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md

```python
from speechbrain.pretrained import EncoderClassifier
clf = 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 them
score = clf.similarity(enroll, clf.encode_batch(load("test.wav"))).item()
verdict = score > 0.25                                     # tune on your data
```

## Embed and detect AudioSeal
type: annotated-code
lang: python
from: phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md

```python
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 + watermark
result, decoded_payload = detector.detect_watermark(watermarked, sample_rate=16000)
```

## Ship a generation
type: flow
from: phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md

1. **Consent**: with a clone reference, `verify_consent(user_id, clone_reference)` first.
2. **Synthesize**: `tts_model.synthesize(text, voice)`.
3. **Watermark**: `audioseal_embed(audio, payload=build_payload(user_id, model_id))`.
4. **Sign**: `c2pa_sign(audio_with_wm, user_id, timestamp=now())` gives the manifest.
5. **Log**: keep a retention-policy-compliant audit log.
6. **Check**: run the detector in your CI.

## Formulas
type: concepts
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/code/main.py, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md

- **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.

## Watermark families
type: concepts
from: phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/docs/en.md

- **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.

## Numbers
type: defaults
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/code/main.py

| 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 |

## Abbreviations
type: glossary
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/docs/en.md

- **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.

## Troubleshooting
type: troubleshooting
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/docs/en.md

| 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 |

## Use X when
type: tips
from: phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md, phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md

- 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.

## Questions
type: qa
from: phases/06-speech-and-audio/16-anti-spoofing-audio-watermarking/docs/en.md, phases/18-ethics-safety-alignment/23-watermarking-synthid-stable-signature-c2pa/docs/en.md, phases/06-speech-and-audio/06-speaker-recognition-verification/docs/en.md

- **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.
Code and artifacts 1
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓