Appearance
VAD 语音活动检测
VAD(Voice Activity Detection)判断连续音频中的哪些时间段包含语音。它通常输出逐帧语音概率或若干组起止时间,供录音切片、流式识别、唤醒后监听、通话检测和功耗控制使用。
VAD 不负责识别说了什么,也不等同于对话结束判断。工程上的关键工作不是得到一个概率,而是把概率、连续帧、前后缓存和业务超时组合成稳定的语音片段。
概念边界
| 模块 | 回答的问题 | 典型输出 |
|---|---|---|
| 降噪 | 如何减少回声、稳态噪声和增益波动 | 增强后的 PCM |
| VAD | 当前音频是否包含语音 | 概率、开始和结束时间 |
| 唤醒词检测 | 是否说出了指定短语 | 唤醒事件、置信度 |
| ASR | 说话内容是什么 | 文本、时间戳、识别状态 |
| 端点检测 | 本轮输入是否可以提交识别或理解 | 句段完成事件 |
| 轮次检测 | 用户是否已经表达完、系统能否接话 | 交互轮次状态 |
VAD 可以为端点检测提供声学依据,但两者不能直接画等号。例如用户说“帮我查一下……明天的天气”,中间停顿可能已经超过 VAD 的静音阈值,端点策略仍应结合 ASR 状态、语义完整性和最大等待时间决定是否结束本轮。
从概率到语音片段
神经网络 VAD 通常按固定帧读取 PCM,并为每帧输出 0~1 的语音概率。生产系统还需要一层分段器,把抖动的帧级结果变成稳定事件:
- 保留一段环形前置缓存,避免检测确认期间吞掉字头。
- 概率连续达到起始条件后进入说话状态,并回补前置音频。
- 说话期间持续输出或缓存音频,不因单帧低概率立即截断。
- 低概率持续达到结束条件后关闭片段,并保留尾部音频。
- 丢弃过短片段;过长片段则在可接受的静音处切开,或按最大时长强制切分。
起始阈值和结束阈值最好分开设置。起始条件严格一些可以降低噪声误触发,结束条件宽松一些可以避免音节间短暂停顿导致频繁切段。这种滞回策略比单一阈值稳定。
text
未说话 --连续高概率--> 候选语音 --满足最短语音--> 说话中
说话中 --连续低概率--> 候选结束 --满足最短静音--> 未说话
候选语音 --概率回落--> 未说话
候选结束 --概率恢复--> 说话中主要参数
| 参数 | 控制的行为 | 过小的表现 | 过大的表现 |
|---|---|---|---|
start_threshold | 进入语音状态的概率门槛 | 噪声、音乐容易触发 | 轻声和远场语音漏检 |
end_threshold | 判断语音结束的概率门槛 | 片段容易拖尾 | 音节间停顿容易被截断 |
min_speech_duration_ms | 接受片段所需的最短语音时长 | 咳嗽、敲击声成为片段 | “嗯”“对”等短词被丢弃 |
min_silence_duration_ms | 结束前要求的连续静音 | 一句话被切成多段 | 提交延迟增加、两句话粘连 |
speech_pad_ms | 片段前后保留的音频 | 字头、尾音被切掉 | 相邻片段重叠、附带噪声增多 |
max_speech_duration_s | 单片段允许的最长时长 | 长句被频繁切分 | 缓存、识别延迟和内存增长 |
参数之间会互相影响。起点丢字不一定需要降低模型阈值,先检查前置缓存通常更安全;句尾拖延也不一定要缩短静音时长,还要确认 ASR 是否需要更多上下文。
放在语音链路的什么位置
常见链路是:
text
Mic -> AEC -> 波束形成 / NS -> AGC -> VAD -> KWS / ASR / 录音切片这个顺序不是固定模板,但有几个约束:
- 有设备播放声时,先让 AEC 去掉扬声器回采,否则播放内容会持续触发 VAD。
- 强降噪可能破坏轻声和辅音,VAD 应同时在原始音频与增强音频上做对比验证。
- AGC 在非语音阶段抬升底噪会增加误触发,应限制静音增益或让 AGC 使用 VAD 状态。
- VAD 若运行在 16 kHz,而采集链路是 48 kHz,应明确使用哪一路重采样结果,不能只改采样率参数。
长录音转写
长录音可以先经 VAD 切成语音片段,再交给非流式 ASR。这样能跳过大段静音并控制单次识别长度,但切分边界必须保留上下文,过度切碎会让标点、说话人和语言模型上下文变差。
流式语音交互
流式系统通常持续把音频送给 VAD。检测到开始后创建或激活 ASR 流,检测到结束后等待端点策略确认,再提交最终结果。相关运行模式见 sherpa-onnx 识别运行模式。
唤醒后监听
设备被唤醒后,VAD 可以判断用户是否开始说话以及何时停止。如果唤醒词和命令紧邻,应保留唤醒前后的共享缓冲,不能在唤醒事件发生时清空整段音频。
流式实现要点
每路会话需要独立维护模型状态、当前分段状态和环形缓存:
text
Session
├── model_state # 神经网络的历史状态
├── segment_state # idle / speech / ending
├── pre_roll_buffer # 字头保护
├── current_segment # 当前语音片段
└── sample_counter # 计算准确时间戳以下情况必须重置状态:新文件、新通话、新设备流、采样率改变、时间戳跳变或中间音频丢失。不能把不同用户的音频交错送入同一个有状态实例,也不能为了并行推理打乱同一会话的帧顺序。
时间戳应以累计采样点为基准,而不是按回调次数估算。设备回调的块大小可能变化,网络抖动也可能造成空洞;只有采样点计数能稳定映射回原音频。
如何评估
帧级准确率不能完整反映工程体验。背景静音帧通常远多于语音帧,即使模型总是输出静音,也可能得到看似较高的准确率。评估至少分三层:
| 层级 | 指标 | 说明 |
|---|---|---|
| 帧级 | Precision、Recall、F1、ROC | 判断语音与非语音的基础能力 |
| 片段级 | 漏检率、误检率、碎片数、起止点偏差 | 判断切片是否完整稳定 |
| 系统级 | 首字丢失率、句尾截断率、误触发次数/小时、提交延迟、WER | 判断 VAD 对真实业务的影响 |
测试集要覆盖安静近场、远场轻声、车噪、风噪、键盘声、音乐和电视人声、设备播放、双讲、儿童声、短词、长停顿以及不同麦克风增益。训练集上的阈值不能直接视为设备量产参数。
排错闭环
| 现象 | 优先检查 | 调整顺序 |
|---|---|---|
| 第一个字缺失 | 前置缓存、回调延迟、起始确认时长 | 先增大前置缓存,再调整起始阈值 |
| 句尾被截断 | 尾部缓存、最短静音、降噪失真 | 先补尾部,再延长静音确认 |
| 一句话被切碎 | 结束阈值、最短静音、丢帧 | 先排除丢帧,再增加静音确认 |
| 音乐或电视持续触发 | AEC、数据集覆盖、阈值 | 先确认回声路径,再评估模型或融合策略 |
| 轻声漏检 | 输入幅度、AGC、模型概率分布 | 先检查采集幅度,再降低阈值或补数据 |
| 结束很慢 | 最短静音、尾部 padding、业务端点策略 | 分清 VAD 延迟和语义端点等待 |
| 多路并发结果串线 | 状态实例、缓冲归属、重置时机 | 每会话独立状态并补充隔离测试 |
排错时同时保存原始 PCM、前处理后 PCM、逐帧概率、状态变化和最终时间戳。只看最终切片无法区分是模型判断错误、平滑策略错误,还是音频链路丢帧。
方案选择
能量阈值适合按键录音、安静近场或资源极紧张的设备,但对非平稳噪声和背景人声较敏感。WebRTC VAD 等传统方案体积小、依赖少,适合先建立低成本基线。神经网络 VAD 对复杂场景通常更稳,但需要模型运行时、状态管理和目标设备基准测试。
如果需要一个可离线运行、支持流式状态并已有多语言预训练模型的方案,可以继续阅读 Silero VAD。如果系统已经使用 sherpa-onnx,应同时检查其模型包版本、接口参数和 ASR 端点配置,不能只替换模型文件。
总结
VAD 的输出只是语音概率,稳定的工程结果来自模型、分段状态机、前后缓存和业务端点策略的组合。调优时先固定音频链路和状态管理,再看概率分布,最后按起点、终点、碎片、误触发和系统延迟逐项收敛。
