DEV-AI

Diarisation audio : qui parle quand avec Whisper et pyannote.audio en Python

Publié le — Par l'équipe DEV-AI

Diarisation audio avec Whisper et pyannote.audio en Python
En résumé : Whisper transcrit ce qui est dit, jamais qui le dit. Pour obtenir « Speaker A : bonjour » / « Speaker B : bonjour » à partir d'une réunion ou d'une interview à plusieurs voix, il faut combiner Whisper avec un modèle de diarisation dédié — pyannote.audio, la référence open source du domaine. Ce guide couvre la méthode manuelle (contrôle total) et le raccourci WhisperX (tout-en-un), avec les astuces qui font la différence en production.

Diarisation, transcription, traduction : trois problèmes distincts

Si vous arrivez sur cette page en cherchant à savoir « qui parle quand » dans un enregistrement, il est important de poser une distinction que beaucoup de tutoriels mélangent :

Whisper n'a aucune notion de locuteur : il peut transcrire fidèlement une conversation entre trois personnes sans jamais indiquer qui a dit quoi. Pour ça, il faut un modèle spécialisé — pyannote.audio, devenu la référence open source de facto pour la diarisation en 2026 — puis fusionner son résultat avec la transcription de Whisper. C'est tout l'objet de ce guide.

Si vous découvrez Whisper, notre guide de transcription en français couvre l'installation et le choix du modèle — ce guide-ci part du principe que vous savez déjà transcrire un audio.

Installation et accès au modèle pyannote

En 2026, le pipeline open source recommandé par pyannote.audio est pyannote/speaker-diarization-community-1. Il succède au pipeline speaker-diarization-3.1, désormais présenté comme « legacy » dans les benchmarks officiels, avec notamment de meilleures performances de comptage et d'attribution des locuteurs.

L'installation reste simple :

  1. Installez la bibliothèque : pip install pyannote.audio
  2. Créez un token d'accès Hugging Face sur hf.co/settings/tokens
  3. Rendez-vous sur la page du modèle pyannote/speaker-diarization-community-1 et acceptez ses conditions d'accès

Le modèle est accessible gratuitement, mais son dépôt Hugging Face est gated : les modèles pyannote distribués via Hugging Face peuvent nécessiter l'acceptation préalable de leurs conditions d'accès. Sans cette étape, le téléchargement du modèle peut échouer même si votre token Hugging Face est valide.

Astuce : l'étape 3 est celle que tout le monde oublie. Si votre script plante avec une erreur d'accès au modèle alors que votre token est correct, c'est presque toujours parce que vous n'avez pas validé l'accord sur la page Hugging Face du modèle — pas un problème de code.

Diariser un audio (sans transcription)

Voici la diarisation pure : on obtient les plages temporelles de chaque locuteur, sans texte.

from pyannote.audio import Pipeline
import torch

pipeline = Pipeline.from_pretrained(
    "pyannote/speaker-diarization-community-1",
    token="VOTRE_TOKEN_HUGGING_FACE"
)

# Envoie le pipeline sur GPU si disponible (bien plus rapide)
if torch.cuda.is_available():
    pipeline.to(torch.device("cuda"))

output = pipeline("reunion.wav")

for turn, speaker in output.speaker_diarization:
    print(f"{turn.start:.1f}s - {turn.end:.1f}s : {speaker}")
    # → 0.0s - 4.2s : SPEAKER_00
    # → 4.2s - 9.8s : SPEAKER_01

Les labels SPEAKER_00, SPEAKER_01... sont anonymes et arbitraires : pyannote ne sait pas qui est qui, seulement qu'il s'agit de voix différentes. Leur attribuer de vrais noms est une étape manuelle (ou heuristique) à part — voir l'astuce 5 plus bas.

Fusionner Whisper et pyannote : le vrai objectif

La diarisation seule n'a d'intérêt que combinée à la transcription. Le principe : pour chaque segment transcrit par Whisper, on cherche le locuteur pyannote dont la plage temporelle chevauche le plus ce segment.

import whisper
from pyannote.audio import Pipeline

# 1. Transcription avec Whisper (segments horodatés)
whisper_model = whisper.load_model("medium")
transcription = whisper_model.transcribe("reunion.wav")

# 2. Diarisation avec pyannote
diar_pipeline = Pipeline.from_pretrained(
    "pyannote/speaker-diarization-community-1",
    token="VOTRE_TOKEN_HUGGING_FACE"
)
output = diar_pipeline("reunion.wav")

# 3. Fonction de fusion : pour un segment donné, trouve le locuteur
# dont la plage de parole chevauche le plus ce segment (heuristique simple)
def locuteur_dominant(debut, fin, diarization):
    chevauchements = {}
    for turn, speaker in diarization.speaker_diarization:
        overlap = max(0, min(fin, turn.end) - max(debut, turn.start))
        if overlap > 0:
            chevauchements[speaker] = chevauchements.get(speaker, 0) + overlap
    return max(chevauchements, key=chevauchements.get) if chevauchements else "INCONNU"

