Диаризация спикеров
Определите, кто и когда говорил в многоспикерной записи. Доступны два движка диаризации: двухэтапный пайплайн Pyannote (сегментация + связывание спикеров на основе активности, затем пост-обработка с эмбеддингами) и end-to-end модель Sortformer (CoreML, Neural Engine).
Движки
Выберите движок через --engine pyannote (по умолчанию) или --engine sortformer.
Pyannote (по умолчанию)
Двухэтапный пайплайн: сегментация Pyannote обрабатывает перекрывающиеся окна со связыванием спикеров на основе активности (корреляция Пирсона в зонах перекрытия) для назначения глобальных меток спикеров. Пост-обработка с извлечением эмбеддингов WeSpeaker обеспечивает идентификацию целевого спикера по аудио-регистрации.
Sortformer (CoreML)
End-to-end нейронная модель диаризации от NVIDIA. Напрямую предсказывает активность спикеров по кадрам до 4 спикеров без отдельных стадий эмбеддинга или кластеризации. Работает на Neural Engine через CoreML со стейт-буферами для потокового режима (FIFO + кеш спикеров).
Sortformer не создаёт эмбеддинги спикеров. Флаги --target-speaker и --embedding-engine доступны только с движком Pyannote.
Пайплайн Pyannote
Пайплайн по умолчанию работает в два этапа:
Этап 1: Сегментация + связывание спикеров
Pyannote segmentation-3.0 обрабатывает 10-секундные скользящие окна с перекрытием 50%. Powerset-декодер преобразует 7-классовый вывод в вероятности по спикерам (до 3 локальных спикеров на окно). Соседние окна имеют 5-секундное перекрытие — идентичность спикера распространяется между окнами через вычисление корреляции Пирсона между дорожками вероятностей в зоне перекрытия, с жадным эксклюзивным сопоставлением для консистентных глобальных ID спикеров.
Этап 2: Пост-обработка эмбеддингов
После диаризации WeSpeaker ResNet34-LM извлекает 256-мерный центроидный эмбеддинг на каждого спикера. Эти эмбеддинги позволяют извлечение целевого спикера (--target-speaker), но не влияют на само назначение спикеров.
Использование CLI
# Базовая диаризация (pyannote, по умолчанию)
.build/release/audio diarize meeting.wav
# End-to-end Sortformer (CoreML)
.build/release/audio diarize meeting.wav --engine sortformer
# Формат вывода RTTM (для оценки)
.build/release/audio diarize meeting.wav --rttm
# JSON-вывод
.build/release/audio diarize meeting.wav --json
Извлечение целевого спикера
Предоставьте аудио-регистрацию известного спикера, чтобы извлечь из записи только его сегменты. Пайплайн вычисляет эмбеддинг спикера из аудио-регистрации и находит кластер с наибольшим косинусным сходством.
# Извлечь сегменты конкретного спикера
.build/release/audio diarize meeting.wav --target-speaker enrollment.wav
Оценка DER
Оцените качество диаризации, сопоставляя с эталонным файлом RTTM. Пайплайн вычисляет Diarization Error Rate (DER), который измеряет долю времени, отнесённого неправильно.
# Оценка против эталонного RTTM
.build/release/audio diarize meeting.wav --score-against reference.rttm
Вывод RTTM
Флаг --rttm выдаёт вывод в формате Rich Transcription Time Marked — стандартном формате для оценки диаризации. Каждая строка имеет вид:
SPEAKER filename 1 start_time duration <NA> <NA> speaker_id <NA> <NA>
Опции
| Опция | Описание |
|---|---|
--target-speaker | Аудио-регистрация для извлечения целевого спикера (только pyannote) |
--embedding-engine | Движок эмбеддингов спикеров: mlx или coreml (только pyannote) |
--vad-filter | Предварительная фильтрация через Silero VAD (только pyannote) |
--rttm | Вывод в формате RTTM |
--json | Формат вывода JSON |
--score-against | Эталонный RTTM-файл для оценки DER |
Диаризация лучше всего работает на записях с чёткими сменами спикеров. Сильно перекрывающаяся речь может снижать точность. Количество спикеров определяется автоматически.
Загрузка моделей
Модели автоматически скачиваются при первом использовании:
| Компонент | Модель | Размер | HuggingFace |
|---|---|---|---|
| Сегментация | Pyannote-Segmentation-3.0 | ~5.7 МБ | aufklarer/Pyannote-Segmentation-MLX |
| Эмбеддинг спикера | WeSpeaker-ResNet34-LM (MLX) | ~25 МБ | aufklarer/WeSpeaker-ResNet34-LM-MLX |
| Эмбеддинг спикера | WeSpeaker-ResNet34-LM (CoreML) | ~25 МБ | aufklarer/WeSpeaker-ResNet34-LM-CoreML |
| Sortformer | Sortformer Diarization (CoreML) | ~240 МБ | 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]")
}
// Извлечение целевого спикера
let targetEmb = pipeline.embeddingModel.embed(audio: enrollmentAudio, sampleRate: 16000)
let segments = pipeline.extractSpeaker(
audio: meetingAudio, sampleRate: 16000,
targetEmbedding: targetEmb
)