语音活动检测

提供两种 VAD 模型:Pyannote 分段用于高精度的离线批处理;Silero VAD v5用于低延迟的流式检测。两者都完全在端侧运行。

Pyannote(离线)

Pyannote segmentation-3.0 使用 PyanNet 架构提供高精度 VAD。它以 1 秒步长在 10 秒滑动窗口上处理音频,然后聚合重叠预测并应用 hysteresis 平滑。

架构

阶段细节
SincNet40 个可学习带通滤波器(共 80:40 cos + 40 sin)
BiLSTM4 层,hidden=128,双向(256 维输出)
Linear带 LeakyReLU 的 2 层线性层(negative_slope=0.01)
输出7 类 softmax,配 hysteresis 后处理

模型大小:约 1.49M 参数,磁盘约 5.7 MB。

默认阈值

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 倍实时,适合实时音频应用。

架构

阶段细节
STFTConv1d(1 到 258 通道),右侧 64 的 reflection pad
Encoder4× Conv1d + ReLU
LSTMhidden 128,状态在 chunk 间延续
Decoder作用在 LSTM 隐藏状态上的 Conv1d(128 到 1),sigmoid 输出

模型大小:约 309K 参数,磁盘约 1.2 MB。

流式状态机

流式 VAD 处理器使用一个 4 状态的状态机来产生干净的语音段:

  1. silence — 未检测到语音
  2. pendingSpeech — 超过 onset 阈值,等待达到最小语音时长
  3. speech — 已确认的语音段正在进行
  4. pendingSilence — 低于 offset 阈值,等待达到最小静音时长

默认阈值

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流式推理引擎:mlxcoreml
--json两者JSON 输出格式
重要

对于实时应用,使用 audio vad-stream 搭配 Silero VAD。Pyannote 模型需要完整的音频文件,更适合以精度为先的离线批处理。

模型下载

模型后端大小HuggingFace
Silero-VAD-v5MLX~1.2 MBaufklarer/Silero-VAD-v5-MLX
Silero-VAD-v5CoreML~1.2 MBaufklarer/Silero-VAD-v5-CoreML
Pyannote-Segmentation-3.0MLX~5.7 MBaufklarer/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")
    }
}

也可在 Android 与 Linux 上通过 ONNX Runtime 使用