语音活动检测
提供两种 VAD 模型:Pyannote 分段用于高精度的离线批处理;Silero VAD v5用于低延迟的流式检测。两者都完全在端侧运行。
Pyannote(离线)
Pyannote segmentation-3.0 使用 PyanNet 架构提供高精度 VAD。它以 1 秒步长在 10 秒滑动窗口上处理音频,然后聚合重叠预测并应用 hysteresis 平滑。
架构
| 阶段 | 细节 |
|---|---|
| SincNet | 40 个可学习带通滤波器(共 80:40 cos + 40 sin) |
| BiLSTM | 4 层,hidden=128,双向(256 维输出) |
| Linear | 带 LeakyReLU 的 2 层线性层(negative_slope=0.01) |
| 输出 | 7 类 softmax,配 hysteresis 后处理 |
模型大小:约 1.49M 参数,磁盘约 5.7 MB。
默认阈值
- Onset:
0.767— 高于该概率则判定为语音开始 - Offset:
0.377— 低于该概率则判定为语音结束
CLI 使用
# 离线 VAD
.build/release/audio vad recording.wav
# JSON 输出
.build/release/audio vad recording.wav --json
# 自定义阈值
.build/release/audio vad recording.wav --onset 0.6 --offset 0.3
Silero VAD v5(流式)
Silero VAD v5 是一个轻量的流式模型,处理 512 样本的 chunk(16 kHz 下 32 ms)。release 模式下可达 23 倍实时,适合实时音频应用。
架构
| 阶段 | 细节 |
|---|---|
| STFT | Conv1d(1 到 258 通道),右侧 64 的 reflection pad |
| Encoder | 4× Conv1d + ReLU |
| LSTM | hidden 128,状态在 chunk 间延续 |
| Decoder | 作用在 LSTM 隐藏状态上的 Conv1d(128 到 1),sigmoid 输出 |
模型大小:约 309K 参数,磁盘约 1.2 MB。
流式状态机
流式 VAD 处理器使用一个 4 状态的状态机来产生干净的语音段:
- silence — 未检测到语音
- pendingSpeech — 超过 onset 阈值,等待达到最小语音时长
- speech — 已确认的语音段正在进行
- pendingSilence — 低于 offset 阈值,等待达到最小静音时长
默认阈值
- Onset:
0.5 - Offset:
0.35 - 最小语音时长:
0.25s - 最小静音时长:
0.1s
CLI 使用
# 流式 VAD
.build/release/audio vad-stream recording.wav
# 自定义阈值
.build/release/audio vad-stream recording.wav --onset 0.6 --offset 0.3
# 最小时长
.build/release/audio vad-stream recording.wav --min-speech 0.5 --min-silence 0.2
# 选择引擎
.build/release/audio vad-stream recording.wav --engine coreml
选项
| 选项 | 适用于 | 说明 |
|---|---|---|
--onset | 两者 | 语音开始的概率阈值 |
--offset | 两者 | 语音结束的概率阈值 |
--min-speech | 流式 | 最小语音段时长(秒) |
--min-silence | 流式 | 结束段所需的最小静音时长(秒) |
--engine | 流式 | 推理引擎:mlx 或 coreml |
--json | 两者 | JSON 输出格式 |
重要
对于实时应用,使用 audio vad-stream 搭配 Silero VAD。Pyannote 模型需要完整的音频文件,更适合以精度为先的离线批处理。
模型下载
| 模型 | 后端 | 大小 | HuggingFace |
|---|---|---|---|
| Silero-VAD-v5 | MLX | ~1.2 MB | aufklarer/Silero-VAD-v5-MLX |
| Silero-VAD-v5 | CoreML | ~1.2 MB | aufklarer/Silero-VAD-v5-CoreML |
| Pyannote-Segmentation-3.0 | MLX | ~5.7 MB | aufklarer/Pyannote-Segmentation-MLX |
Swift API
import SpeechVAD
// 离线 VAD (Pyannote)
let pyannote = try await PyannoteVAD.loadFromHub()
let segments = try await pyannote.detectSpeech(audioFile: "recording.wav")
for segment in segments {
print("\(segment.start)s - \(segment.end)s")
}
// 流式 VAD (Silero)
let silero = try await SileroVAD.loadFromHub()
let processor = StreamingVADProcessor(model: silero, config: .sileroDefault)
for chunk in audioChunks {
if let segment = try processor.process(chunk: chunk) {
print("Speech: \(segment.start)s - \(segment.end)s")
}
}