Diarisation audio : qui parle quand avec Whisper et pyannote.audio en Python
Publié le — Par l'équipe DEV-AI
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 :
- Transcription (
task="transcribe") : convertit la parole en texte, dans la langue d'origine. - Traduction (
task="translate") : convertit la parole en texte anglais, quelle que soit la langue source — voir notre guide dédié sur la traduction avec Whisper. - Diarisation : répond à « qui a parlé, et quand » — sans se soucier du contenu du discours. C'est un problème entièrement différent, que Whisper ne résout pas du tout.
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 :
- Installez la bibliothèque :
pip install pyannote.audio - Créez un token d'accès Hugging Face sur hf.co/settings/tokens
- 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.
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 ne fait jamais de diarisation — c'est un problème distinct qui nécessite
pyannote.audio. - N'oubliez pas d'accepter l'accord d'utilisation sur Hugging Face avant d'utiliser le modèle — c'est l'erreur n°1 des débutants.
- Indiquer
num_speakers(ou une fourchettemin_speakers/max_speakers) améliore significativement la précision. - La parole superposée reste une limite réelle de la diarisation actuelle — pas une précision parfaite garantie.
- WhisperX est le choix le plus rapide à mettre en place pour la majorité des usages ; la fusion manuelle garde l'avantage pour les besoins sur mesure.
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 →