Phase 06 - Lesson 06
Reconocimiento y Verificación de Hablante
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
El ASR pregunta "¿qué dijeron?". El reconocimiento de hablante pregunta "¿quién lo dijo?". La matemática parece la misma — embeddings más coseno — pero cada decisión de producción depende de un único número de EER.
Tipo: Build Lenguajes: Python Prerrequisitos: Fase 6 · 02 (Espectrogramas y Mel), Fase 5 · 22 (Modelos de Embedding) Tiempo: ~45 minutos
El Problema
Un usuario dice una frase secreta. Quieres saber: ¿es esta la persona que dice ser (verificación, 1:1), o es la primera persona en tu banco de inscripción (identificación, 1:N)? ¿O ninguna de las dos — es un hablante desconocido (open-set)?
Antes de 2018: GMM-UBM + i-vectors. EER razonable pero frágil ante el cambio de canal (teléfono vs laptop) y la emoción. 2018–2022: x-vectors (backbone TDNN entrenado con margen angular). 2022+: embeddings ECAPA-TDNN y WavLM-large. Para 2026 el campo está dominado por tres modelos y una métrica.
La métrica es el EER — Equal Error Rate (tasa de error igual). Ajusta tu umbral de decisión de modo que la Tasa de Falsa Aceptación = Tasa de Falso Rechazo. El punto de cruce es el EER. Se usa en cada artículo, cada leaderboard, cada licitación.
El Concepto
El pipeline. Inscripción: graba de 5 a 30 segundos del hablante objetivo; calcula un embedding de dimensión fija (192-d para ECAPA-TDNN, 256-d para WavLM-large). Verificación: obtén el embedding de la locución de prueba; calcula la similitud de coseno; compara contra un umbral.
ECAPA-TDNN (2020, todavía dominante en 2026). Emphasized Channel Attention, Propagation and Aggregation - Time-Delay Neural Network. Bloques de convolución 1D con squeeze-excitation, pooling por atención multi-cabeza, seguidos de una capa lineal a 192-d. Entrenado en VoxCeleb 1+2 (2.700 hablantes, 1,1 M de locuciones) con la pérdida Additive Angular Margin (AAM-softmax).
WavLM-SV (2022+). Haz fine-tuning de un backbone SSL WavLM-large preentrenado con pérdida AAM. Mayor calidad pero más lento — 300+ MB vs 15 MB.
x-vector (baseline). TDNN + statistics pooling. Clásico; aún útil en CPU / edge.
AAM-softmax. Softmax estándar con un margen m agregado en el espacio angular: cos(θ + m) para la clase correcta. Fuerza la separación angular entre clases. m=0.2 típico, escala s=30.
Puntuación
- Coseno entre los embeddings de inscripción y de prueba. Decisión basada en umbral.
- PLDA (LDA Probabilístico). Proyecta los embeddings en un espacio latente donde mismo-hablante vs hablante-diferente tiene una razón de verosimilitud en forma cerrada. Se agrega sobre el coseno para una reducción de EER de +10–20%. Estándar antes de 2020; ahora se usa solo en configuraciones closed-set.
- Normalización de score.
S-normoAS-norm: normaliza cada score contra un cohort de medias y desviaciones estándar de impostores. Esencial para evaluación cross-domain.
Números que deberías conocer (2026)
| Modelo | VoxCeleb1-O EER | Parámetros | Throughput (A100) |
|---|---|---|---|
| x-vector (clásico) | 3.10% | 5 M | 400× RT |
| ECAPA-TDNN | 0.87% | 15 M | 200× RT |
| WavLM-SV large | 0.42% | 316 M | 20× RT |
| Pyannote 3.1 segmentación + embedding | 0.65% | 6 M | 100× RT |
| ReDimNet (2024) | 0.39% | 24 M | 100× RT |
Diarización
"Quién habló cuándo" en un clip con múltiples hablantes. Pipeline: VAD → segmentar → embedar cada segmento → clusterizar (aglomerativo o espectral) → suavizar fronteras. Stack moderno: pyannote.audio 3.1, que reúne segmentación de hablante + embedding + clustering detrás de una sola llamada. El DER SOTA de 2026 en AMI es ~15% (a la baja desde el 23% de 2022).
Constrúyelo
Paso 1: embedding de juguete a partir de estadísticas de MFCC
def embed_mfcc_stats(signal, sr):
frames = featurize_mfcc(signal, sr, n_mfcc=13)
mean = [sum(f[i] for f in frames) / len(frames) for i in range(13)]
std = [
math.sqrt(sum((f[i] - mean[i]) ** 2 for f in frames) / len(frames))
for i in range(13)
]
return mean + std # 26-d
Lejos de SOTA — solo con fines didácticos. code/main.py lo usa como prueba de concepto sobre datos sintéticos de hablantes.
Paso 2: similitud de coseno + umbral
def cosine(a, b):
dot = sum(x * y for x, y in zip(a, b))
na = math.sqrt(sum(x * x for x in a))
nb = math.sqrt(sum(x * x for x in b))
return dot / (na * nb) if na and nb else 0.0
def verify(enroll, test, threshold=0.75):
return cosine(enroll, test) >= threshold
Paso 3: EER a partir de pares de similitud
def eer(same_scores, diff_scores):
thresholds = sorted(set(same_scores + diff_scores))
best = (1.0, 1.0, 0.0) # (fa, fr, threshold)
for t in thresholds:
fr = sum(1 for s in same_scores if s < t) / len(same_scores)
fa = sum(1 for s in diff_scores if s >= t) / len(diff_scores)
if abs(fa - fr) < abs(best[0] - best[1]):
best = (fa, fr, t)
return (best[0] + best[1]) / 2, best[2]
Devuelve (eer, threshold_at_eer). Reporta ambos.
Paso 4: producción con SpeechBrain
from speechbrain.pretrained import EncoderClassifier
clf = EncoderClassifier.from_hparams(source="speechbrain/spkrec-ecapa-voxceleb")
# enroll: average the embeddings of 3-5 clean samples
enroll = torch.stack([clf.encode_batch(load(x)) for x in enrollment_clips]).mean(0)
# verify
score = clf.similarity(enroll, clf.encode_batch(load("test.wav"))).item()
verdict = score > 0.25 # ECAPA typical threshold; tune on your data
Paso 5: diariza con pyannote
from pyannote.audio import Pipeline
pipe = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")
diarization = pipe("meeting.wav", num_speakers=None)
for turn, _, speaker in diarization.itertracks(yield_label=True):
print(f"{turn.start:.1f}–{turn.end:.1f} {speaker}")
Úsalo
El stack de 2026:
| Situación | Elección |
|---|---|
| Verificación 1:1 closed-set, edge | ECAPA-TDNN + umbral de coseno |
| Verificación open-set, nube | WavLM-SV + AS-norm |
| Diarización (reuniones, podcasts) | pyannote/speaker-diarization-3.1 |
| Anti-spoofing (detección de replay / deepfake) | AASIST o RawNet2 |
| Embebido diminuto (KWS + inscripción) | Titanet-Small (NeMo) |
Trampas
- Desajuste de canal. Modelo entrenado en VoxCeleb (video web) ≠ audio de llamada telefónica. Evalúa siempre en el canal objetivo.
- Locuciones cortas. El EER se degrada bruscamente por debajo de 3 segundos de audio de prueba.
- Inscripción con ruido. Una sola inscripción ruidosa envenena el anclaje. Usa ≥3 muestras limpias y promedia.
- Umbral fijo entre condiciones. Ajusta siempre el umbral en un conjunto de dev separado del dominio objetivo.
- Coseno sobre embeddings no normalizados. Normaliza por L2 primero; de lo contrario, la magnitud domina.
Entrégalo
Guarda como outputs/skill-speaker-verifier.md. Elige el modelo, el protocolo de inscripción, el plan de ajuste de umbral y las salvaguardas contra fraude.
Ejercicios
- Fácil. Ejecuta
code/main.py. Construye "hablantes" sintéticos (perfiles de tono diferentes), inscribe, calcula el EER sobre una lista de prueba de 100 pares. - Medio. Usa el ECAPA de SpeechBrain en 30 locuciones de VoxCeleb1 (5 hablantes × 6 cada uno). Calcula el EER con coseno vs PLDA.
- Difícil. Construye el pipeline completo inscripción → diarización → verificación con
pyannote.audio. Evalúa el DER en el conjunto de dev de AMI.
Términos Clave
| Término | Lo que dice la gente | Lo que realmente significa |
|---|---|---|
| EER | La métrica principal | Umbral donde Falsa Aceptación = Falso Rechazo. |
| Verificación | 1:1 | "¿Es esta Alice?" |
| Identificación | 1:N | "¿Quién está hablando?" |
| Open-set | Desconocido posible | El conjunto de prueba puede contener hablantes no inscritos. |
| Inscripción | Registrar | Calcular el embedding de referencia de un hablante. |
| AAM-softmax | La pérdida | Softmax con margen angular aditivo; fuerza la separación de clusters. |
| PLDA | Puntuación clásica | LDA Probabilístico; puntuación por razón de verosimilitud sobre los embeddings. |
| DER | Métrica de diarización | Diarization Error Rate — miss + falsa alarma + confusión. |
Lecturas Adicionales
- Snyder et al. (2018). X-Vectors: Robust DNN Embeddings for Speaker Recognition — el clásico artículo de embedding profundo.
- Desplanques et al. (2020). ECAPA-TDNN — arquitectura dominante 2020–2026.
- Chen et al. (2022). WavLM: Large-Scale Self-Supervised Pre-Training for Full Stack Speech Processing — backbone SSL para SV y diarización.
- Bredin et al. (2023). pyannote.audio 3.1 — stack de diarización + embedding de producción.
- VoxCeleb leaderboard (actualizado en 2026) — clasificación actual de EER entre modelos.