स्पीकर डायराइज़ेशन
एक multi-speaker रिकॉर्डिंग में पहचानें कि कौन कब बोला। दो डायराइज़ेशन इंजन उपलब्ध हैं: एक two-stage Pyannote पाइपलाइन (segmentation + activity-based speaker chaining, फिर post-hoc embedding) और एक end-to-end Sortformer मॉडल (CoreML, Neural Engine)।
इंजन
--engine pyannote (डिफ़ॉल्ट) या --engine sortformer के साथ इंजन चुनें।
Pyannote (डिफ़ॉल्ट)
Two-stage पाइपलाइन: Pyannote segmentation overlapping windows को activity-based speaker chaining (overlap zones में Pearson correlation) के साथ प्रोसेस करता है ताकि global speaker labels असाइन किए जा सकें। Post-hoc WeSpeaker embedding extraction enrollment audio के माध्यम से target speaker पहचान सक्षम करता है।
Sortformer (CoreML)
NVIDIA का end-to-end neural diarization मॉडल। अलग embedding या clustering चरणों के बिना 4 speakers तक के लिए प्रति-फ़्रेम speaker activity का सीधे अनुमान लगाता है। CoreML के माध्यम से Neural Engine पर streaming state buffers (FIFO + speaker cache) के साथ चलता है।
Sortformer स्पीकर embeddings उत्पन्न नहीं करता है। --target-speaker और --embedding-engine flags केवल Pyannote इंजन के साथ उपलब्ध हैं।
Pyannote पाइपलाइन
डिफ़ॉल्ट पाइपलाइन दो चरणों में चलती है:
चरण 1: Segmentation + Speaker Chaining
Pyannote segmentation-3.0 50% overlap के साथ 10-सेकंड sliding windows प्रोसेस करता है। एक powerset decoder 7-class आउटपुट को प्रति-speaker probabilities (प्रति window 3 local speakers तक) में कन्वर्ट करता है। आसन्न windows 5-सेकंड overlap साझा करते हैं — speaker identity को overlap zone में probability tracks के बीच Pearson correlation की गणना करके windows में प्रसारित किया जाता है, जिसमें सुसंगत global speaker IDs के लिए greedy exclusive matching होती है।
चरण 2: Post-hoc Embedding
डायराइज़ेशन के बाद, WeSpeaker ResNet34-LM प्रति speaker एक 256-dimensional centroid embedding निकालता है। ये embeddings target speaker extraction (--target-speaker) सक्षम करते हैं, लेकिन स्वयं speaker assignment को drive नहीं करते।
pyannote.audio से Migrate करना
यदि आप Python pyannote.audio library से आ रहे हैं — एक Pipeline subclass को replace कर रहे हैं जो pipeline.segmentation = ... set करती है, या pyannote/speaker-diarization-3.1 host करने वाले server से migrate कर रहे हैं — Soniqo उसी Pyannote-Segmentation-3.0 model को wrap करता है और इसे Apple Silicon पर पूरी तरह on-device चलाता है। कोई Python runtime, CUDA, या inference time पर Hugging Face token नहीं चाहिए।
| pyannote.audio (Python) | Soniqo (Swift) |
|---|---|
Pipeline.from_pretrained("pyannote/speaker-diarization-3.1") |
DiarizationPipeline.fromPretrained() |
pipeline(audio_file) |
pipeline.diarize(audio: samples, sampleRate: 16000) |
pipeline.segmentation = ... (custom subclass) |
Fixed: Pyannote-Segmentation-3.0 (MLX या CoreML, auto-selected) |
diarization.itertracks(yield_label=True) |
for seg in result.segments { ... } |
diarization.write_rttm(file) |
CLI: --rttm |
pyannote.metrics.diarization.DiarizationErrorRate |
CLI: --score-against reference.rttm |
Pyannote-Segmentation-3.0 weights upstream HuggingFace checkpoint से convert किए गए हैं, इसलिए segmentation logits float-precision tolerance के भीतर numerically equivalent हैं। Post-segmentation chaining (overlapping windows पर Pearson correlation + greedy exclusive matching) और post-hoc WeSpeaker embedding stages Swift में reimplement किए गए हैं, लेकिन reference Python pipeline से comparable RTTM output produce करते हैं।
Pyannote engine के लिए OnlineSpeakerDiarization के बराबर कोई streaming API नहीं है। Real-time diarization के लिए --engine sortformer का use करें, जो Sortformer model को FIFO + speaker-cache state buffers के साथ चलाता है।
CLI उपयोग
# Basic diarization (pyannote, default)
.build/release/speech diarize meeting.wav
# End-to-end Sortformer (CoreML)
.build/release/speech diarize meeting.wav --engine sortformer
# RTTM output format (for evaluation)
.build/release/speech diarize meeting.wav --rttm
# JSON output
.build/release/speech diarize meeting.wav --json
Target Speaker Extraction
एक ज्ञात speaker का enrollment audio प्रदान करें ताकि उसके केवल segments को रिकॉर्डिंग से निकाला जा सके। पाइपलाइन enrollment audio का speaker embedding कंप्यूट करती है और उच्चतम cosine similarity वाले cluster को खोजती है।
# Extract segments for a specific speaker
.build/release/speech diarize meeting.wav --target-speaker enrollment.wav
DER Scoring
एक reference RTTM फ़ाइल के विरुद्ध scoring करके डायराइज़ेशन गुणवत्ता का मूल्यांकन करें। पाइपलाइन Diarization Error Rate (DER) कंप्यूट करती है, जो समय के अनुपात को मापती है जो गलत तरीके से attributed है।
# Score against reference RTTM
.build/release/speech diarize meeting.wav --score-against reference.rttm
RTTM आउटपुट
--rttm flag Rich Transcription Time Marked आउटपुट उत्पन्न करता है, जो डायराइज़ेशन मूल्यांकन के लिए उपयोग किया जाने वाला एक मानक फ़ॉर्मैट है। प्रत्येक line इस फ़ॉर्मैट का अनुसरण करती है:
SPEAKER filename 1 start_time duration <NA> <NA> speaker_id <NA> <NA>
विकल्प
| विकल्प | विवरण |
|---|---|
--target-speaker | Target speaker extraction के लिए enrollment ऑडियो (केवल pyannote) |
--embedding-engine | Speaker embedding इंजन: mlx या coreml (केवल pyannote) |
--vad-filter | Silero VAD के साथ pre-filter (केवल pyannote) |
--rttm | RTTM फ़ॉर्मैट में आउटपुट |
--json | JSON आउटपुट फ़ॉर्मैट |
--score-against | DER मूल्यांकन के लिए reference RTTM फ़ाइल |
डायराइज़ेशन उन रिकॉर्डिंग के साथ सबसे अच्छा काम करता है जिनमें स्पष्ट speaker turns होते हैं। अत्यधिक overlapping speech सटीकता को कम कर सकती है। Speaker count स्वचालित रूप से निर्धारित होता है।
मॉडल डाउनलोड
मॉडल पहले उपयोग पर स्वचालित रूप से डाउनलोड होते हैं:
| कॉम्पोनेंट | मॉडल | आकार | HuggingFace |
|---|---|---|---|
| Segmentation | Pyannote-Segmentation-3.0 | ~5.7 MB | aufklarer/Pyannote-Segmentation-MLX |
| Speaker Embedding | WeSpeaker-ResNet34-LM (MLX) | ~25 MB | aufklarer/WeSpeaker-ResNet34-LM-MLX |
| Speaker Embedding | WeSpeaker-ResNet34-LM (CoreML) | ~25 MB | aufklarer/WeSpeaker-ResNet34-LM-CoreML |
| Sortformer | Sortformer Diarization (CoreML) | ~240 MB | aufklarer/Sortformer-Diarization-CoreML |
Swift API
import SpeechVAD
let pipeline = try await DiarizationPipeline.fromPretrained()
let result = pipeline.diarize(audio: samples, sampleRate: 16000)
for seg in result.segments {
print("Speaker \(seg.speakerId): [\(seg.startTime)s - \(seg.endTime)s]")
}
// Target speaker extraction
let targetEmb = pipeline.embeddingModel.embed(audio: enrollmentAudio, sampleRate: 16000)
let segments = pipeline.extractSpeaker(
audio: meetingAudio, sampleRate: 16000,
targetEmbedding: targetEmb
)