NeMo ASR+VAD 推理管线实战指南:基于 VAD 分段语音识别的完整流程与源码解析
2026/9/14 2:09:36 网站建设 项目流程

NeMo ASR+VAD 推理管线实战指南:基于 VAD 分段语音识别的完整流程与源码解析

【免费下载链接】SpeechA scalable generative AI framework built for researchers and developers working on Large Language Models, Multimodal, and Speech AI (Automatic Speech Recognition and Text-to-Speech)项目地址: https://gitcode.com/GitHub_Trending/nem/Speech

本文以 NVIDIA NeMo 仓库(当前项目根目录/data/web/disk1/git_repo/GitHub_Trending/nem/Speech)中 examples/asr/asr_vad/README.md 为骨架,结合 speech_to_text_with_vad.py 及 VAD 工具库源码,系统讲解 ASR+VAD 联合推理管线的输入输出格式、命令参数、Frame-VAD / Segment-VAD 两种模式、基于 RTTM 的非语音段特征处理策略,以及每个关键参数在底层代码中的实际作用。读完本文,你将能直接上手运行"先语音活动检测、后语音识别"的完整推理流程,也能独立配置 VAD 后处理参数以获得理想的语音分段效果。

一、管线概览:ASR 与 VAD 如何协同工作

speech_to_text_with_vad.py提供了一条完整的ASR+VAD 推理管线,同时支持三种运行模式:

  • ASR + VAD 联合推理:先用 VAD 模型检测语音/非语音区间,再仅对语音部分进行 ASR 转写(默认模式);
  • 仅 ASR:跳过 VAD,直接对整段音频做语音识别;
  • 仅 VAD:只做语音活动检测,输出语音分段结果,不进行转写。

从源码主函数 main() 可以看出,整条管线按顺序执行三个核心阶段:

  1. prepare_inference_manifest(cfg):规范化输入清单(manifest 或音频目录);
  2. extract_audio_features(...):使用 VAD 模型的 preprocessor 提取并缓存音频特征(.pt 文件);
  3. 若配置了vad_model,执行run_vad_inference(...)生成语音分段(RTTM);
  4. 若配置了asr_model,执行run_asr_inference(...)基于分段结果完成转写并计算 WER/CER。

这三个阶段依次执行,中间产物(特征文件、VAD 预测、RTTM)都会被写入输出目录,因此重复运行同一任务时,如果中间结果已存在,程序会自动跳过已完成的阶段(详见下文"断点续跑"说明)。

二、输入格式:Manifest 与音频目录两种方式

管线支持两种输入形式,由InferenceConfig中的manifest_filepathaudio_dir两个字段控制(源码见 InferenceConfig):

输入方式配置参数说明
Manifest 清单manifest_filepath=/PATH/TO/MANIFEST.json每行一个 JSON 字典的清单文件,字段要求严格
音频目录audio_dir=/PATH/TO/AUDIOS+audio_type=wav自动扫描目录下所有指定类型的音频文件,audio_type默认为wav

2.1 Manifest 必备字段

Manifest 是 NeMo 生态通用的 JSON Lines 格式,每一行必须是一个合法的 Python 字典,其中["audio_filepath", "offset", "duration"]三个字段为必需项:

{"audio_filepath": "/path/to/audio_file1", "offset": 0, "duration": 10000} {"audio_filepath": "/path/to/audio_file2", "offset": 0, "duration": 10000}

各字段含义:

  • audio_filepath:音频文件的绝对路径(或相对路径,程序会自动尝试基于 manifest 所在目录解析);
  • offset:从音频的哪个时间点(秒)开始处理;
  • duration:要处理的音频时长(秒)。注意示例中写的是10000,即处理从offset开始长达 10000 秒的音频(实际会被音频总长度截断),等效于处理整段音频。

2.2 提供文本标注以计算 WER

如果希望管线在转写完成后自动计算WER(词错误率),需要在 manifest 中额外提供text字段作为 ground truth:

{"audio_filepath": "/path/to/audio_file1", "offset": 0, "duration": 10000, "text": "hello world"} {"audio_filepath": "/path/to/audio_file2", "offset": 0, "duration": 10000, "text": "hello world"}

当 manifest 中不存在text字段时,run_asr_inference会统计生成的字数/词数并打印;存在text时则调用word_error_rate同时计算并打印 WER 与 CER(源码见 run_asr_inference):

----------------------------------------- WER=0.0432, CER=0.0125 -----------------------------------------

2.3 音频目录输入的内部处理

