Диаризация спикеров

Определите, кто и когда говорил в многоспикерной записи. Доступны два движка диаризации: двухэтапный пайплайн 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
SortformerSortformer 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
)