尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

FunASR 关键词检测(KWS)实战指南:SANM 流式接口与 FSMN 离线示例详解

FunASR 关键词检测(KWS)实战指南:SANM 流式接口与 FSMN 离线示例详解 FunASR 关键词检测KWS实战指南SANM 流式接口与 FSMN 离线示例详解【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASRFunASR 开源语音工具包内置了面向关键词/唤醒词检测Keyword Spotting, KWS任务的模型与示例可在一句音频中判断是否出现预先配置的关键词适用于智能家居唤醒、命令词门控等场景。本篇指南以仓库内 docs/keyword_spotting.md 为核心结合 SANM 流式实现源码、FSMN 离线示例 与配套测试系统讲解 KWS 与 ASR/VAD 的边界、版本固定与模型快照准备、完整可运行的流式/文件检测脚本、结果语义与会话管理以及部署边界与调试建议。读完本文你将能基于 FunASR 用 SANM 在线检查点按包喂入音频并在句末获得检测结果也能独立评估 FSMN 离线 KWS 示例与各运行时契约是否适用于你的场景。一、任务边界KWS 不是转写、不是 VAD、也不是热词关键词检测的目标非常收敛在一句utterance音频中判断配置的关键词是否出现。它不输出通用转写文本不输出说话人身份也不输出关键词出现的时间戳。文档开篇特别强调了一个容易踩坑的事实当前 SANM 流式 Python 接口在整句音频结束时才返回结果不是每收到一个音频包就产生唤醒事件。也就是说喂包packet只是流式传输的输入方式最终判定在is_finalTrue的句末触发。这与逐包即时唤醒的交互模式有本质区别构建产品时不能按后者宣传。选择对应路径任务指南检测完整录音中的关键词FSMN KWS 示例按顺序输入音频包句末检测本文下方 SANM 示例连续转写一般语音流式 ASR SDK中文版见 python_api_zh.md定位语音活动流式 VAD中文版见 streaming_vad_zh.md三条边界必须牢记FSMN 与 SANM 的接口不通用FSMN 使用对应检查点自带的 tokenizer 和关键词词表不要套用流式 SANM 的缓存参数SANM 示例使用在线检查点和关键词小云小云。ASR 文本/热词不是 KWS 检测器ASR 的hotword参数用于偏置转写不承担检测语义VAD 只找语音边界不判断关键词是否出现。修改keywords只是配置解码候选不是为任意短语或语言训练新模型。必须使用检查点支持的 token阅读模型卡与许可证并用目标音频评测每个关键词。参数格式方面keywords必须是非空字符串多个关键词用英文逗号分隔而不是 Python 列表也不是 ASR 的hotword参数且检测结果不保证列出所有关键词的每次出现。离线 FSMN 示例使用的是iic/speech_charctc_kws_phone-xiaoyun不要自行改成不存在的fsmn-kws别名。其他架构请查阅 Model Zoo中文版 readme_zh.md和对应训练示例。二、版本固定与模型快照准备为什么必须固定源码版本此示例依赖 #3655中文版 installation_zh.md后在隔离环境中安装已测试的确切源码 commitpython -m pip uninstall -y funasr python -m pip install funasr githttps://github.com/modelscope/FunASR.git403555289a6d4f79f5c4a48e5beb00f521c5e172为什么必须先卸载因为 Git 地址安装会得到与已装包相同的版本号1.4.14只指定 Git 地址或加--upgrade可能让旧包残留。tests/test_kws_docs.py中的test_pinned_install_replaces_an_existing_same_version正是对这两条命令逐字校验的契约测试。请务必在隔离环境执行不要直接修改共享生产工作进程的环境。固定版本后还需注意源码安装仍可能显示包版本1.4.14因此必须同时记录Git commit与实际导入的模块路径仅当后续发布明确包含这两项修复时才能用对应 wheel 替代。本指南不代表已发布新的 PyPI 包。准备不可变的模型快照需要准备iic/speech_sanm_kws_phone-xiaoyun-commands-online的完整本地快照包括配置、tokenizer、前端/CMVN 文件与权重。建议记录解析后的 revision 或文件校验清单checksum manifest——可变的master标签不等于不可变 revision。示例内部不下载模型模型目录必须完整存在于本地。音频输入要求非空、单声道mono、16 kHz 的 WAV外部数组应使用归一化的一维float32波形而不是整数 PCM先对完整信号统一采样率再切包逐包独立重采样不在连续性保证范围内。三、运行文件或顺序音频包完整可运行脚本程序接收model_dir、audio两个位置参数和可选的--mode file默认模式为stream。流式模式先读取完整 WAV再模拟每包 960 个采样点16 kHz 下即 60 ms它不是麦克风采集程序整段文件仍保留在内存中。detect_stream是应用侧辅助函数不是新的 SDK 方法。import argparse from pathlib import Path import soundfile as sf from funasr import AutoModel def detect_stream(model, speech, sample_rate, packet_samples960): if packet_samples 0 or len(speech) 0: raise ValueError(Audio length and packet size must be positive) cache {} final_results [] for start in range(0, len(speech), packet_samples): end min(start packet_samples, len(speech)) final_results model.generate( inputspeech[start:end], fssample_rate, cachecache, chunk_size[4, 8, 4], batch_size1, is_finalend len(speech), ) return final_results parser argparse.ArgumentParser() parser.add_argument(model_dir) parser.add_argument(audio) parser.add_argument(--mode, choices[file, stream], defaultstream) args parser.parse_args() model_dir Path(args.model_dir).expanduser().resolve(strictTrue) if not model_dir.is_dir(): raise ValueError(Expected a complete local SANM KWS model directory) speech, sample_rate sf.read(args.audio, dtypefloat32) if sample_rate ! 16000 or speech.ndim ! 1 or len(speech) 0: raise ValueError(Expected nonempty mono 16 kHz audio) model AutoModel( modelstr(model_dir), keywords小云小云, devicecpu, ncpu1, chunk_size[4, 8, 4], encoder_chunk_look_back0, decoder_chunk_look_back0, disable_updateTrue, trust_remote_codeFalse, ) if args.mode file: results model.generate( inputargs.audio, fssample_rate, cache{}, chunk_size[4, 8, 4], batch_size1, is_finalTrue, ) else: results detect_stream(model, speech, sample_rate) for item in results: print(item[text])运行方式流式模式为默认也可显式指定--mode file走完整文件推理python kws_example.py /path/to/speech_sanm_kws_phone-xiaoyun-commands-online positive.wav python kws_example.py /path/to/speech_sanm_kws_phone-xiaoyun-commands-online positive.wav --mode file关键参数说明AutoModel(modelstr(model_dir), ...)传入本地完整模型目录不触发示例内下载keywords小云小云解码候选关键词逗号分隔多关键词chunk_size[4, 8, 4]左/当前/右三个方向的前端特征帧数见下文语义encoder_chunk_look_back0、decoder_chunk_look_back0流式编码器/解码器回看帧数disable_updateTrue禁用模型自动更新检查trust_remote_codeFalse不执行远程代码安全默认batch_size1KWS 会话要求 batch 为 1。tests/test_kws_docs.py用录制调用recording的 SDK 替身执行了上述完整示例入口不加载真实权重并断言了分包大小[960, 1]、is_final序列[False,...,True]、全程共享同一个cache字典、构造参数keywords 小云小云、device cpu、trust_remote_code is False、output_dir未传入等契约非空单声道 16 kHz 之外的非法音频会触发ValueError。这些测试可以看作本示例对外 API 行为的可执行规范。四、结果语义与会话管理读懂返回结果非末包调用公开的AutoModel.generate返回[]含义是尚无最终结果不是关键词被拒绝。最终结果包含key和text两个字段text形如detected keyword score或rejected。score是解码器给出的命中分数不是校准后的概率也不是通用操作阈值结果中不包含关键词时间区间或说话人身份。若整句音频都没有有效特征帧最终结果也可能为[]——没有结果不等于检测拒绝。空的 EOS结尾调用仍会解码此前音频包已累计的输出。上述输出拼接逻辑在 sanm_kws_streaming/model.py 的generate_chunk末包分支中可以直接看到detected keyword score或rejected的字符串即在此构造并可选写入output_dir下的结果文件。chunk_size 的真实含义chunk_size[4, 8, 4]指定的是前端特征帧数左/当前/右不是毫秒也不是调用者的音频包长度。示例中的 960 个采样点在 16 kHz 下等于 60 ms——这是输入包时长不是实测唤醒延迟。会话内必须固定模型、关键词、分块设置与采样率。源码层面sanm_kws_streaming/model.py 会对chunk_size做合法性校验必须形如[left 0, middle 0, right 0]的三元组。缓存与会话纪律同一句音频的有序调用共用同一个字典使用batch_size1新录音或取消会话后创建新缓存。独立缓存不代表同一个AutoModel可以线程安全地并发调用应串行调用或隔离模型工作进程。本例最后一个非空包携带is_finalTrue整包倍数长度也一样。固定版本的 SANM 修复也支持先输入非末包音频再用一次空数组末包刷新状态。不要重发已消费音频不要在终结后追加第二次 EOS也不要将此行为推广到其他模型。文件/URL 输入按完整一句自动终结不能重复传文件路径来模拟连续音频包。终结会原地重置模型缓存字段不保证字典变空应用侧仍应在会话边界丢弃状态。编码输出会一直积累到 EOS因此必须明确限制句长不能无限保持常开会话。用 VAD 或超时划分句子属于应用策略会改变检测器实际接收到的音频。tests/test_kws_streaming_continuity.py是对这些会话契约的强验证它用打标前端MarkerFrontend和身份分块编码器在不加载权重的前提下验证了完整文件、完整数组、各种分包如[1, 959, 3001, 7000]、空 EOS 冲刷下最终编码帧逐帧一致同时覆盖了空音频/过短音频不伪造检测、二次句子干净开局、文件输入即使is_finalFalse也自动终结、真实前端WavFrontendOnline下分包与整句特征一致、非对称/零重叠 chunk如[0, 8, 0]等场景。关于 output_dir现在省略output_dir会直接返回结果不创建结果写入器。如需输出文件显式配置可写的output_dir结果文件是可选项多次调用可能追加写入它不是推理的前提也不是唤醒事件分发系统。tests/test_kws_optional_output.py 验证了output_dir缺省/为None时不创建 writer、开启时结果与文件格式detect文件形如sample detected wake 0.9保持、关闭后不复用缓存 writer、连续开启调用会追加等四种行为且同时覆盖FsmnKWS、FsmnKWSMT、SanmKWS、SanmKWSStreaming四个模型类。五、底层原理KwsCtcPrefixDecoder 如何判定关键词SANM/FSMN KWS 的判定不是转写整句再匹配而是针对候选关键词 token 集合做受限的 CTC 前缀束搜索实现在 funasr/utils/kws_utils.py 的KwsCtcPrefixDecoder中。其流程大致为关键词 token 化__init__中把keywords字符串按英文逗号拆分经query_token_set将每个关键词映射为 token 序列支持符号表直接命中、词表/lexicon 展开、未知 token 回退并构造keywords_idxset默认含 blank即 token id0。受限束搜索beam_search逐帧取 CTC 概率的 top-k只保留落在keywords_idxset内且概率大于阈值源码中为0.05的 token做标准 CTC 前缀束搜索score_beam_size3、path_beam_size20为默认值。子序列匹配_decode_inside对束内最优假设用is_sublist检查关键词 token 序列是否作为子序列出现命中则把各 token 帧概率连乘并开方作为hit_score返回(True, keyword, score)否则返回(False, None, None)。这解释了为什么keywords只是配置解码候选模型权重固定解码器只在候选 token 集合内搜索能否命中取决于该检查点的 CTC 输出是否支持相应 token。这也是文档强调分数不是校准概率、需自行评测每个关键词的源码依据。六、FSMN 离线 KWS 示例速览对于检测完整录音中的关键词这一任务文档指向 examples/industrial_data_pretraining/fsmn_kws。该目录提供两条推理路径方式一Python APIdemo.pyfrom funasr import AutoModel model AutoModel( modeliic/speech_charctc_kws_phone-xiaoyun, keywords小云小云, output_dir./outputs/debug, devicecpu ) test_wav https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/KWS/pos_testset/kws_xiaoyunxiaoyun.wav res model.generate(inputtest_wav, cache{},) print(res)方式二命令行infer.shmodeliic/speech_charctc_kws_phone-xiaoyun inputhttps://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/KWS/pos_testset/kws_xiaoyunxiaoyun.wav keywords(小云小云) keywords_string$(IFS,; echo ${keywords[*]}) python funasr/bin/inference.py \ model${model} \ input${input} \ output_dir./outputs/debug \ devicecpu \ keywords\$keywords_string\注意两点一是模型名为iic/speech_charctc_kws_phone-xiaoyun不要用不存在的fsmn-kws别名二是多关键词仍以英文逗号拼接的字符串传入。模型实现类为FsmnKWS见 funasr/models/fsmn_kws/model.py其推理路径与 SANM 共用KwsCtcPrefixDecoder但编码器不同FSMN 结构且不涉及流式 SANM 的 cache/chunk 参数——两条路径不要混用。七、验证证据与部署边界连续性回归验证的范围源码修复已在 CPU 上使用官方检查点、一条官方正样本与合成静音验证。在单线程、前端dither0的条件下完整文件、完整数组、960 点分包、不规则分包加空 EOS 的正样本最终编码帧一致修复前后均检出关键词静音均被拒绝。需要明确这是连续性回归验证不是准确率提升的证明不是自然负样本误唤醒率false-accept评测不是麦克风或 GPU 验证逐位一致性比较需要使用验证记录中相同的确定性设置示例默认保留检查点前端配置。部署边界示例 ≠ 各运行时已支持 KWS此 Python 示例不能证明以下运行时已支持 KWS转写 HTTP 服务OpenAI 兼容服务、原生 vLLM、llama.cpp、C WebSocket 协议。构建服务前请查阅独立的 部署矩阵中文版 deployment_matrix_zh.md和对应运行时的模型契约。两条红线不要把 KWS 结果字符串当作 OpenAI 转写文本路由不要宣传实现尚未输出的即时唤醒事件。报告问题的清单报告 bug 时保留原始音频、模型文件清单manifest、源码 commit、分包长度与顺序、末包标志is_final与结果字符串。宣称部署准确率前应包含自然负样本与误唤醒/漏检的评测方法。不要公开密钥或私人音频。八、源码契约与延伸阅读关注点仓库位置SANM 流式 KWS 实现SanmKWSStreaming含inference/generate_chunk/init_cache/_consume_streaming_featuresfunasr/models/sanm_kws_streaming/model.pySANM 离线基类SanmKWSfunasr/models/sanm_kws/model.pyFSMN KWS 实现FsmnKWS/FsmnKWSConvertfunasr/models/fsmn_kws/model.pyCTC 前缀解码器KwsCtcPrefixDecoder与关键词 token 化funasr/utils/kws_utils.py可选输出契约测试output_dir 行为tests/test_kws_optional_output.py流式连续性契约测试无权重tests/test_kws_streaming_continuity.py指南可运行性测试执行示例入口tests/test_kws_docs.pyFSMN 离线示例demo.py / infer.sh / finetune.sh / convert.shexamples/industrial_data_pretraining/fsmn_kws相关任务流式 ASR / 流式 VAD / 部署矩阵python_api.md、streaming_vad.md、deployment_matrix.md小结用 SANM 流式接口做 KWS 时请遵循固定源码版本 → 准备完整模型快照 → 按序喂包 → 句末取结果 → 会话边界重置缓存的完整流程用 FSMN 离线示例时注意其独立的模型名、tokenizer 与调用方式。两者共用keywords字符串参数与KwsCtcPrefixDecoder判定逻辑但接口、缓存与适用任务并不互通。评测任何关键词前务必用包含自然负样本的目标音频做误唤醒/漏检评估并以各运行时模型契约为准确认部署形态。【免费下载链接】FunASROpen-source speech recognition toolkit for training, inference, streaming ASR, VAD, punctuation, speaker diarization pipelines, and OpenAI-compatible/MCP serving.项目地址: https://gitcode.com/GitHub_Trending/fun/FunASR创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表