audio_dir不为空且未提供manifest_filepath时,prepare_inference_manifest 会递归扫描目录下所有*.{audio_type}文件,为每个文件生成{"audio_filepath": ..., "duration": 1000000, "offset": 0}条目,并自动写入输出目录下的temp_manifest_input.json。同时该函数还会对 manifest 中的相对路径做归一化:若audio_filepath长度小于 255、不是绝对路径且相对 manifest 所在目录可找到文件,则自动拼接为绝对路径,并统一补上label="infer"text="-"两个字段。

三、输出:VAD 预测、RTTM 分段与转写清单

输出写入output_dir(默认./outputs),主要内容包括:

产物路径/命名说明
音频特征outputs/features/*.pt每段音频提取的 log-mel 特征(torch tensor)
帧级 VAD 预测outputs/vad_frame_pred/*.frame每行一个 speech 概率值,对应一个 VAD 帧
语音分段(RTTM)outputs/vad_rttm-{postprocessing 参数拼接}/*.rttm每个语音段的起止时间与时长
转写结果清单outputs/{原清单名}-{ASR模型名}-{tag}.json每行在原条目基础上追加pred_textfeature_filerttm_file
中间清单temp_manifest_input.jsontemp_manifest_input_feature.jsontemp_manifest_{seg}_*.json各阶段传递的临时数据

其中 RTTM 分段目录名会把后处理参数拼进目录名(如vad_rttm-onset0.3offset0.3pad_onset0.2...),源码见 run_vad_inference,便于对比不同后处理参数的效果。

四、快速上手:运行 ASR+VAD 推理

以默认设置运行 ASR+VAD 联合推理,在examples/asr/asr_vad目录下执行:

python speech_to_text_with_vad.py \ manifest_filepath=/PATH/TO/MANIFEST.json \ vad_model=vad_multilingual_frame_marblenet \ asr_model=stt_en_conformer_ctc_large \ vad_config=../conf/vad/frame_vad_infer_postprocess.yaml

参数说明:

  • manifest_filepath:输入清单路径(必填,除非使用audio_dir);
  • vad_model:VAD 模型名。可传.nemo本地模型路径、.ckpt检查点路径,或 NGC 上的预训练模型名(如vad_multilingual_frame_marblenet)。init_frame_vad_model会按上述顺序依次尝试加载(见 vad_utils.py);
  • asr_model:ASR 模型名,同样支持.nemo/.ckpt/ NGC 预训练名三种来源(见 init_asr_model);
  • vad_config:VAD 后处理 YAML 配置文件路径(见下文第六节)。

提示:若使用音频目录输入,将manifest_filepath替换为audio_dir=/PATH/TO/AUDIOS audio_type=wav即可;audio_type默认值就是wav

4.1 仅使用 ASR(关闭 VAD)

设置vad_model=Noneuse_rttm=False,管线将跳过 VAD 阶段,直接对整段音频转写:

python speech_to_text_with_vad.py \ manifest_filepath=/PATH/TO/MANIFEST.json \ asr_model=stt_en_conformer_ctc_large \ vad_model=None \ use_rttm=False

4.2 仅使用 VAD(不转写)

设置asr_model=None,同时指定vad_modelvad_config,管线只输出语音分段:

python speech_to_text_with_vad.py \ manifest_filepath=/PATH/TO/MANIFEST.json \ vad_model=vad_multilingual_frame_marblenet \ asr_model=None \ vad_config=../conf/vad/frame_vad_infer_postprocess.yaml

4.3 开启性能剖析

设置profiling=True可启用 PyTorch Profiler,对 CPU/CUDA 各阶段耗时、显存占用进行记录,并在结束后打印按cuda_time_total排序的前 15 行统计表(源码见 main)。注意:profiling 会显著拖慢程序运行速度,仅建议在性能排查时临时开启。

五、基于 RTTM 的非语音段特征处理

VAD 阶段会把检测出的语音分段写入 RTTM 文件,ASR 阶段可以选择用这些分段信息"屏蔽"非语音区域的特征,避免模型对静音/噪声段产生无效输出。相关参数如下:

5.1 use_rttm 与 rttm_mode

  • use_rttmTrue/False,是否启用 RTTM 特征处理,默认True
  • rttm_mode:RTTM 的使用方式,仅可为maskdrop
    • mask:用 RTTM 分段信息掩蔽非语音段的特征(把特征值替换为feat_mask_val),特征序列长度保持不变;
    • drop:直接丢弃非语音段的特征,仅保留语音段特征送入 ASR,特征序列变短。

源码中这两个参数被透传给feature_to_text_dataset.get_bpe_dataset / get_char_dataset(见 feature_to_text_dataset.py 与 run_asr_inference),由数据集的use_rttmrttm_modefeat_mask_valframe_unit_time_secs等字段控制实际的特征裁剪/掩蔽逻辑。

5.2 实践建议:drop 模式要留足 padding

文档与代码均建议:rttm_mode='drop'时,应使用更大的pad_onsetpad_offset(在 VAD 配置的postprocessing中设置),以避免 VAD 边界误差导致语音特征被误删。因为 drop 模式是硬性裁剪,边界上的轻微误差会直接丢掉有效语音。

5.3 feat_mask_val:掩蔽值

设置feat_mask_val可指定掩蔽时使用的具体特征值。默认feat_mask_val=None,此时程序自动选择默认值:

  • normalize='post_norm'时使用-16.530(零 log-mel 谱特征值,即log(1e-7)量级的静音特征)——README 中写作 -16.530,脚本 docstring 中写作 -16.635,二者是同一概念的不同精度表述,实际以运行时打印的feat_mask_val为准;
  • normalize='pre_norm'时使用0(与 SpecAugment 的掩蔽值一致,即特征归一化前的 0 值)。

5.4 normalize:掩蔽与归一化的先后顺序

normalize决定特征归一化与掩蔽的先后关系:

  • normalize='pre_norm'先归一化、后掩蔽
  • normalize='post_norm'先掩蔽、后归一化(默认值)。

配套参数normalize_type(默认per_feature)决定计算均值/方差的方式,normalize_audio_db(默认None)可设置为数值以在特征提取前对音频做 RMS DB 归一化,这两个参数同样会传入特征提取与 ASR 数据集的配置中。

六、Frame-VAD 与 Segment-VAD 两种模式

VAD 模型分为两类,由vad_type参数选择(默认frame),源码在 run_vad_inference 中据此分别调用init_frame_vad_model(加载EncDecFrameClassificationModel)或init_vad_model(加载EncDecClassificationModel)。

6.1 Frame-VAD(帧级 VAD)

python speech_to_text_with_vad.py \ manifest_filepath=/PATH/TO/MANIFEST.json \ vad_model=vad_multilingual_frame_marblenet \ asr_model=stt_en_conformer_ctc_large \ vad_config=../conf/vad/frame_vad_infer_postprocess.yaml
  • 对每个20ms音频帧输出一个 speech/non-speech 预测;
  • 对应的 frame_vad_infer_postprocess.yaml 中,shift_length_in_sec: 0.02(20ms 帧长)与window_length_in_sec: 0.0(帧级 VAD 必须为 0,无需滑窗上下文)是预训练 Frame-VAD 模型(如vad_multilingual_frame_marblenet)的固定约束,不可随意改动;
  • 帧级预测结果保存为.frame文件,每行一个概率值(generate_vad_frame_pred中逐行写入,见 speech_to_text_with_vad.py)。

6.2 Segment-VAD(分段级 VAD)

python speech_to_text_with_vad.py \ manifest_filepath=/PATH/TO/MANIFEST.json \ vad_model=vad_multilingual_marblenet \ asr_model=stt_en_conformer_ctc_large \ vad_type='segment' \ vad_config=../conf/vad/vad_inference_postprocessing.yaml
  • 将音频切分为重叠的短分段,对每个分段独立做 VAD 分类,最后把各分段的预测拼接成完整语音分段表;
  • 分段大小与步长由 VAD 配置中的window_length_in_secshift_length_in_sec控制:对应的 vad_inference_postprocessing.yaml 中默认值分别为0.63 秒0.08 秒(0.08s 步长用于更快的推理);
  • Segment-VAD 可配合重叠平滑(smoothing设为medianmeanoverlap=0.875)对重叠分段的预测做多数表决/平均,提升边界稳定性——该逻辑由generate_overlap_vad_seq实现(见 vad_utils.py)。注意:smoothingoverlap在 Frame-VAD 配置中已标记为 Deprecated,仅对 Segment-VAD 有意义。

七、VAD 后处理配置详解

两份配置文件的vad.parameters.postprocessing字段控制"帧级概率 → 语音分段"的转换,核心参数如下(Frame-VAD 与 Segment-VAD 配置中默认值略有差异):

参数Frame-VAD 默认值Segment-VAD 默认值作用
onset0.30.5语音开始判定阈值:概率超过该值认为进入语音
offset0.30.3语音结束判定阈值:概率低于该值认为语音结束
pad_onset0.20.2每个语音段前额外填充的时长(秒),防止切掉语音起始
pad_offset0.20.2每个语音段后额外填充的时长(秒)
min_duration_on0.20.5小于该时长的语音段将被删除(短语音滤波)
min_duration_off0.20.5小于该时长的非语音间隙将被合并到语音段
filter_speech_firstTrueTrue滤波执行顺序:先滤语音段还是先合并间隙

底层转换由generate_vad_segment_table调用binarization(阈值二值化)与filtering(短段滤波/间隙合并)完成(见 vad_utils.py 与generate_vad_segment_table_per_tensor),最终按 RTTM 格式写出:

SPEAKER <NA> 1 0.3200 0.5600 <NA> <NA> speech <NA> <NA>

Frame-VAD 配置中另有两个与长音频处理相关的字段:

  • prepare_manifest.auto_split: true:自动按split_duration切分超长音频,避免 CUDA 显存溢出;
  • prepare_manifest.split_duration: 400:单条最长秒数,若仍显存不足可调小。

八、断点续跑与临时数据

整个管线以"产物是否已存在"作为阶段跳过的依据,具备天然的断点续跑能力:

  • outputs/features/temp_manifest_input_feature.json已存在,特征提取阶段直接跳过(extract_audio_features);
  • outputs/vad_frame_pred目录已存在,帧级预测阶段直接跳过;
  • outputs/vad_rttm-{参数拼接}目录已存在,分段生成阶段直接跳过。

因此,若需调整后处理参数(如onset/pad_onset)或更换 ASR 解码方式,不必重跑特征提取与 VAD 预测——只需删除对应阶段的输出目录或修改配置后重跑,管线会复用已有中间产物。所有临时文件都落在output_dir(默认./outputs)中,不会污染输入数据。

九、进阶参数:InferenceConfig 全字段速查

除前述参数外,InferenceConfig数据类(speech_to_text_with_vad.py)还提供以下可直接在命令行覆盖的选项:

参数默认值说明
batch_size1ASR 批大小。注意特征提取与 VAD 仅支持单样本/批(内部强制 batch=1)
num_workers8DataLoader 工作进程数
sample_rate16000音频采样率
frame_unit_time_secs0.01单帧时长(秒),须与 ASR 配置中的window_stride一致(通常 10ms)
audio_typewavaudio_dir模式下扫描的音频扩展名
output_dir./outputs输出目录,可覆盖
output_filename自动生成转写结果清单文件名,默认按模型名+处理方式拼装
pred_name_postfixNone自定义输出文件名后缀
compute_langsFalse置 True 时输出语言 ID 信息(需模型支持)
ctc_decodingCTCDecodingConfig()CTC 解码策略配置
rnnt_decodingRNNTDecodingConfig(fused_batch_size=-1)RNNT 解码策略配置

解码策略的自动选择逻辑值得注意(见 run_asr_inference):

  • 若传入额外参数decoder_typernnt/ctc),按 Hybrid 模型处理,分别调用rnnt_decoder_predictions_tensorctc_decoder_predictions_tensor
  • 否则若模型具有joint属性(RNNT 模型),走 RNNT 解码;
  • 否则按 CTC 模型处理,并自动从asr_model.decoder.vocabulary读取字符表。

十、运行前置条件

  1. 环境:需安装本项目 NeMo(pip install nemo_toolkit[asr]或从仓库源码安装,参见 README.md),并保证 CUDA 环境可用(代码会自动回退到 CPU,但推理会明显变慢);
  2. 模型下载vad_model/asr_model传 NGC 预训练模型名时,程序首次运行会自动下载模型权重,需保持网络连通;也可预先将模型导出为.nemo文件传入本地路径离线使用;
  3. 音频格式:默认要求 16kHz 单声道音频,若采样率不一致需先重采样,或在 manifest 中按实际时长正确填写offset/duration
  4. 运行位置:示例脚本与配置采用相对路径(../conf/vad/...),建议在examples/asr/asr_vad目录下执行,或将vad_config改为绝对路径。

总结

speech_to_text_with_vad.py是 NeMo 中"VAD 前置过滤 + ASR 精准转写"的标准参考实现:一条命令即可在整段长音频上自动完成语音活动检测、语音分段(RTTM)、分段转写与 WER/CER 评估。理解 Frame-VAD 与 Segment-VAD 的差异、mask/drop两种 RTTM 处理策略,以及postprocessing各阈值对分段质量的影响,是把它应用到生产场景(电话录音转写、会议语音、长音频批处理)的关键。建议以本仓库的 asr_vad 示例、frame_vad_infer_postprocess.yaml 与 vad_inference_postprocessing.yaml 为起点,结合 vad_utils.py 中的二值化/滤波源码进行参数调试。

【免费下载链接】SpeechA scalable generative AI framework built for researchers and developers working on Large Language Models, Multimodal, and Speech AI (Automatic Speech Recognition and Text-to-Speech)项目地址: https://gitcode.com/GitHub_Trending/nem/Speech

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询