NeMo 流式 / 缓冲 / 分块 ASR 推理实战:AED 与 Transducer 模型的 chunked 与 streaming 解码指南
2026/9/14 9:26:05 网站建设 项目流程

NeMo 流式 / 缓冲 / 分块 ASR 推理实战:AED 与 Transducer 模型的 chunked 与 streaming 解码指南

【免费下载链接】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

本指南围绕 NeMo(当前仓库)中examples/asr/asr_chunked_inference目录下的推理脚本,系统讲解 Streaming(流式)、Buffered(缓冲)、Chunked(分块)三种长音频 ASR 推理方式的原理、参数与实战用法。读完本文,你将掌握 Transducer(RNNT/TDT)模型与 MultitaskAED(如 Canary 系列)模型各自的分块推理脚本、流式解码策略(Wait-k / AlignAtt / Middle-Token / LCS)以及 chunk 大小与延迟、准确率之间的权衡方法,可直接复现仓库中的命令行示例。

三种推理模式的定位与区别

该目录同时承载了三类推理脚本,分别面向 Transducer 模型(RNNT、TDT)和 MultitaskAED 模型(如nvidia/canary-1b系列):

推理模式适用模型核心脚本
Chunked InferenceMultitaskAED(Canary 等)aed/speech_to_text_aed_chunked_infer.py
AED 流式推理MultitaskAED(Canary 等)aed/speech_to_text_aed_streaming_infer.py
Buffered InferenceRNNT / TDT / Hybridrnnt/speech_to_text_buffered_infer_rnnt.py
流式 / 缓冲推理(新)RNNT / TDT / Hybridrnnt/speech_to_text_streaming_infer_rnnt.py

对于 CTC 模型,本目录不适用,README 明确指引使用独立的 asr_streaming_inference.py 脚本。

Streaming 与 Buffered 的本质差异

README 指出:streaming ASR 与 buffered ASR 的主要区别在于 chunk size(块大小)和总上下文缓冲区(total context buffer)的大小,二者只是同一套“滑动窗口”机制的不同参数配置:

  • 减小 chunk size:首个预测结果的延迟更低,模型输出文本的“滞后感”更短;但由于每个块内携带的信息变少,会导致更高的 WER(词错误率)。
  • 增大 chunk size:语音与转写之间的延迟增加(这正是 buffered ASR 的形态);但模型拥有更多上下文来正确转写,能获得更准确的转录文本。

这一权衡贯穿本目录全部四个脚本:所有脚本都通过chunk(块)与left/right context(左右上下文)两个维度来控制“延迟 vs 准确率”的平衡点。

Chunked Inference:AED 模型的长音频分段推理

对于 MultitaskAED 模型,仓库提供 speech_to_text_aed_chunked_infer.py 执行分块推理。该脚本将输入音频切分为不重叠chunk_len_in_secs秒片段,对每个片段单独执行推理,最后将各片段结果拼接成完整转录文本。

输入方式:audio_dir 与 dataset_manifest

脚本支持两种输入,且优先 audio_dir(从源码main()可见,audio_dir存在时manifest会被置为None,见 speech_to_text_aed_chunked_infer.py):

  • audio_dir:音频文件目录,脚本会以audio_type(默认wav)递归匹配目录下所有音频文件;
  • dataset_manifest:JSON manifest 文件路径。

README 特别强调:推荐使用 manifest 输入,否则模型只会执行带标点和大小写的英文 ASR。manifest 每行格式如下:

