说话人嵌入向量

使用 WeSpeaker ResNet34-LM 提取 256 维 L2 归一化的说话人向量。这些 embedding 捕获说话人独特的声学特征,可用于识别、验证和声音检索。

架构

WeSpeaker ResNet34-LM 是一个深度残差网络,用于说话人表示学习。

阶段细节
输入Conv2d(1 到 32 通道)
ResNet34[3, 4, 6, 3] 残差块
统计池化时间维度上的均值 + 标准差
投影Linear(5120 到 256)
输出L2 归一化的 256 维 embedding

模型大小:约 6.6M 参数,磁盘约 25 MB。

Mel 特征

模型使用由 Hamming 窗计算的 80 维 mel 频率特征。对数缩放使用简单的 log(max(mel, 1e-10)) 公式,无需额外归一化。为提高推理效率,batch normalization 在转换时就已融合到 Conv2d 层中。

CLI 使用

# Extract speaker embedding
.build/release/speech embed-speaker voice.wav

# JSON output (includes the 256-dim vector)
.build/release/speech embed-speaker voice.wav --json

# Choose inference engine
.build/release/speech embed-speaker voice.wav --engine coreml

选项

选项说明
--engine推理引擎:mlxcoreml
--json含完整 embedding 向量的 JSON 输出格式

使用场景

说话人验证

对比两段音频,判断是否来自同一个说话人。分别提取 embedding 并计算余弦相似度。相似度越高,属于同一说话人的概率越大。

import SpeechVAD

let model = try await WeSpeakerModel.fromPretrained()

let samples1: [Float] = loadAudio("sample1.wav")
let samples2: [Float] = loadAudio("sample2.wav")
let embedding1 = model.embed(audio: samples1, sampleRate: 16000)
let embedding2 = model.embed(audio: samples2, sampleRate: 16000)

let similarity = WeSpeakerModel.cosineSimilarity(embedding1, embedding2)
print("Similarity: \(similarity)")  // > 0.7 typically same speaker

说话人识别

将一段未知音频与已注册的说话人 embedding 数据库匹配。余弦相似度最高的已注册说话人即为预测身份。

声音检索

按说话人 embedding 为一组音频录音建立索引,然后用一段新音频查询,找出所有同一说话人的录音。

重要

说话人嵌入向量在至少 2-3 秒的干净语音上效果最佳。非常短的片段或嘈杂录音可能会得到不太可靠的 embedding。对于嘈杂音频,可考虑先应用语音增强

模型下载

模型后端大小HuggingFace
WeSpeaker-ResNet34-LMMLX~25 MBaufklarer/WeSpeaker-ResNet34-LM-MLX
WeSpeaker-ResNet34-LMCoreML~25 MBaufklarer/WeSpeaker-ResNet34-LM-CoreML

Swift API

import SpeechVAD

let model = try await WeSpeakerModel.fromPretrained()

// Extract embedding from audio samples
let samples: [Float] = loadAudio("voice.wav")
let embedding = model.embed(audio: samples, sampleRate: 16000)
print("Embedding dimensions: \(embedding.count)")  // 256