話者embedding
WeSpeaker ResNet34-LMを使用して256次元のL2正規化された話者ベクトルを抽出します。これらの埋め込みは話者の固有の声質特徴を捉え、識別、検証、音声検索に使用できます。
アーキテクチャ
WeSpeaker ResNet34-LMは、話者表現学習のためにトレーニングされた深い残差ネットワークです。
| ステージ | 詳細 |
|---|---|
| 入力 | Conv2d (1から32チャネル) |
| ResNet34 | [3, 4, 6, 3] 残差ブロック |
| 統計プーリング | 時間にわたる平均 + 標準偏差 |
| プロジェクション | Linear (5120から256) |
| 出力 | L2正規化された256次元embedding |
モデルサイズ:約6.6Mパラメーター、ディスク上約25 MB。
Mel特徴量
モデルはハミング窓で計算された80次元のmel周波数特徴量を使用します。log スケーリングは追加の正規化なしで単純なlog(max(mel, 1e-10))式を使用します。バッチ正規化は、推論効率のために変換時にConv2dレイヤーに融合されます。
CLIの使用法
# 話者embeddingを抽出
.build/release/audio embed-speaker voice.wav
# JSON出力(256次元ベクトルを含む)
.build/release/audio embed-speaker voice.wav --json
# 推論エンジンを選択
.build/release/audio embed-speaker voice.wav --engine coreml
オプション
| オプション | 説明 |
|---|---|
--engine | 推論エンジン:mlxまたはcoreml |
--json | 完全なembeddingベクトルを含むJSON出力形式 |
ユースケース
話者検証
2つの音声サンプルを比較して、同じ話者によるものかどうかを判断します。両方から埋め込みを抽出し、コサイン類似度を計算します。類似度スコアが高いほど、同じ話者である確率が高くなります。
import SpeechVAD
let model = try await WeSpeaker.loadFromHub()
let embedding1 = try await model.embed(audioFile: "sample1.wav")
let embedding2 = try await model.embed(audioFile: "sample2.wav")
let similarity = cosineSimilarity(embedding1, embedding2)
print("Similarity: \(similarity)") // > 0.7 は通常同じ話者
話者識別
未知の音声サンプルを登録済み話者embeddingのデータベースと照合します。最大のコサイン類似度を持つ登録済み話者が予測されるアイデンティティです。
音声検索
音声録音のコレクションを話者embeddingでインデックス付けし、新しい音声サンプルでクエリして、同じ話者からのすべての録音を見つけます。
重要
話者embeddingは、少なくとも2〜3秒のクリーンな音声で最高に機能します。非常に短いクリップやノイズの多い録音は、信頼性の低い埋め込みを生成する可能性があります。ノイズの多い音声については、最初に音声強調を適用することを検討してください。
モデルダウンロード
| モデル | バックエンド | サイズ | HuggingFace |
|---|---|---|---|
| WeSpeaker-ResNet34-LM | MLX | 約25 MB | aufklarer/WeSpeaker-ResNet34-LM-MLX |
| WeSpeaker-ResNet34-LM | CoreML | 約25 MB | aufklarer/WeSpeaker-ResNet34-LM-CoreML |
Swift API
import SpeechVAD
let model = try await WeSpeaker.loadFromHub()
// ファイルから埋め込みを抽出
let embedding = try await model.embed(audioFile: "voice.wav")
print("Embedding dimensions: \(embedding.count)") // 256
// 音声サンプルから埋め込みを抽出
let samples: [Float] = loadAudio("voice.wav")
let embedding = try await model.embed(samples: samples, sampleRate: 16000)