Skip to main content

AI VAD报告

总结:建议方案:TEN VAD

优势超低延迟极小体积跨平台支持高精度

(一)VAD 技术

Voice Activity Detection(语音活动检测) 是一个用于区分“有人说话”与“静音、噪音、背景声”的技术。

在 AI 场景中,VAD 通常是:

  • 对接 语音识别系统(ASR) 的前置模块。
  • 起到判断“是否开始/结束讲话”的作用。
  • 智能对话中用于判断何时打断、何时开始响应

与语音识别(ASR)的关系

  • VAD 是语音识别的前置模块
  • 可以防止长时间静音被识别
  • 在 AI 语音助手中,VAD + ASR + NLU 构成完整识别逻辑链

对话打断逻辑

  • 何时判断用户说完了话?
    • 连续静音超过 X ms
    • 检测到语音下降趋势(如 intonation 向下)
  • 如何打断用户?
    • 判断对方说话内容中断点(如“我觉得……”停顿)
    • AI语音助手做出反馈:“你是说……对吗?”

(1)音频处理

模拟音频信号 是连续变化的电压或声压值,表示随时间变化的声波。

  • 它是一个一维连续函数

    s(t):RRs(t):R→R

    • t:时间
    • s(t):对应时刻的音频信号幅度(声压、电压等)

数字音频设备(麦克风、声卡)采样的过程,就是用一定频率取点,把模拟信号变成离散数据点

如果采样率是 16kHz,就表示:每秒取 16000 个点

每个点记录的就是:采样时间点 tit_i 和该时刻的幅度值 s(ti)s(t_i)

注意:最终存储时只记录了幅度值序列: 因为时间间隔是等间隔的,所以只需要一组数字就可以表示整段音频。

数组 = [0.01, 0.05, 0.13, -0.06, -0.20, ...]  # 这些值就是采样的幅度

每个值叫做 采样值,或 PCM 值(Pulse Code Modulation)。

(2)VAD 的基本原理

方式原理说明
基于能量检测语音段能量高于背景噪音简单但不可靠
基于频谱特征分析MFCC、频谱平坦度等更准确
基于深度学习CNN、RNN、Transformer模型最新主流做法,如 Silero VAD

前两种方法已经被时代淘汰,这里聚焦于第三种方法:基于深度学习

流程图:

原始音频(16kHz PCM)

分帧 + 特征提取(如 Mel 频谱)

深度神经网络(CNN / RNN / Dilated CNN / Transformer)

帧级语音概率输出(0~1)

阈值判断(是否为语音帧)

语音段聚合 + 时间戳输出

详细解释:

1. 原始音频输入

  • 格式:通常为 PCM 格式,采样率多为 16kHz,16-bit

  • 为什么 16kHz? 人声主要集中在 0~4kHz,16kHz 是 Nyquist 采样定理的两倍以上

  • 表示方式:输入为一维浮点数组,例如:

    [0.02, -0.01, 0.05, ..., -0.03]
    

2. 分帧 + 特征提取

分帧(Framing)

  • 通常每帧长度为 25ms(=400点),帧移为 10ms(=160点)

帧移 :相邻两帧的起点间隔时间 假设帧长为 25ms,帧移为 10ms → 意味着相邻两帧 有重叠(15ms)

滑动窗口:一个时间序列上逐步滑动的定长窗口,用于局部计算或判断。 应用在 VAD 中:

  • 用于平滑帧级决策(如连续 3 帧都为 1 才判断为语音)
  • 用于聚合一段语音概率为一个“语音段”

特征提取

原始波形变化太快、太杂,因此需要将原始音频(波形)转换成更有代表性、更易于机器学习的表达。

特征类型说明
Mel 频谱图最常用,模拟人耳听觉感知的频率分布
MFCC由 Mel 频谱进一步取对数 + DCT 变换,压缩维度
Log-MelMel 能量谱取对数,更适合神经网络
SpectrogramSTFT 结果,包含幅度(有时也含相位)信息

Mel 频率(Mel Scale):一种模拟人耳听觉感知的非线性频率刻度,在人耳对低频更敏感、高频不敏感的基础上设计。 人耳对频率的感知是非线性的(低频更敏感),Mel 频率模拟这一感知。

