Naar inhoud
Inloggen

/docs · SignalLab · Deep

Sprekerwisseling-segmentatie: de pragmatische stack

Diarisatie is een lastig ML-probleem. Sprekerwisseling-segmentatie, de goedkope variant, is voldoende opgelost om overal te gebruiken.


Echte diarisatie (“label elk audiosegment met wie er aan het woord is”) is een lastig ML-probleem en een actief onderzoeksgebied. Sprekerwisseling-segmentatie (“vind de momenten waarop de spreker verandert”) is veel eenvoudiger en bruikbaar voor de meeste downstream-toepassingen.

Voor een audioarchief is “laat me de wisselingen zien” een vaker voorkomend verzoek dan “vertel me wie er spreekt”. Dit document gaat over hoe je de eenvoudigere variant goed bouwt.

De twee problemen, gescheiden

ProbleemMoeilijkheidTools
Sprekerwisseling-segmentatieHanteerbaar op basis van het signaal alleenEnergie- + spectrale-envelopveranderingen
SprekeridentificatieLastig, vereist embeddingsModellen zoals pyannote, NeMo, Resemblyzer
SprekerdiarisatieGecombineerde versie van beideLastig, end-to-end ML-systemen

De meeste mensen die om “diarisatie” vragen, willen eigenlijk sprekerwisseling-segmentatie. Bevestig dit voordat je naar het zware gereedschap grijpt.

De signaal-enkel-aanpak

Een sprekerwisseling verschijnt in het signaal als een discontinuïteit. De eenvoudigste kenmerken die dit vastleggen:

  1. Discontinuïteit in de energie-envelop: sprekers hebben een verschillend basaal volume. Een wisseling uit zich vaak als een sprong in de kortetermijn-RMS.
  2. Verandering in de spectrale envelop: verschillende sprekers hebben verschillende formantpatronen. Zelfs zonder vast te stellen wie het is, kun je detecteren dat er een verandering plaatsvond.
  3. Pauzestructuur: wisselingen worden meestal omlijst door korte pauzes (50–300 ms). Het patroon van pauze-gevolgd-door-ander-spectrum is sterk voorspellend.

Een eenvoudige pipeline:

def segment_turns(samples, sr, min_turn_sec=2.0):
    # 1. Compute MFCCs in 25 ms frames, 10 ms hop
    mfccs = mfcc(samples, sr, n_mfcc=13, hop=int(0.01 * sr))
    # 2. Compute cosine distance between consecutive MFCC frames
    dists = [cosine_distance(mfccs[i], mfccs[i+1]) for i in range(len(mfccs)-1)]
    # 3. Smooth and threshold
    smoothed = moving_average(dists, window=5)
    threshold = percentile(smoothed, 95)
    # 4. Find peaks above threshold separated by min_turn_sec
    peaks = find_peaks(smoothed, height=threshold, distance=int(min_turn_sec / 0.01))
    return [p * 0.01 for p in peaks]  # convert to seconds

Dit is geen state-of-the-art diarisatiesysteem. Het is een functie van 30 regels die op schoon materiaal met twee sprekers 80% van de wisselingen oppikt.

Waarom het werkt

Sprekers verschillen voldoende in hun spectrale enveloppen (bepaald door formantposities, lengte van het spraakkanaal, toonhoogte) dat MFCC-vectoren in onderscheiden gebieden van de kenmerkenruimte belanden. Wanneer de spreker midden in een opname verandert, “springt” de MFCC-vector door die ruimte, en de cosinusafstand tussen opeenvolgende frames piekt.

De eenvoudige smoothing en percentiel-drempelwaarde vangen het grootste deel van de ruis op. Je zult wisselingen missen waarbij sprekers vergelijkbare stemmen hebben, waarbij één spreker veel zachter is, of waarbij er veel overlap is, maar voor een bruikbare tijdlijn op de meeste podcast- en interviewmaterialen werkt dit.

Wanneer opschalen naar echte diarisatie

Je hebt de zwaardere ML-stack nodig wanneer:

  1. Meer dan 2–3 sprekers, vooral met overlap.
  2. Cross-channel-mixing: één mono-bestand met meerdere microfoons op afstand.
  3. Sprekeridentificatie is vereist (niet alleen “er vond een wisseling plaats” maar “spreker A is terug”).
  4. Ruisige praktijkaudio: straatopnames, vergaderingen met slechte akoestiek.

Hiervoor is pyannote.audio momenteel de beste open-source diarisatiepipeline. NeMo is een meer enterprise-grade alternatief. Beide draaien op een GPU en vereisen ~1-5 GB aan modelgewichten, niet browservriendelijk zonder aanzienlijk werk.

Wat SignalLab doet

De SignalLab Indexer (preview aan browserzijde) gebruikt het hierboven beschreven signaal-enkel-patroon voor sprekerwisseling-segmentatie. De volledige versie aan serverzijde routeert naar pyannote wanneer diarisatienauwkeurigheid telt. De versie aan browserzijde is goed genoeg voor QA en verkenning; de versie aan serverzijde is goed genoeg voor productiearchieven.

De beslisboom:

  • Doe je snelle QA bij ingest? Gebruik signaal-enkel-segmentatie.
  • Produceer je per-spreker-metadata voor een archief? Gebruik pyannote.
  • Doe je realtime transcriptie met sprekerlabels? Gebruik de ingebouwde diarisatie van de ASR-provider (Deepgram, AWS).

Gerelateerd