{ "audio_filepath": "/path/to/audio.wav", # path to the audio file "duration": 10000.0, # duration of the audio "taskname": "asr", # use "s2t_translation" for AST "source_lang": "en", # Set `source_lang`==`target_lang` for ASR. Currently supported for 25 EU languages. "target_lang": "de", # See https://huggingface.co/nvidia/canary-1b-v2 }

其中tasknameasr时执行语音识别,为s2t_translation时执行语音翻译(AST);source_langtarget_lang相等时即 ASR,仓库源码注释显示当前支持 25 种欧盟语言。

命令行示例与核心参数

python examples/asr/asr_chunked_inference/aed/speech_to_text_aed_chunked_infer.py \ model_path=null \ pretrained_name="nvidia/canary-1b-flash" \ audio_dir="<(optional) path to folder of audio files>" \ dataset_manifest="<(optional) path to manifest>" \ output_filename="<(optional) specify output filename>" \ chunk_len_in_secs=40.0 \ batch_size=16 \ decoding.beam.beam_size=1

核心参数(依据脚本中TranscriptionConfigdataclass,见 speech_to_text_aed_chunked_infer.py):

参数默认值说明
model_path/pretrained_nameNone二者必填其一:本地.nemo文件路径,或 Hugging Face 预训练模型名(如nvidia/canary-1b-flash
audio_dir/dataset_manifestNone二者必填其一:音频目录或 manifest 路径
chunk_len_in_secs40.0每个分块的时长(秒)
model_stride8模型下采样因子:FastConformer 为 8,Conformer 为 4
batch_size8并行处理的 chunk 数量
timestampsFalse输出词级与段级时间戳(仅部分模型支持)
compute_langsFalse输出语言 ID 信息
output_filenameNone输出文件名;为None时输出到输入文件同目录
cudaNone指定 CUDA 设备;负数表示纯 CPU 推理
amp/amp_dtypeFalse/float16自动混合精度开关,amp_dtype可为float16bfloat16
overwrite_transcriptsTrue是否覆盖已存在的转录结果文件
calculate_werTrue计算词错误率,需要 manifest 中含text字段

时间戳与长音频的注意事项

  • 源码在main()入口处有一个重要约束:当timestamps=Truechunk_len_in_secs != 10.0时,脚本会打警告并强制将chunk_len_in_secs重置为 10.0(见 speech_to_text_aed_chunked_infer.py)。即开启时间戳时建议使用 10 秒分块以获得最优结果。
  • Canary-1b-v2 长文推理:该模型可通过.transcribe()方法进行长文推理,内部采用带重叠窗口的动态分块以获得更好性能。这一行为在转写单个音频文件或batch_size=1时自动启用。

底层原理:FrameBatchMultiTaskAED

从源码看,chunked 推理的核心类为 FrameBatchMultiTaskAED,它接收frame_len=chunk_len_in_secstotal_buffer=chunk_len_in_secsbatch_size三个参数——注意此处frame_lentotal_buffer相等,即各 chunk 之间互不重叠,与 README 中“non-overlapping chunks”的描述一致。真正的推理循环由 get_buffered_pred_feat_multitaskAED() 驱动:它先根据preprocessor_cfg构建一个不执行归一化的预处理器(归一化在 frame_bufferer 内按 buffer 完成),逐条读取音频/ manifest,调用asr.read_audio_file()asr.transcribe()得到假设结果。脚本在推理前还会把preprocessor.ditherpreprocessor.pad_to置零,并要求模型使用per_feature归一化(见 speech_to_text_aed_chunked_infer.py)。

推理完成后,结果通过write_transcription()写入输出 manifest,若calculate_wer=True则调用cal_write_wer()计算并输出 WER/CER 汇总。

AED 流式推理:Wait-k 与 AlignAtt 解码策略

面向实时场景,仓库提供 speech_to_text_aed_streaming_infer.py 支持 AED(Canary)模型的流式解码,目前支持Wait-kAlignAtt两种策略:

  • Wait-k 策略:每个新的语音 chunk 只预测一个 token,整体延迟较高。由于不清楚在有限缓冲区下何时可以丢弃左侧上下文,建议将左上下文设为最大可能值(无限左上下文)
  • AlignAtt 策略:根据每次下一个 token 预测时的交叉注意力(cross-attention)条件决定:若条件满足,则无需增加音频输入即可继续预测下一个 token;否则需要扩大音频缓冲区。相比 Wait-k,该策略延迟更低,也适合固定左上下文的窗口识别(但可能损失部分准确率)。

音频缓冲区推荐配置

脚本 docstring 给出推荐的缓冲区设置:

  • 1.5s 延迟进行流式推理:10-1-0.5(左上下文 10s、chunk 1s、右上下文 0.5s)。

命令行示例与关键参数

python examples/asr/asr_chunked_inference/aed/speech_to_text_aed_streaming_infer.py \ pretrained_name=nvidia/canary-1b-v2 \ model_path=null \ audio_dir="<optional path to folder of audio files>" \ dataset_manifest="<optional path to manifest>" \ output_filename="<optional output filename>" \ right_context_secs=0.5 \ chunk_secs=1.0 \ left_context_secs=10.0 \ batch_size=32 \ clean_groundtruth_text=False \ langid='en' \ decoding.streaming_policy=alignatt

该脚本的配置在TranscriptionConfig中定义(见 speech_to_text_aed_streaming_infer.py),关键参数如下:

参数默认值说明
chunk_secs2流式 chunk 时长(秒)
left_context_secs10.0左上下文:增大可提升质量且不影响理论延迟
right_context_secs2右上下文,直接影响延迟
decoding.streaming_policy必须是alignattwaitk,否则脚本抛ValueError(见 speech_to_text_aed_streaming_infer.py)
decoding.alignatt_thr8AlignAtt 策略的交叉注意力阈值
decoding.waitk_lagging2起始等待的 chunk 数,对两种策略均生效
decoding.exclude_sink_frames8计算 xatt 分数时排除的帧数(AlignAtt 专用)
decoding.xatt_scores_layer-2获取交叉注意力分数的层(AlignAtt 专用)
decoding.hallucinations_detectorTrue检测预测 token 中的幻觉(两种策略均生效)
calculate_bleuFalseAST 任务下计算 BLEU
calculate_latencyTrue计算 LAAL 解码延迟

解码过程的工程细节

从源码看,该脚本对上下文做了帧级对齐处理:先由make_divisible_by()将“音频采样数→特征帧→编码器帧”的换算因子对齐到编码器下采样因子的整数倍,再通过ContextSize把 left/chunk/right 三个秒级配置换算成编码器帧数与音频采样数(见 speech_to_text_aed_streaming_infer.py)。脚本会在日志中输出“修正后的上下文(秒)”与理论延迟

Theoretical latency: {latency_secs:.2f} seconds

(chunk + right_context)对应的音频时长。解码主循环使用StreamingBatchedAudioBuffer维护滑动音频缓冲区,每次向模型送入完整的[left | chunk | right]缓冲,随后仅解码 chunk 对应帧的编码器输出,并滑动窗口继续处理下一个 chunk(见 speech_to_text_aed_streaming_infer.py)。

延迟评估:LAAL 指标

脚本内置延迟评估:calculate_latency=True时,按策略调用compute_waitk_lagging()compute_alignatt_lagging(),输出基于Length-Adaptive Average Lagging (LAAL)度量的平均解码延迟(毫秒)。两种策略的取舍可概括为:

  • Wait-k:准确率更高,需要更大的左上下文,延迟更高;
  • AlignAtt:延迟更低,每个 chunk 可预测多个 token,更适合生产环境。

更多参数细节可参考仓库配套文档 canary_chunked_and_streaming_decoding.rst,其中还强调了 AST 任务下应使用+prompt.pnc+prompt.task+prompt.source_lang+prompt.target_lang等 prompt 参数控制模型行为。

RNNT Buffered 推理:Middle Token、LCS 与 TDT 合并算法

对于 Transducer 系模型,speech_to_text_buffered_infer_rnnt.py 提供缓冲推理。缓冲推理是音频片段长于 20~30 秒时的首选转写方式——尤其对 Conformer 这类时间与内存随音频时长二次增长的模型至关重要。它与流式推理的区别同样是 chunk 大小:缓冲推理使用大 chunk(5~10 秒)加额外上下文缓冲;流式推理使用小 chunk(0.1~0.25 秒)加额外右上下文缓冲。

Middle Token 合并算法

python examples/asr/asr_chunked_inference/rnnt/speech_to_text_buffered_infer_rnnt.py \ model_path=null \ pretrained_name=null \ audio_dir="<remove or path to folder of audio files>" \ dataset_manifest="<remove or path to manifest>" \ output_filename="<remove or specify output filename>" \ total_buffer_in_secs=4.0 \ chunk_len_in_secs=1.6 \ batch_size=32 \ clean_groundtruth_text=True \ langid='en'

Longer Common Subsequence (LCS) 合并算法

python examples/asr/asr_chunked_inference/rnnt/speech_to_text_buffered_infer_rnnt.py \ model_path=null \ pretrained_name=null \ audio_dir="<remove or path to folder of audio files>" \ dataset_manifest="<remove or path to manifest>" \ output_filename="<remove or specify output filename>" \ total_buffer_in_secs=4.0 \ chunk_len_in_secs=1.6 \ batch_size=32 \ merge_algo="lcs" \ lcs_alignment_dir=<OPTIONAL: Some path to store the LCS alignments>

此外可用DEBUG=1环境变量启动脚本,打印模型预测与 manifest 中的真实文本(如果存在)。

合并算法与模型类型的对应关系

脚本在运行时自动检测模型类型并选择默认算法:若模型损失为TDTLossNumba(TDT 模型),默认merge_algo="tdt",否则默认"middle";TDT 模型强制要求merge_algo='tdt',否则抛异常(见 speech_to_text_buffered_infer_rnnt.py)。三种算法的底层实现类均位于 streaming_utils.py:

  • middle:使用 BatchedFrameASRRNNT,基于中间 token拼接相邻 chunk 的预测;
  • lcs:使用 LongestCommonSubsequenceBatchedFrameASRRNNT,基于最长公共子序列做文本对齐合并,可指定lcs_alignment_dir保存中间对齐结果,且需通过frame_asr.lcs_delay = floor((total_buffer - chunk_len) / model_stride_in_secs)设置算法延迟;
  • tdt:使用 BatchedFrameASRTDT。

关键参数与解码配置

参数默认值说明
chunk_len_in_secs1.6chunk 时长(秒)
total_buffer_in_secs4.0总缓冲区时长(chunk + 左右填充),秒
merge_algoNonemiddle/lcs/tdtNone时按模型类型自动选择
max_steps_per_timestep5每个声学时间步最多解码的 token 数
stateful_decodingFalse是否启用跨 buffer 的状态保持解码
compute_timestampsFalse输出时间戳(仅部分模型支持)

脚本会自动改写解码配置:启用stateful_decoding或 TDT 时使用greedy策略,否则使用greedy_batch;同时强制preserve_alignments=True(计算中间 token 必需)、fused_batch_size=-1(临时关闭融合批处理)、beam.return_best_hypothesis=True(仅返回最优假设,见 speech_to_text_buffered_infer_rnnt.py)。

注意:该脚本运行时会打印弃用警告,推荐改用新的speech_to_text_streaming_infer_rnnt.py

RNNT 新一代流式 / 缓冲推理脚本

speech_to_text_streaming_infer_rnnt.py 是 RNNT 缓冲推理的替代与升级版本,同时支持缓冲与流式两种模式。其理论延迟(不含模型推理时间的纯延迟)=chunk 时长 + 右上下文时长;保持较大的左上下文(约 10s)并非必需,但可以提升转录质量。

推荐设置

脚本 docstring 给出的经验配置:

  • 长文件转写:多数场景下10-10-5(左上下文 10s、chunk 10s、右上下文 5s)可获得接近离线推理的结果;
  • 4s 延迟流式10-2-2通常与10-0.16-3.84效果相当或更好,且显著更快。

命令行示例

python examples/asr/asr_chunked_inference/rnnt/speech_to_text_streaming_infer_rnnt.py \ pretrained_name=nvidia/parakeet-rnnt-1.1b \ model_path=null \ audio_dir="<optional path to folder of audio files>" \ dataset_manifest="<optional path to manifest>" \ output_filename="<optional output filename>" \ right_context_secs=2.0 \ chunk_secs=2 \ left_context_secs=10.0 \ batch_size=32 \ clean_groundtruth_text=False \ langid='en'

相比旧脚本的新增能力

TranscriptionConfig(见 speech_to_text_streaming_infer_rnnt.py)可以看出,新脚本在旧脚本基础上扩展了多项能力:

  • 上下文三要素独立配置left_context_secs/chunk_secs/right_context_secs,脚本会打印修正后的上下文与理论延迟;
  • 小 chunk 显存优化:脚本在导入 PyTorch/NeMo 之前自动向PYTORCH_CUDA_ALLOC_CONF注入expandable_segments:True,注释表明使用小 chunk 时最多可节省超过 10 倍的 GPU 显存
  • 解码策略:支持greedy_batch(含 Label-Looping)、malsd_batchmaes_batch,分别对应GreedyBatchedLabelLoopingComputerBaseModifiedALSDBatchedRNNTComputerModifiedAESBatchedRNNTComputer
  • Per-Stream Biasinguse_per_stream_biasing=True时可按 manifest 中每条样本的biasing_request做上下文偏置;
  • 模拟解码simulated=True时先按 chunk 计算编码器输出并拼接,再一次性解码,用于快速实验不同解码算法(理论上应与支持流式解码的算法结果一致);
  • 时间戳与置信度timestamps输出词级时间戳(TDT 模型通过tdt_include_token_duration支持),confidence输出词级置信度;
  • 性能评估calculate_rtfx=True时输出 RTFx(实时率因子倒数),calculate_wer=True时计算 WER/CER。

流式主循环源码解析

与 AED 脚本类似,主循环按[left | chunk | right]窗口滑动:StreamingBatchedAudioBuffer.add_audio_batch_()填充缓冲区 → 编码器一次性处理整段缓冲 → 裁掉左右上下文、仅保留 chunk 对应的编码器帧 → 解码器在上一 chunk 状态(prev_batched_state)基础上继续解码 → 假设通过merge_()与历史合并,窗口前移一个 chunk(见 speech_to_text_streaming_infer_rnnt.py)。对于att_context_style='chunked_limited_with_rc'的统一 ASR 模型,脚本还会通过set_default_att_context_size()把注意力窗口与解码 chunk 对齐,这是实现极低延迟的关键。

参数速查与最佳实践总结

通用输入约束

四个脚本共同的约束(均由源码校验):

  • model_pathpretrained_name必须至少提供一个,否则抛ValueError
  • audio_dirdataset_manifest必须至少提供一个;
  • 模型预处理器必须使用per_feature归一化,否则脚本报错(仅记录错误日志);
  • 流式场景下dither=0.0pad_to=0会被强制设置,以保证分块特征一致性。

不同场景的参数选型建议

场景模型类型推荐配置预期延迟
长音频离线转写RNNTleft=10s, chunk=10s, right=5s接近离线
流式转写(4s 延迟)RNNTleft=10s, chunk=2s, right=2s约 4s
流式转写(1.5s 延迟)Canary (AED)left=10s, chunk=1s, right=0.5s约 1.5s
高准确率流式Canary (AED)Wait-k + 大左上下文较高
低延迟生产流式Canary (AED)AlignAtt + 固定窗口较低

实践要点

  1. chunk 越小延迟越低、WER 越高:chunk 大小是调节“首字延迟”与“准确率”的核心旋钮,所有脚本的 README 与 docstring 都围绕这一点展开。
  2. 左上下文只影响质量、不影响理论延迟:左右上下文与 chunk 独立配置,理论延迟恒为chunk + right
  3. manifest 优于裸音频目录:manifest 可以指定tasknamesource_langtarget_lang,从而控制 ASR/AST 任务与语言方向,避免默认英文 ASR。
  4. 开启时间戳注意 chunk 限制:AED chunked 脚本在timestamps=True时会强制chunk_len_in_secs=10.0
  5. 小 chunk 记得启用显存优化:RNNT 新脚本默认注入expandable_segments,如手动设置PYTORCH_CUDA_ALLOC_CONF请保留该选项。

延伸阅读

  • 配套文档:Canary Chunked and Streaming Decoding,包含 Wait-k / AlignAtt 参数与+prompt用法;
  • 流式相关教程:Streaming_ASR.ipynb、Buffered_Transducer_Inference.ipynb、Buffered_Transducer_Inference_with_LCS_Merge.ipynb;
  • CTC 模型流式推理:asr_streaming_inference;
  • 底层实现:streaming_utils.py(FrameBatchMultiTaskAEDBatchedFrameASRRNNTLongestCommonSubsequenceBatchedFrameASRRNNTContextSizeStreamingBatchedAudioBuffer)、transcribe_utils.py(get_buffered_pred_feat_rnntget_buffered_pred_feat_multitaskAED)。

【免费下载链接】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),仅供参考

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

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

立即咨询