可读对比图(线性 vs Mel):

  • 线性频率:0Hz → 1000Hz → 2000Hz → 3000Hz ...
  • Mel频率:0Hz → 500Mel → 800Mel → 950Mel ...

转换公式:

Mel(f)=2595log10(1+f700)\text{Mel}(f) = 2595 \cdot \log_{10}(1 + \frac{f}{700})

3. 深度神经网络

用于建模语音时频结构 + 时间上下文的神经网络模块,一般包括:

3.1 卷积层(CNN)

  • 捕捉短时频谱模式(如发音共振峰)
  • 多用于输入是 Mel 图像或谱图
  • 特点:局部感知、参数少、计算快

3.2 时序建模层

模型类型功能
RNN / LSTM / GRU建模时间序列依赖关系(例如语音延续性)
Dilated CNN空洞卷积,扩大感受野替代 RNN,效率更高
Transformer自注意力机制,支持长距离依赖,但开销大,一般不用在前端 VAD

名词解释:Dilated CNN:卷积时跳过间隔的点,可视为快速模拟记忆


4. 输出层 + 激活函数

最后一层为全连接层 + Sigmoid 激活函数

sigmoid(x)=11+ex\text{sigmoid}(x) = \frac{1}{1 + e^{-x}}

每一帧输出一个值,代表“是语音”的概率(0~1)


5. 阈值判断

将每帧概率与阈值比较,生成 0 或 1 的标签序列

默认阈值为 0.5,可调(如 0.4 更灵敏,0.6 更保守)


6. 后处理:语音段聚合

把相邻语音帧组合成完整的语音段

  • 设置:
    • min_speech_ms = 150:最短语音段时长
    • min_silence_ms = 300:最短静音间隔
    • speech_pad_ms = 100:语音段前后填充平滑

输出结果形式如:

[
  {"start": 0.35, "end": 1.15},
  {"start": 2.08, "end": 3.27}
]


(3)训练过程

项目内容
数据合成数据(纯净语音 + 噪声叠加,控制 SNR)
标签帧级标签(0:非语音,1:语音)
损失函数Binary Cross-Entropy(交叉熵)
优化器Adam(学习率如 0.001)
训练目标最小化帧级预测误差,提升 Recall / F1 分数

名词解释:

  • Cross-Entropy Loss:衡量预测概率与真实标签差异的损失函数
  • SNR(信噪比):语音功率 vs 噪声功率的对数比,控制语音清晰程度


(4)部署模式

语音活动检测(VAD, Voice Activity Detection)是一项非常轻量级的前端处理任务,通常部署对计算资源的需求是极低的,适合边缘设备、移动端和服务器前处理等场景。绝大多数 VAD 模型非常轻量,即使是神经网络版本也可在轻量 CPU 上实时运行,不需要 GPU。

VAD 类型说明资源需求典型模型/框架
传统算法型 VAD基于能量/频谱阈值或 WebRTC 算法极低(CPU 级别)WebRTC-VAD、SoX
轻量神经网络 VAD使用简单 DNN/RNN/LSTM 做帧级分类低(嵌入式设备可运行)Silero VAD、TEN VAD
端到端大模型 VAD内嵌在大模型语音处理系统中高(GPU或TPU)Whisper、Minimax、豆包等自研模块

VAD 常见部署模式

模式适用场景资源需求
边缘部署设备端实时检测,如智能耳机、摄像头1核CPU即可
服务器前处理在进入语音识别或 TTS 前过滤静音较低,1核多线程
浏览器端WebAssembly + JS 实现 VAD可直接嵌入网页,无需后端
嵌入语音大模型如 Whisper + VAD 联合结构GPU资源占主导,不是 VAD 单独占用

(二)方案整理

1. 主流方案

