登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

语音转写前怎样用 VAD 切除静音区

来源:17golang原创

时间:2026-10-17 23:46:37 371浏览 收藏

会议录音、客服语音或手机采访交给 ASR 前,先用 VAD(Voice Activity Detection,语音活动检测)找出真正有人声的区间,通常能减少无效音频和长静音带来的等待时间。稳妥做法不是把所有低能量片段直接删掉,而是先得到语音时间戳,再为每段保留少量前后上下文,最后把原始偏移一起传给转写环节。

官方地址:https://github.com/snakers4/silero-vad

如果目标只是切掉静音,先把 VAD 当成“边界检测器”,不要把它当成最终转写器。真正影响结果的是采样率、静音持续时间和边界 padding 三组参数。
要点速览
  • Silero VAD 常用 8 kHz 或 16 kHz 输入,先统一音频格式再检测。
  • threshold 决定“像不像语音”,min_silence_duration_ms 决定何时断开,speech_pad_ms 用来保护词头词尾。
  • 切段后必须保存原始 start/end;只拼接语音会让后续字幕时间轴失真。

先把采样率与 VAD 输入边界固定下来

VAD 的输入边界要比 ASR 的模型选择更早确定。以 Silero VAD 为例,官方实现支持 8000 和 16000 Hz;录音是 44.1 kHz 或 48 kHz 时,应先用音频工具重采样到目标采样率,而不是把原始采样率直接塞给检测函数。还要统一声道和张量形状,否则同一组参数在不同文件上的边界会漂移。

下面的调用只展示数据关系,不代表已经在本机执行。return_seconds=True 让时间戳直接用秒表示,后续回写 ASR 结果更直观。

import torch

# 载入官方模型与工具;实际项目应固定依赖版本并缓存模型文件
model, utils = torch.hub.load(
    repo_or_dir="snakers4/silero-vad",
    model="silero_vad",
    trust_repo=True,
)
get_speech_timestamps, _, read_audio, _, _ = utils

SAMPLE_RATE = 16000  # 只使用模型支持的采样率
wav = read_audio("input.wav", sampling_rate=SAMPLE_RATE)

# start/end 是语音区间;阈值和边界参数应按业务录音调参
timestamps = get_speech_timestamps(
    wav,
    model,
    sampling_rate=SAMPLE_RATE,
    threshold=0.5,
    min_speech_duration_ms=250,
    min_silence_duration_ms=220,
    speech_pad_ms=120,
    return_seconds=True,
)
VAD 输入边界说明图:采样率、单声道音频、模型和语音时间戳之间的静态关系
图1:VAD 输入边界结构说明图,展示采样率、音频张量、检测参数与语音时间戳的关系;不是运行截图。

用三个参数控制“切得干不干净”

threshold 越高,越不容易把背景噪声当成人声,但轻声和远场说话也更可能被漏掉;min_silence_duration_ms 太小会把一句话切碎,太大又会把两句话粘在一起;speech_pad_ms 则给每个区间补边,重点保护爆破音、词头和词尾。工程上不要先追求“静音绝对为零”,应先保证关键字不被截断。

参数解决的问题调整方向
threshold噪声误报或轻声漏检噪声多时上调,远场轻声多时下调
min_silence_duration_ms短停顿是否切段对话快时减小,长句多时增大
speech_pad_ms词头词尾被削掉先保守增加,再观察 ASR 重复字
max_speech_duration_s长段不利于转写按 ASR 上下文窗口拆分,并保留偏移

VAD 只给出候选边界,混响、音乐、多人重叠说话和笑声都可能改变概率曲线。调参时应抽取一批真实录音,分别观察漏切、误切和重复字,而不是只用一段安静样本决定阈值。

保留上下文,再把分段交给转写模型

拿到时间戳后,不建议直接把各段首尾裁到极限。可以用 100~200 毫秒的 padding 扩展区间,并把相邻扩展后重叠的区间合并;这样既减少句首丢字,也避免 ASR 在两个片段之间失去语境。合并后的每段仍要记录原始坐标。

def expand_segments(timestamps, total_seconds, pad_seconds=0.12):
    # 扩展边界并合并相交区间,避免词头词尾被硬切开
    expanded = []
    for item in timestamps:
        start = max(0.0, item["start"] - pad_seconds)
        end = min(total_seconds, item["end"] + pad_seconds)
        if expanded and start 
VAD 分段与 ASR 边界说明图:语音段、padding、ASR 分段和原始时间偏移的关系
图2:分段与转写边界结构说明图,强调 padding、ASR 输入和原始时间偏移的静态关系;不是运行结果。

常见问题

VAD 切完后,转写结果少了句首怎么办?

先增加 speech_pad_ms 或扩展分段的前置 padding,再检查采样率和 threshold;不要一开始就把阈值调得很低。

静音切除后为什么字幕时间对不上?

通常是只保存了拼接音频,没有保存每段在原文件中的 start/end。转写结果必须带回原始偏移,再生成字幕时间轴。

VAD 能代替说话人识别吗?

不能。VAD 只判断某个时间段是否存在语音活动,不负责区分是谁在说,也不负责把多人重叠语音分离开。

这套流程的边界很清楚:VAD 负责找语音区间,padding 负责保护边界,ASR 负责识别文字,时间偏移负责把结果放回原音频。先固定输入格式,再用真实录音调三个参数,切静音才不会变成“少字但更快”的假优化。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>