ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

NeMo ASR Evaluator 实战指南:离线/分块推理、实时数据增强与分组 WER 深入分析

NeMo ASR Evaluator 实战指南:离线/分块推理、实时数据增强与分组 WER 深入分析 NeMo ASR Evaluator 实战指南离线/分块推理、实时数据增强与分组 WER 深入分析【免费下载链接】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 开源仓库中 ASR Evaluator 工具位于tools/asr_evaluator/目录的设计原理与完整用法。该工具用于对 ASR 模型及其相关能力如语音活动检测 VAD进行全方位评估一次配置即可在同一套评测流程中覆盖 offline离线整段、chunked分块流式与 offline_by_chunked分块模拟离线三种 NeMo 当前支持的推理模式支持静音、噪声等实时数据增强以检验模型鲁棒性并通过逐样本的插入、删除、替换错误率拆解以及基于元数据时长、情感、说话人、性别、年龄等的分组 WER 统计定位模型在特定人群与音频条件下的性能短板。读完本文你将能够独立配置评测 YAML、执行命令行评估、解读 report.json 输出并掌握如何基于 asr_evaluator.py 的引擎/分析师架构扩展新的评测任务。一、工具定位与核心能力ASR Evaluator 是 NeMo 语音工具链中专门用于“全面评估”ASR 模型性能的独立工具定位与examples/asr/speech_to_text_eval.py这类快速评估脚本不同它更强调多维度的鲁棒性与细粒度诊断。官方 README 列出了四大核心能力一键覆盖三种推理模式offline、chunked、offline_by_chunked同一份评测数据集可分别在三种模式下运行便于横向对比实时/离线场景的精度差异。实时数据增强在推理过程中即时注入静音、噪声等干扰on-the-fly augmentation用于 ASR 鲁棒性评估无需预先制作增强后的数据集。细粒度错误拆解对每个样本以及全量数据分别统计插入insertion、删除deletion、替换substitution错误率而不仅仅是单一 WER 数值帮助定位模型错误模式例如是漏读还是多读。基于元数据的分组评估当 manifest 中带有 duration、gender、emotion 等元数据字段时可对特定分组计算 WER例如验证模型在短音频、长音频、不同情感类别下的表现差异。从 README 的说明可以看出该工具的设计目标是在发布模型或上线前做“彻底的”thoroughly性能体检其评估维度覆盖了模型能力、鲁棒性与公平性三个层面。二、整体架构ENGINE 与 ANALYST 两段式流水线ASR Evaluator 由两个核心部分组成README 原话ENGINE引擎负责执行 ASR 推理产出带预测文本的 manifest。ANALYST分析师基于预测结果评估模型性能产出各类指标。这一架构在 asr_evaluator.py 主流程中体现得非常清晰程序被显式地分为三段# ① ENGINE 阶段执行 ASR 推理L48-L64 if cfg.analyst.metric_calculator.exist_pred_manifest is None: cfg.engine run_asr_inference(cfgcfg.engine) else: # 指定 exist_pred_manifest 时跳过推理直接复用已有预测结果 cfg.engine.output_filename cfg.analyst.metric_calculator.exist_pred_manifest # ② ANALYST 阶段计算指标L67-L93 if cfg.analyst.metric_calculator.get(metric, wer) wer: output_manifest_w_wer, total_res, eval_metric cal_write_wer(...) else: output_manifest_w_wer, total_res, eval_metric cal_write_text_metric(...) # ③ 元数据分组评估L100-L108 for target in cfg.analyst.metadata: if cfg.analyst.metadata[target].enable: occ_avg_wer cal_target_metadata_wer( manifestcfg.analyst.metric_calculator.output_filename, targettarget, meta_cfgcfg.analyst.metadata[target], eval_metriceval_metric, )主程序入口使用 Hydra 的hydra_runner(config_pathconf, config_nameeval.yaml)装饰器所有参数均从 eval.yaml 读取并可通过命令行覆盖。值得注意的工程细节包括可复现性若env.save_git_hash: True程序会通过git.Repo记录当前代码仓库的 commit hash 并写入报告asr_evaluator.py L44-L46确保评测结果可回溯到具体代码版本。引擎可跳过通过analyst.metric_calculator.exist_pred_manifest指定一份已生成的预测 manifest即可跳过推理阶段、只做指标分析避免重复推理成本README 与 asr_evaluator.py L49-L64 均有说明。推理阶段不算 WERENGINE 在调用底层推理脚本时显式传入calculate_werFalse将 WER 计算推迟到 ANALYST 阶段统一完成一是避免重复计算浪费推理成本二是让 ANALYST 拥有更灵活的前处理控制权见 utils.py L190 与 L249。Writer 输出最终结果总体指标 各元数据分组指标 引擎配置 指标计算器配置以 JSON 形式追加写入report.json可通过writer.report_filename改名每行一个 JSON 对象便于后续批量收集多次实验asr_evaluator.py L121-L129。三、配置文件详解eval.yaml 全参数解析conf/eval.yaml 是工具的配置中枢按env/engine/analyst/writer四个顶层命名空间组织。下面按区块完整展开并给出参数语义。3.1 env 与 writerenv: save_git_hash: True # 是否在报告中记录当前 git commit hash用于结果溯源 ... writer: report_filename: null # 报告文件名null 时默认写入当前目录 report.json3.2 engine推理参数engine: model_path: null # 本地 .nemo 模型路径与 pretrained_name 二选一 pretrained_name: null # NGC/HF 上的预训练模型名与 model_path 二选一 output_filename: null # 预测结果 manifest 输出路径null 时自动生成 random_seed: random_seed 42 # 随机种子YAML 锚点同时被增强器引用 inference: mode: offline # 可选 offline、chunked、offline_by_chunked chunk_len_in_secs: 1.6 # 分块推理的块长秒offline_by_chunked 模式默认 20 total_buffer_in_secs: 4 # 分块推理的缓冲总时长秒offline_by_chunked 模式默认 22 model_stride: 8 # 模型下采样倍数Citrinet/FastConformer 为 8Conformer 为 4 decoder_type: null # 仅混合 CTCRNNT 模型需要可选 ctc 或 rnnt test_ds: manifest_filepath: null # 评测数据 manifest必填 sample_rate: 16000 # 采样率 batch_size: 32 # 推理 batch size num_workers: 4 # 数据加载进程数 augmentor: # 实时数据增强 silence: # 静音增强 prob: 0.8 # 应用概率 min_start_silence_secs: 0 # 句首静音时长范围秒 max_start_silence_secs: 5 min_end_silence_secs: 0 # 句尾静音时长范围秒 max_end_silence_secs: 5 rng: *random_seed noise: # 噪声增强 manifest_path: null # 噪声数据 manifest用于鲁棒性评估 prob: 0.8 min_snr_db: 0 # 信噪比范围dB max_snr_db: 15 rng: *random_seed transcribe_params: # 额外透传给底层 transcribe_speech.py 的 TranscriptionConfig 覆盖项 # 注意不可包含 calculate_wer / model_path / pretrained_name / # dataset_manifest / output_filename / batch_size / num_workers / # random_seed / eval_config_yaml / decoder_type 这些字段 allow_partial_transcribe: False # 仅当音频过长且 manifest 含 offset 字段时设为 True几个关键参数需要结合源码深入理解inference.mode三种取值由 utils.py 的run_asr_inference分发L48-L81其决策逻辑为offline→ 调用run_offline_inferencechunked→ 强制要求同时提供total_buffer_in_secs和chunk_len_in_secs否则直接抛错L52-L58offline_by_chunked→ 若未提供缓冲与块长参数自动填入默认值total_buffer_in_secs22、chunk_len_in_secs20L61-L78。该模式的设计动机在源码注释中写得很清楚用 Conformer 转写长音频时可能遭遇 CUDA 显存不足OOM此时可用“分块方式模拟离线”规避 OOM即以 20 秒块长、22 秒缓冲来近似整段离线效果其他取值一律抛错L80-L81。inference.decoder_type的取值受严格校验utils.py L45-L46只能是None、ctc、rnnt或aed。它的真正作用在run_chunked_inference中体现——工具会根据模型名关键字自动推断脚本与解码器类型L107-L157模型名关键字推断的模型类使用的推理脚本decoder_type 约束含hybridEncDecHybridRNNTCTCModel分块 RNNT 脚本默认 rnnt可显式指定 ctc/rnnt含rnnt/transducerEncDecRNNTModel分块 RNNT 脚本只能为 null 或 rnnt含ctcEncDecCTCModel不支持分块评估直接抛错只能为 null 或 ctc含canaryEncDecMultiTaskModel分块 AED 脚本只能为 null 或 aed其他——抛错提示命名须包含上述关键字——从源码结构看utils.py L159-L181分块推理实际复用examples/asr/asr_chunked_inference/下的现成脚本rnnt/speech_to_text_buffered_infer_rnnt.py 与 aed/speech_to_text_aed_chunked_infer.py。CTC 模型当前不支持分块评估L178-L179 直接抛出ValueError这是一个需要记住的适用前提。3.3 analyst指标计算与分组评估analyst: metric_calculator: exist_pred_manifest: null # 指定已生成的预测 manifest 时跳过 ENGINE clean_groundtruth_text: True # 是否清洗参考文本小写、数字转单词等 langid: en # 文本清洗语言注意 NeMo 文本规范化Text Normalization效果更佳 output_filename: null # 带指标的结果 manifest 输出路径 use_cer: False # True 时改用字符错误率CER ignore_capitalization: False # 是否忽略大小写比较前统一小写 ignore_punctuation: False # 是否移除标点后再比较 punctuations: null # 指定要移除的标点串null 时使用默认集 # !#$%()*,-./:;?[\\]^_{|}~ strip_punc_space: False # 去除标点前的空格如 I do . - I do. metadata: # 分组评估对 manifest 中的元数据字段分组计算指标 duration: enable: True slot: [[0,2],[2,5],[5,10],[10,20],[20,100000]] save_wer_per_class: False gender: enable: False slot: [[female]] save_wer_per_class: True speaker: enable: True save_wer_per_class: False age: enable: False slot: null save_wer_per_class: False emotion: enable: True slot: [[happy,laugh],[neutral],[sad]] save_wer_per_class: Falsemetric_calculator.metric的选择虽然 eval.yaml 中未显式写出metric字段但 asr_evaluator.py 通过cfg.analyst.metric_calculator.get(metric, wer)L67支持两种指标族默认wer调用cal_write_wer输出 WER/CER、插入率、删除率、替换率其他取值如bleu、rouge调用cal_write_text_metric适用于非 ASR 错误率的文本指标评测场景。后者的可选指标由 eval_utils.py 中的TEXT_METRICS_MAPPINGL27-L30限定当前仅注册了bleuSacreBLEUScore与rougeROUGEScore两种 torchmetrics 实现。slot的两种语义README 与 eval.yaml 的注释明确说明 slot 接受List[List[str]]或List[List[float]]两种形态数值型 slot如 duration按“左闭右开”区间匹配例如 1.8 秒落入[0,2]组字符串型 slot如 emotion按集合成员匹配一个 slot 可以聚合多个类别例如[happy,laugh]把 happy 与 laugh 两条情感合成一组。save_wer_per_class的含义置为True时会对数据中出现的每一个类别分别计算指标即使该类别没有出现在任何 slot 中置为False时只输出 slot 汇总组的结果。README 举的例子很贴切如果数据里存在cry情感但 slot 中没有它save_wer_per_classTrue也会额外给出 cry 组的 WER。3.4 README 中的官方配置示例原样保留README 给出了一个可直接对照上述 YAML 的示例通过duration配置把音频按[[0,2],[2,5],[5,10],[10,20],[20,100000]]单位秒分为 5 个区间组分别计算 WER通过emotion配置把情感聚为[[happy,laugh],[neutral],[sad]]三个组若设置save_wer_per_classTrue则数据中出现过的所有情感类别含未进 slot 的cry都会单独输出 WERanalyst: metadata: duration: enable: True slot: [[0,2],[2,5],[5,10],[10,20],[20,100000]] save_wer_per_class: False # whether to save wer for each presented class. emotion: enable: True slot: [[happy,laugh],[neutral],[sad]] # we could have cry in data but not in slot we focus on. save_wer_per_class: False四、底层指标计算原理从编辑距离到细粒度错误率ANALYST 的指标计算核心在 eval_utils.py 的cal_write_werL158-L249其处理管线为逐行读取预测 manifest取参考文本gt_text_attr_name默认text与预测文本pred_text_attr_name默认pred_text按配置做文本前处理L199-L211clean_groundtruth_textTrue时调用clean_labelL94-L119转小写、替换非法字符、压缩空格并在langiden时把阿拉伯数字转为英文单词convert_num_to_wordsL122-L155。注意源码对非英语数字转写只给出警告并跳过README 明确建议其他语言使用 NeMo Text Normalization 获得更好的清洗效果ignore_punctuationTrue时对参考与预测同时调用remove_punctuations默认标点集为!#$%()*,-./:;?[\\]^_{|}~L82-L91strip_punc_spaceTrue时调用strip_spaces_before_punctuations把I do .规整为I do.L74-L79ignore_capitalizationTrue时统一转小写对每一条样本调用word_error_rate_detail来自 nemo/collections/asr/metrics/wer.py L75-L132该函数基于参考与假设之间的**编辑距离edit distance**分解出插入、删除、替换操作数并计算wer (ins del sub) / ref 词数 ins_rate ins / ref 词数 del_rate del / ref 词数 sub_rate sub / ref 词数use_cerTrue时按字符粒度list(h)/list(r)执行同样计算wer.py L108-L113。每条样本的wer/cer、tokens、ins_rate、del_rate、sub_rate会回写进该样本的 JSON 行eval_utils.py L216-L220这正是后续分组统计能够直接累加的基础。最后对全部假设/参考序列再算一次总体指标得到total_resL241-L248并输出带指标的新 manifest。cal_write_text_metricL252-L331则走另一条路径按metric从映射表实例化评分器BLEU 以metric_calculator([hyp], [[ref]])形式调用其他指标直接传两个字符串逐样本打分后写回sample[metric]最后对全集计算总分。五、分组统计实现cal_target_metadata_wer 深读utils.py 的cal_target_metadata_werL271-L402实现了 README 所述的分组评估。其算法可归纳为三步第一步按类别聚合L299-L322。遍历带指标 manifest 的每一行若样本含目标元数据字段target in sample则按该字段值如emotionhappy建立类别桶累加该桶的samples、tokens、errors tokens × 样本 WER、以及插入/删除/替换的错误数。第二步计算类别级指标L323-L343。对每个类别桶计算 WER/CER 与三个错误率若数据中不存在该元数据字段则记录日志metadata target does not present in manifest. Skipping!并返回None该分组在报告中不出现。第三步按 slot 聚合L345-L395。当配置了slot时数值型 slot按s[0] target_class s[1]左闭右开匹配slot 键格式为slot-0,2字符串型 slot判断target_class in s成员归属slot 键格式为slot-happy,laugh每个 slot 汇总其下所有类别桶的样本数与错误数再统一计算指标并弹出中间累加字段errors/inss/dels/subs。最终返回值取决于save_wer_per_classL397-L402为True时返回“全部类别 slot 组”的完整字典为False且配置了 slot 时只返回 slot 组结果。eval_metric参数目前仅支持wer与cer传入其他值会直接抛错L294-L297说明分组统计暂未覆盖 BLEU/ROUGE 这类文本指标。在 asr_evaluator.py 主流程中每个启用的 metadata 目标cfg.analyst.metadata[target].enable的分组结果会以report[target]键写入最终报告L100-L108因此 report.json 中每个元数据字段都会有自己的分组指标区块。六、运行方式与命令行参数6.1 官方标准运行命令README 给出的最小可运行命令如下从仓库根目录执行python tools/asr_evaluator/asr_evaluator.py \ engine.pretrained_namestt_en_conformer_transducer_large \ engine.inference.modeoffline \ engine.test_ds.augmentor.noise.manifest_pathmanifest file for noise data其中engine.pretrained_name指定预训练模型也可改用engine.model_path指向本地.nemo文件engine.inference.mode指定推理模式engine.test_ds.augmentor.noise.manifest_path指定噪声数据 manifest 以启用噪声增强鲁棒性评估。由于 Hydra 的覆盖机制eval.yaml 中的任何字段都可以像这样在命令行追加覆盖例如engine.test_ds.manifest_filepath...、analyst.metric_calculator.use_cerTrue等。6.2 必填项与常见错误根据 utils.py 的校验逻辑有几个容易踩的坑模型来源二选一model_path与pretrained_name必须且只能指定一个否则run_asr_inference抛出ValueError: Please specify either cfg.model_path or cfg.pretrained_name!L42-L43chunked 模式必须给缓冲参数不指定chunk_len_in_secs/total_buffer_in_secs会直接报错L52-L58模型命名须含关键字离线模式下模型名须能匹配hybrid/rnnt/transducer/ctc/canary之一否则分块路径无法选择脚本L150-L157CTC chunked 不支持CTC 模型走分块评估会直接抛错L178-L179。6.3 离线模式的底层调用链run_offline_inferenceutils.py L212-L268的实现是把 engine 配置保存为临时 YAML 文件构造命令行调用 examples/asr/transcribe_speech.pybase_cmd [ python, str(script_path), calculate_werFalse, fmodel_path{cfg.model_path}, fpretrained_name{cfg.pretrained_name}, fdataset_manifest{cfg.test_ds.manifest_filepath}, foutput_filename{cfg.output_filename}, fbatch_size{cfg.test_ds.batch_size}, fnum_workers{cfg.test_ds.num_workers}, frandom_seed{cfg.random_seed}, feval_config_yaml{f.name}, fdecoder_type{cfg.inference.decoder_type}, ]其中transcribe_params中用户自定义的覆盖项会通过get_hydra_override_from_configeval_utils.py L57-L71展平为keyvalue形式的 Hydra 覆盖参数追加到命令末尾且显式排除了calculate_wer、model_path、pretrained_name、dataset_manifest、output_filename、batch_size、num_workers、random_seed、eval_config_yaml、decoder_type这 10 个字段utils.py L230-L241——因为它们在 base_cmd 中已被显式传递重复会导致冲突。若需要更精细地调整解码策略如decoding.strategygreedy_batch、rnnt_decoding.strategy...源码注释给出两条途径utils.py L183-L185、L243-L245一是修改底层脚本如transcribe_speech.py、speech_to_text_buffered_infer_rnnt.py顶部的TranscriptionConfig二是把这些参数追加到命令行 Hydra 覆盖中。6.4 输出文件与报告解读运行结束后会生成两类产物带指标的预测 manifest默认命名规则为{model_name}-{dataset_name}-{mode}.json离线模式utils.py L213-L223或{model_name}-{dataset_name}-{mode}B{buffer}C{chunk}.json分块模式L93-L105每行 JSON 包含原始字段 pred_textwer/certokensins_ratedel_ratesub_ratereport.json追加写入每行一个 JSON结构大致为{ git_hash: commit hash, res: {samples: ..., tokens: ..., wer: 0.0..., ins_rate: ..., del_rate: ..., sub_rate: ...}, duration: {slot-0,2: {...}, slot-2,5: {...}, ...}, emotion: {slot-happy,laugh: {...}, slot-neutral: {...}, ...}, engine: {...}, analyst.metric_calculator: {...} }程序结束时还会在日志中打印整体指标Overall wer is xx.x %asr_evaluator.py L116-L119。由于是追加写入多次实验的 report.json 行可以很方便地用于横向对比与批量统计。七、扩展指南如何接入新任务README 明确说明如果你计划评估/新增 Punctuation and Capitalization标点与大小写等新任务请将其添加到 ENGINE 部分If you plan to evaluate/add new tasks such as Punctuation and Capitalization, add it to the engine。结合架构理解这一建议ENGINE 负责产出预测ANALYST 负责基于预测算指标。新任务若只是换一种文本指标如 BLEU只需在metric_calculator.metric中指定并依赖cal_write_text_metric的映射表但若要评估新的模型能力如标点恢复则需要在 utils.py 的run_asr_inference/run_offline_inference/run_chunked_inference中扩展对对应模型类型脚本的调用仿照现有 rnnt/aed 分支L107-L181让底层推理脚本输出包含预测结果字段的 manifest在 eval.yaml 的analyst.metric_calculator下配置新的字段名如pred_text_attr_name指向新的预测属性如需分组统计在analyst.metadata下新增元数据目标cal_target_metadata_wer会直接按 manifest 中的字段名通用地工作它只要求target in sample即可。从代码结构看cal_target_metadata_wer对元数据字段是通用的——只要 manifest 行里存在该字段就能分组计算因此新增age、speaker之类的分组无需改动代码只需在 YAML 中启用。八、总结与适用前提ASR Evaluator 是 NeMo 仓库中面向“深度评估”场景的专用工具其价值在于把三种推理模式、数据增强、细粒度错误分析与分组公平性分析整合进一条可复现的流水线。使用时的关键注意事项可归纳为评测数据须为 NeMo manifest 格式JSON 行含audio_filepath与text字段元数据字段duration/emotion/speaker 等可选存在时才会触发对应分组统计offline模式适用于任意 NeMo ASR 模型chunked模式仅支持 RNNT/AED含 hybrid 默认走 rnnt类模型CTC 模型不支持分块评估长音频 Conformer 组合遇到 OOM 时优先考虑offline_by_chunked默认 20s 块长 22s 缓冲噪声增强需要额外提供噪声数据 manifest并通过engine.test_ds.augmentor.noise.manifest_path传入文本清洗与指标口径大小写、标点、CER/WER、语言都会显著影响数字评测前应在analyst.metric_calculator中明确口径并保持实验间一致。对于希望进一步深挖的读者建议依次阅读 tools/asr_evaluator/asr_evaluator.py主流程、tools/asr_evaluator/utils.py推理分发与分组统计、nemo/collections/asr/parts/utils/eval_utils.py指标计算以及 nemo/collections/asr/metrics/wer.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),仅供参考
返回列表