# 4. Fusion finale
for segment in transcription["segments"]:
    speaker = locuteur_dominant(segment["start"], segment["end"], output)
    print(f"[{speaker}] {segment['text'].strip()}")
    # → [SPEAKER_00] Bonjour à tous, on commence la réunion.
    # → [SPEAKER_01] Oui, j'ai le compte-rendu sous les yeux.

Bonus : la diarisation exclusive de pyannote

Le pipeline speaker-diarization-community-1 fournit également une diarisation exclusive, pensée notamment pour faciliter la synchronisation avec une transcription. La diarisation classique peut représenter plusieurs locuteurs actifs simultanément lorsqu'ils parlent en même temps, tandis que la diarisation exclusive produit une chronologie dans laquelle un seul locuteur est retenu à chaque instant.

output = pipeline("reunion.wav")
# Diarisation classique : peut représenter les chevauchements
diarization = output.speaker_diarization
# Diarisation exclusive : un seul locuteur à chaque instant
exclusive_diarization = output.exclusive_speaker_diarization

Cette représentation exclusive peut être particulièrement pratique pour attribuer un locuteur aux segments d'une transcription, car elle évite d'avoir à arbitrer directement entre plusieurs locuteurs actifs au même instant. Pour l'utiliser dans la fonction de fusion présentée plus haut, il suffit de parcourir output.exclusive_speaker_diarization à la place de output.speaker_diarization.

5 astuces pro pour une diarisation fiable en production

1. Indiquez le nombre de locuteurs si vous le connaissez

Lorsque le nombre de locuteurs est connu, le fournir au pipeline permet de contraindre directement le clustering et peut éviter certaines erreurs de comptage ou d'attribution :

# Nombre exact connu
output = diar_pipeline("reunion.wav", num_speakers=3)

# Ou une fourchette si vous n'êtes pas sûr
output = diar_pipeline(
    "reunion.wav",
    min_speakers=2,
    max_speakers=5
)

2. GPU fortement recommandé pour les fichiers longs

La diarisation et la transcription peuvent fonctionner sur CPU, mais le traitement devient rapidement plus lent lorsque la durée des fichiers augmente. Pour des fichiers longs ou du traitement en volume, un GPU est donc fortement recommandé : avec un GPU CUDA, pyannote peut exécuter son pipeline sur l'accélérateur, tandis que faster-whisper permet également d'accélérer fortement la transcription. Pour un usage ponctuel ou des fichiers relativement courts, une exécution CPU reste parfaitement possible.

3. La parole superposée reste plus difficile à traiter

Quand deux personnes parlent en même temps — lors d'une interruption ou d'une réunion animée, par exemple — la diarisation devient plus difficile. La diarisation classique de pyannote peut représenter des segments de parole qui se chevauchent et donc plusieurs locuteurs actifs simultanément. En revanche, distinguer correctement les voix et leurs frontières temporelles reste généralement plus difficile dans ces situations que lorsque les personnes parlent successivement. La sortie exclusive_speaker_diarization, elle, résout volontairement ces chevauchements pour produire une chronologie avec un seul locuteur à chaque instant, ce qui peut faciliter l'alignement avec une transcription.

4. Alignez sur les segments Whisper, pas l'inverse

Dans la fonction de fusion ci-dessus, on part des segments Whisper et on leur attribue un locuteur — pas l'inverse. C'est important : les segments de pyannote ne correspondent pas aux limites naturelles des phrases, alors que les segments Whisper sont déjà découpés de façon à peu près lisible. Partir des segments pyannote donnerait un texte haché en plein milieu des phrases.

5. Remplacer les labels anonymes par de vrais noms

SPEAKER_00 et SPEAKER_01 ne veulent rien dire pour un lecteur humain. Une fois la fusion faite, un simple dictionnaire de correspondance suffit si vous connaissez l'ordre d'intervention ({"SPEAKER_00": "Alice", "SPEAKER_01": "Bob"}). Pour une identification automatique par la voix elle-même (reconnaissance de locuteur, pas juste diarisation), il faudrait un modèle d'identification de locuteur entraîné sur des échantillons de référence — un problème différent, hors du périmètre de cet article.

Le raccourci WhisperX : tout-en-un

WhisperX combine faster-whisper pour la transcription, un alignement forcé permettant d'obtenir des timestamps beaucoup plus précis au niveau des mots, et pyannote.audio pour la diarisation. L'attribution des locuteurs peut donc s'appuyer sur des timestamps au niveau des mots plutôt que uniquement sur les segments produits par Whisper. C'est l'option la plus rapide à mettre en place si vous ne voulez pas gérer la fusion manuellement.