模型开源/论文来源精度指标推理速度 RTF* / 时延模型大小 & 资源占用平台适配特点与适用场景
Silero VADSnakers4 GitHub (2024) (github.com)高(多语言训练)RTF ≈0.03(1 ms/30 ms帧)~1–2 MB(JIT/ONNX),CPU 优化CPU/GPU/ONNX轻量、低延迟、跨平台、MIT 许可,适合实时与离线系统
TEN VADTEN-framework (Hugging Face)精度 > SileroRTF ~0.01–0.02(极低)~300–500 KB 二进制(C/Python)各主流 CPU/移动平台极轻量、延迟极低、多平台支持,推荐用于高并发对话系统
NVIDIA NeMo VAD (MarbleNet)Ginsburg et al. “MarbleNet” (2020)性能优,轻量化0.6s 帧块,批次推理可优化~0.3 MB(ONNX/PyTorch)GPU/CPU via ONNX/Triton适合批量离线识别,结构紧凑,适用于服务端部署
CNN-BiLSTM VADWilkinson & Niesler (2021)AUC≈0.951≈实时 / 需测评中等(参数适中)GPU/CPU在噪音环境表现优异(+2% 精度提升),适用于高质量任务
ResNet VAD学术研究模型(如 ResNet-18 + 对抗训练)极高精度延迟高,适用强 GPU多 MB,计算复杂GPU部署资源富余时性能佳,牺牲延迟;适用于离线或超高精度需求的场景

* RTF = Real‑Time Factor(推理时间 / 语音时长),越低越快,适合实时对话系统。

2. 最优方案:TEN VAD

考虑到要求为:低延迟,服务器端,(资源占用小),支持中文,准确率高

建议方案:TEN VAD

优势

  • 超低延迟:在 Ryzen 5900X 上 RTF≈0.015;在 M1 上 RTF≈0.010–0.016,同样在 Web M1 上 RTF≈0.010(github.com)。

  • 极小体积:仅 ~300 KB(Linux x64),移动端为 ~373–532 KB(Android),iOS 为 ~320 KB(github.com)。

  • 跨平台支持:C/C++ 库形式,支持 Linux、Windows、macOS、Android、iOS,还提供 WebAssembly、Python、JavaScript Bindings(github.com)。

  • 高精度:相对于 Silero VAD 与 WebRTC Pitch-based VAD,TEN VAD 在多数据集测评中获得更优 PR 曲线和更快语音转换检测(github.com)。img

    img

备用方案:Silero VAD

各方面都略次于 TEN VAD ,但是差别不大



3. TEN VAD 的处理路径

下面是 TEN VAD 的详细内部处理路径,展示其从音频输入到语音检测输出的完整流程

Raw audio (16 kHz PCM stream)

帧划分(帧长 160 或 256 个样本,对应 10 ms 或 16 ms hop)

特征提取(模型内部处理)

轻量 CNN 提取局部时频特征

时间聚合层(如 temporal convolution 或简易 RNN)

线性层 + Sigmoid 输出:每帧语音存在的概率

二值化(默认阈值 ≈0.5,可调)

“静音→语音→静音”滑动算法检测活动边界
  • 帧划分
    • 输入音频以 10 ms 或 16 ms 切帧,帧窗大小 160 或 256 样本(github.com)。
    • 支持 16 kHz 输入;其它采样率自动重采样。
  • 轻量 CNN 层
    • 首层为深度可分离或轻量卷积,用于提取每帧的时频特征(如局部能量、谱形结构)。
  • 时间聚合(Temporal Module)
    • 聚合跨帧上下文,增强对短暂停顿的鲁棒识别。
  • 输出层
    • 使用 sigmoid 激活给出每帧语音概率(0–1)。
  • 后处理逻辑
    • 默认概率阈值为 0.5(可根据场景调优)(github.com)。
    • 使用滑动窗口聚合二值帧,识别短静音/语音,并输出连续语音段边界。

说明

  • 阈值判断 + 滑窗合并 是防止误判的关键技巧。过低阈值会误报,过高会漏检。
  • 所有模块均在 C 库或 WASM 库中高度优化,可部署在服务器、移动端或 Web。


4. TEN VAD 的打断逻辑

TEN VAD 本身是一个帧级语音检测模型,并不直接负责“打断”操作,但它是打断逻辑的核心触发条件来源。

也就是说,TEN VAD 提供“语音帧 vs 静音帧”的信息,打断逻辑基于这些信息做高层决策。

下面是 TEN VAD 在实际对话系统中实现打断(interruption)逻辑的典型方式:

1. TEN VAD 的输出信息

  • 每帧输出一个值(每 10ms):Pspeech[0,1]P_{\text{speech}} \in [0, 1]
  • 经二值化阈值(如 0.5)后输出帧标签:0 = 非语音,1 = 语音
  • 配合滑动窗口聚合,形成语音段(start, end)

2. 打断的判断逻辑流程

