話者ダイアライゼーション

複数話者録音で誰がいつ話したかを識別します。2つのダイアライゼーションエンジンが利用可能です:2段階のPyannoteパイプライン(セグメンテーション + アクティビティベースの話者チェーン、その後のポストホック埋め込み)とエンドツーエンドのSortformerモデル(CoreML、Neural Engine)。

エンジン

--engine pyannote(デフォルト)または--engine sortformerでエンジンを選択します。

Pyannote(デフォルト)

2段階パイプライン:Pyannoteセグメンテーションはオーバーラップする窓をアクティビティベースの話者チェーン(オーバーラップゾーンでのピアソン相関)で処理し、グローバル話者ラベルを割り当てます。ポストホックWeSpeaker埋め込み抽出により、登録音声経由のターゲット話者識別が可能になります。

Sortformer(CoreML)

NVIDIAのエンドツーエンドニューラルダイアライゼーションモデル。最大4話者まで、別々の埋め込みやクラスタリング段階なしで、フレームごとの話者アクティビティを直接予測します。ストリーミング状態バッファ(FIFO + 話者キャッシュ)を備えたCoreML経由でNeural Engine上で動作します。

注記

Sortformerは話者embeddingを生成しません。--target-speaker--embedding-engineフラグはPyannoteエンジンでのみ使用できます。

Pyannoteパイプライン

デフォルトパイプラインは2段階で実行されます:

ステージ1: セグメンテーション + 話者チェーン

Pyannote segmentation-3.0は、50%オーバーラップの10秒スライディング窓を処理します。powersetデコーダーは7クラス出力を話者ごとの確率(窓あたり最大3ローカル話者)に変換します。隣接する窓は5秒のオーバーラップを共有します — 話者のアイデンティティは、オーバーラップゾーンの確率トラック間でピアソン相関を計算し、一貫したグローバル話者IDのためのグリーディ排他マッチングにより、窓を横断して伝播されます。

ステージ2: ポストホック埋め込み

ダイアライゼーション後、WeSpeaker ResNet34-LMは話者ごとに256次元のセントロイド埋め込みを抽出します。これらの埋め込みはターゲット話者抽出(--target-speaker)を可能にしますが、話者割り当て自体を駆動するものではありません。

CLIの使用法

# 基本的なダイアライゼーション(pyannote、デフォルト)
.build/release/audio diarize meeting.wav

# エンドツーエンド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-filterSilero VADで事前フィルタリング(pyannoteのみ)
--rttmRTTM形式で出力
--jsonJSON出力形式
--score-againstDER評価用のリファレンスRTTMファイル
重要

ダイアライゼーションは、明確な話者ターンのある録音で最高に機能します。高度にオーバーラップする音声は精度を低下させる可能性があります。話者数は自動的に決定されます。

モデルダウンロード

モデルは初回使用時に自動的にダウンロードされます:

コンポーネントモデルサイズHuggingFace
セグメンテーションPyannote-Segmentation-3.0約5.7 MBaufklarer/Pyannote-Segmentation-MLX
話者埋め込みWeSpeaker-ResNet34-LM (MLX)約25 MBaufklarer/WeSpeaker-ResNet34-LM-MLX
話者埋め込みWeSpeaker-ResNet34-LM (CoreML)約25 MBaufklarer/WeSpeaker-ResNet34-LM-CoreML
SortformerSortformer Diarization (CoreML)約240 MBaufklarer/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
)