# pip install whisperx
import whisperx
from whisperx.diarize import DiarizationPipeline

device = "cuda"
audio_file = "reunion.wav"
batch_size = 16
compute_type = "float16"

# 1. Transcription
model = whisperx.load_model("large-v2", device, compute_type=compute_type)
audio = whisperx.load_audio(audio_file)
result = model.transcribe(audio, batch_size=batch_size)

# 2. Alignement mot par mot
align_model, metadata = whisperx.load_align_model(language_code=result["language"], device=device)
result = whisperx.align(result["segments"], align_model, metadata, audio, device)

# 3. Diarisation (nécessite le même token Hugging Face)
diarize_model = DiarizationPipeline(token="VOTRE_TOKEN_HUGGING_FACE", device=device)
diarize_segments = diarize_model(audio_file)

# 4. Attribution des locuteurs aux mots/segments
result = whisperx.assign_word_speakers(diarize_segments, result)

for segment in result["segments"]:
    speaker = segment.get("speaker", "INCONNU")
    print(f"[{speaker}] {segment['text'].strip()}")

Le projet annonce jusqu'à 70× le temps réel avec large-v2 grâce à l'inférence par batch. Cette valeur correspond à une performance annoncée dans les benchmarks du projet et non à une vitesse garantie : les performances réelles dépendent notamment du GPU, du batch_size, du modèle utilisé et de la durée de l'audio.

Méthode manuelle vs WhisperX : lequel choisir ?

Critère Whisper + pyannote (manuel) WhisperX
Précision d'attribution Par segment (phrase) Par mot (alignement forcé)
Mise en place Fusion manuelle à écrire soi-même Fonctions prêtes à l'emploi
Contrôle fin Total sur chaque étape Limité à l'API du pipeline
Vitesse (GPU) Dépend de l'implémentation Jusqu'à 70× temps réel annoncé par le projet (large-v2)
Accès pyannote Token HF requis Même token HF requis

En clair : WhisperX convient à la grande majorité des usages (meeting notes, podcasts, interviews) grâce à son alignement temporel au niveau des mots et sa rapidité. La méthode manuelle garde son intérêt quand vous avez besoin de logique métier spécifique dans la fusion (pondération différente selon le contexte, post-traitement particulier) que le pipeline WhisperX n'expose pas.

Bonus : sous-titres SRT avec noms des locuteurs

Comme pour la traduction, les segments horodatés se prêtent directement à la génération de sous-titres. Il suffit de préfixer le texte de chaque segment avec le label du locuteur avant de l'écrire dans le fichier .srt, en conservant les mêmes horodatages que ceux produits par Whisper — voir notre guide de transcription pour le détail du format SRT.

En résumé

Whisper pyannote Diarisation Python WhisperX NLP

Envie de tester la transcription sans écrire de code ?

Notre outil de transcription audio propulsé par Whisper est gratuit, sans passer par une API tierce.

Transcrire un audio gratuitement →

Articles liés

Questions fréquentes

Whisper peut-il dire qui parle dans un audio ?

Non. Whisper transcrit le contenu parlé mais n'a aucune notion de locuteur. Pour savoir qui parle quand, il faut un modèle de diarisation dédié comme pyannote.audio, puis fusionner ses résultats avec la transcription de Whisper.

Comment installer pyannote.audio et accéder au modèle ?

pip install pyannote.audio, puis créer un token sur hf.co/settings/tokens et accepter l'accord d'utilisation sur la page Hugging Face du modèle pyannote/speaker-diarization-community-1. Sans cette acceptation, le téléchargement échoue.

Qu'est-ce que WhisperX et en quoi diffère-t-il de la méthode manuelle ?

WhisperX combine faster-whisper, un alignement forcé permettant d'obtenir des timestamps plus précis au niveau des mots, et pyannote pour la diarisation. Il fournit ainsi un pipeline plus intégré que la fusion manuelle Whisper + pyannote, tout en permettant d'attribuer les locuteurs avec une granularité plus fine.

pyannote.audio gère-t-il les locuteurs qui parlent en même temps ?

Oui, la diarisation classique de pyannote peut représenter des segments où plusieurs locuteurs parlent simultanément. Ces situations restent toutefois plus difficiles à analyser correctement que la parole non superposée. Le pipeline community-1 fournit également une diarisation exclusive qui résout volontairement les chevauchements afin de conserver un seul locuteur à chaque instant, ce qui facilite notamment l'alignement avec une transcription.

Comment améliorer la précision si je connais le nombre de locuteurs ?

Passez num_speakers à l'appel du pipeline si le nombre exact est connu, ou min_speakers/max_speakers pour une fourchette. Ça réduit significativement les erreurs de sur- ou sous-segmentation.

Aller plus loin

Formation recommandée