用户说话中(VAD连续输出 1)

某个时间点开始连续静音(VAD输出一串 0)

系统统计静音长度

若静音持续 ≥ 阈值(如 300ms)

系统判断用户说话可能结束

立即“打断”:启动响应流程 / AI 回答

3. 关键参数(推荐配置)

参数含义示例值
min_silence_duration_ms连续静音多少毫秒以上,才认为是停顿200~300ms
speech_pad_ms每段语音前后要不要留点“缓冲”100ms
trigger_level静音后触发响应的策略等级(Aggressive/Normal)Normal
early_stop_mode是否允许在未完全静音前“提前打断”可以配置

4. 打断场景分类与实现方式

场景一:用户短暂停顿,系统抢答

  • 逻辑
    • 当前帧为语音,下一帧为静音
    • 观察静音是否持续超过 200~300ms
    • 若满足,则立即进入系统响应状态

场景二:边听边说,语音后端预测提前打断

  • 逻辑增强
    • 判断语调下降(未来需引入 Prosody 特征)
    • 结合 ASR 实时转录文本句式(检测“语气终止”)

(三)TEN VAD部署流程

步骤 1:克隆仓库

git clone https://github.com/TEN-framework/ten-vad.git
cd ten-vad

步骤 2:新建并激活虚拟环境

conda create -n VAD-env python=3.10
conda activate VAD-env

步骤 3:安装依赖(按官方要求)

安装基本依赖(运行 TEN-VAD 本体所需)

pip install -r requirements.txt
pip install -e .
pip install -r examples/requirements.txt

这些额外包包括 matplotlib, scikit-learn, torchaudio 等。

步骤 4:安装系统运行依赖(只需一次)

sudo apt update
sudo apt install libc++1

步骤 5:运行官方示例测试

确保当前目录为 ten-vad 项目根目录,然后运行:

cd examples
python test.py s0724-s0730.wav out.txt

提示:你可以将自己的 .wav 文件命名为 s0724-s0730.wav 替换示例音频。

步骤 6:调用 TEN-VAD

你可以在 venv_tenvad 中新建文件如 my_vad_test.py

from ten_vad import TenVad
import soundfile as sf

audio, sr = sf.read("your_audio.wav")
assert sr == 16000, "TEN-VAD only supports 16kHz audio"

vad = TenVad()
probs = vad.run(audio)

print("前10帧语音概率:", probs[:10])

运行:

python my_vad_test.py

整体结构检查示意

ten-vad/
├── examples/
│ ├── test.py
│ ├── s0724-s0730.wav
│ └── requirements.txt
├── ten_vad/
├── requirements.txt
├── setup.py
├── venv_tenvad/ ← 你创建的虚拟环境

(四)降噪模块

对于背景人声, VAD 处理得不好,因此需要先进行背景降噪

一、安装 Demucs v4

在虚拟环境中运行:

pip install demucs

这会安装 Demucs v4 和对应模型。默认模型是 htdemucs(Hybrid Transformer)(pypi.org)。

二、Python 集成脚本

保存为 demucs_tenvad_pipeline.py

import subprocess
import soundfile as sf
import numpy as np
from ten_vad import TenVad

def demucs_split(input_wav, out_dir="demucs_out"):
    subprocess.run([
        "demucs", input_wav,
        "--two-stems=vocals",
        "-n", "htdemucs",
        "-d", "cpu",
        "--out", out_dir
    ], check=True)
    # 生成 vocals.wav 在 <out_dir>/htdemucs/<basename>/vocals.wav
    base = input_wav.split(".")[0]
    return f"{out_dir}/htdemucs/{base}/vocals.wav"

def run_tenvad(on_wav):
    audio, sr = sf.read(on_wav)
    assert sr == 16000, "TEN‑VAD 要求 16 kHz 输入"
    vad = TenVad()
    probs = vad.run(audio)
    flags = (probs > 0.5).astype(int)
    return flags, probs

if __name__ == "__main__":
    infile = "audio_16k.wav"
    print("Demucs 正在执行隔离 vocals...")
    vocals_wav = demucs_split(infile)
    print("隔离结果保存在:", vocals_wav)

    print("正在运行 TEN‑VAD...")
    flags, _ = run_tenvad(vocals_wav)
    print("前 20 帧 VAD 标记:", flags[:20])