Diarizacao de falantes
Identifique quem falou quando em uma gravacao multi-locutor. Ha tres engines: Pyannote leve e padrao, Community-1 com pipeline completo (CoreML + PLDA/VBx nativo) e Sortformer para streaming.
Engines
Selecione --engine pyannote (padrao), --engine community1 ou --engine sortformer.
Pyannote (padrao)
Pipeline de duas etapas: a segmentacao Pyannote processa janelas sobrepostas com encadeamento de locutores baseado em atividade (correlacao de Pearson nas zonas de sobreposicao) para atribuir rotulos globais de locutor. A extracao post-hoc de embedding WeSpeaker permite identificacao de locutor alvo via audio de enrolamento.
Community-1 (CoreML + VBx nativo)
O bundle Community-1 CoreML usa contexto de 10 s, passo de 1 s, embeddings WeSpeaker mascarados, PLDA/VBx nativo e atribuicao restrita; retorna um centroide de 256 dimensoes por falante. A verificacao de paridade em cinco arquivos obteve 4,66% DER / 21,43% JER.
Com o avaliador de grade de frames do speech-swift no mesmo subconjunto, o Community-1 mediu 9,31% DER / 16,20% JER, 25,5× tempo real e 1,54 GB de RSS maximo; o mecanismo Pyannote padrao mediu 5,03% / 9,28%, 105,7× tempo real e 393 MB. Portanto, Community-1 e um pipeline opcional de paridade com upstream, com limites de numero de falantes e centroides retornados, e nao uma melhoria universal de precisao ou velocidade. Os resultados dos dois metodos de avaliacao nao sao diretamente comparaveis.
Sortformer (CoreML)
Modelo neural ponta-a-ponta de diarizacao da NVIDIA. Preve diretamente a atividade por frame de ate 4 falantes sem estagios separados de embedding ou clustering. Roda no Neural Engine via CoreML com buffers de estado de streaming (FIFO + speaker cache).
Para áudio ao vivo, SortformerStreamingSession executa incrementalmente o modelo Sortformer .streaming com buffers PCM mono de 16 kHz de qualquer tamanho. Quando os 560 ms de lookahead estão disponíveis, avança em passos de áudio de 480 ms; um teste com cinco arquivos no Neural Engine da série M mediu latência mediana de 12,4 ms por push de 500 ms. Os rótulos de falante seguem o Arrival-Order Speaker Cache em vez de reagrupar cada janela, e cada push devolve um instantâneo de todo o fluxo. finish() processa a cauda armazenada no buffer. No teste de equivalência com modelo, os segmentos finais coincidiram com a diarização .streaming de buffer completo dentro de aproximadamente um frame de 80 ms.
Sortformer nao produz embeddings de falante. As flags --target-speaker e --embedding-engine estao disponiveis apenas com o engine Pyannote.
Baseline CALLHOME publicado
A tabela mostra o baseline bruto de diarizacao com falantes anonimos publicado pela NVIDIA para diar_streaming_sortformer_4spk-v2. E uma referencia externa, nao uma medicao local da conversao CoreML do speech-swift nem um resultado de atribuicao a falantes nomeados.
| Dataset | Condicao | DER |
|---|---|---|
| CALLHOME Part 2 | 2 falantes de referencia | 6,57% |
| CALLHOME Part 2 | 3 falantes de referencia | 10,05% |
| CALLHOME Part 2 | 4 falantes de referencia | 12,44% |
Todas as linhas usam 1,04 s de latencia do buffer de entrada, incluem sobreposicao, aplicam collar de 0,25 s e pos-processamento ajustado no CALLHOME Part 1 disjunto. CALLHOME exige licenca e nao e incluido. O diarization-bench local mostra resultados comparaveis separados por numero de falantes de referencia no console e no campo JSON byReferenceSpeakerCount.
Pipeline Pyannote
O pipeline padrao roda em duas etapas:
Etapa 1: Segmentacao + Encadeamento de falantes
Pyannote segmentation-3.0 processa janelas deslizantes de 10 segundos com sobreposicao de 50%. Um powerset decoder converte a saida de 7 classes em probabilidades por falante (ate 3 falantes locais por janela). Janelas adjacentes compartilham uma sobreposicao de 5 segundos — a identidade do falante e propagada entre janelas computando correlacao de Pearson entre as trilhas de probabilidade na zona de sobreposicao, com matching exclusivo greedy para IDs de falante globais consistentes.
Etapa 2: Embedding post-hoc
Apos a diarizacao, o WeSpeaker ResNet34-LM extrai um embedding centroide de 256 dimensoes por falante. Esses embeddings permitem extracao de falante alvo (--target-speaker) mas nao guiam a atribuicao de falante em si.
Migrando do pyannote.audio
Se voce vem da biblioteca Python pyannote.audio — substituindo uma subclasse de Pipeline que define pipeline.segmentation = ..., ou migrando de um servidor que hospeda pyannote/speaker-diarization-3.1 — o Soniqo encapsula o mesmo modelo Pyannote-Segmentation-3.0 e o executa totalmente no dispositivo em Apple Silicon. Sem runtime Python, sem CUDA, sem token Hugging Face em tempo de inferencia.
| 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 = ... (subclasse personalizada) |
Fixo: Pyannote-Segmentation-3.0 (MLX ou CoreML, selecionado automaticamente) |
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 |
Os pesos do Pyannote-Segmentation-3.0 sao convertidos do checkpoint upstream do HuggingFace, portanto os logits de segmentacao sao numericamente equivalentes dentro da tolerancia de precisao em ponto flutuante. O encadeamento pos-segmentacao (correlacao de Pearson em janelas sobrepostas + matching exclusivo guloso) e as etapas de embedding pos-hoc com WeSpeaker sao reimplementados em Swift, mas produzem saida RTTM comparavel ao pipeline Python de referencia.
Nao ha um equivalente em streaming para OnlineSpeakerDiarization no motor Pyannote. Para diarizacao em tempo real, use --engine sortformer, que executa o modelo Sortformer com buffers de estado FIFO + cache de falantes.
Uso do 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
Extracao de falante alvo
Forneca audio de enrolamento de um locutor conhecido para extrair apenas seus segmentos de uma gravacao. O pipeline computa o embedding de falante do audio de enrolamento e encontra o cluster com a maior similaridade de cosseno.
# Extract segments for a specific speaker
.build/release/speech diarize meeting.wav --target-speaker enrollment.wav
Pontuacao DER
Avalie a qualidade da diarizacao pontuando contra um arquivo RTTM de referencia. O pipeline calcula a Diarization Error Rate (DER), que mede a proporcao de tempo atribuido incorretamente.
# Score against reference RTTM
.build/release/speech diarize meeting.wav --score-against reference.rttm
Saida RTTM
A flag --rttm produz saida Rich Transcription Time Marked, um formato padrao usado para avaliacao de diarizacao. Cada linha segue o formato:
SPEAKER filename 1 start_time duration <NA> <NA> speaker_id <NA> <NA>
Opcoes
| Opcao | Descricao |
|---|---|
--target-speaker | Audio de enrolamento para extracao de falante alvo (somente pyannote) |
--embedding-engine | Engine de embedding de falante: mlx ou coreml (somente pyannote) |
--vad-filter | Pre-filtrar com Silero VAD (somente pyannote) |
--rttm | Saida no formato RTTM |
--json | Formato de saida JSON |
--score-against | Arquivo RTTM de referencia para avaliacao DER |
A diarizacao funciona melhor com gravacoes que tem turnos claros de falante. Fala altamente sobreposta pode reduzir a precisao. O numero de falantes e determinado automaticamente.
Downloads de modelos
Os modelos sao baixados automaticamente no primeiro uso:
| Componente | Modelo | Tamanho | HuggingFace |
|---|---|---|---|
| Segmentacao | Pyannote-Segmentation-3.0 | ~5.7 MB | aufklarer/Pyannote-Segmentation-MLX |
| Embedding de falante | WeSpeaker-ResNet34-LM (MLX) | ~25 MB | aufklarer/WeSpeaker-ResNet34-LM-MLX |
| Embedding de falante | WeSpeaker-ResNet34-LM (CoreML) | ~25 MB | aufklarer/WeSpeaker-ResNet34-LM-CoreML |
| Sortformer | Sortformer Diarization (CoreML) | ~240 MB | aufklarer/Sortformer-Diarization-CoreML |
API Swift
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
)