简介
语音唤醒在学术上被称为keyword spotting(简称KWS),给它做了一个定义:在连续语流中实时检测出说话人特定片段。
这里要注意,检测的“实时性”是一个关键点,语音唤醒的目的就是将设备从休眠状态激活至运行状态,所以唤醒词说出之后,能立刻被检测出来,用户的体验才会更好。
那么,该怎样评价语音唤醒的效果呢?通行的指标有四个方面,即唤醒率、误唤醒、响应时间和功耗水平:
➤唤醒率,指用户交互的成功率,专业术语为召回率,即recall。
➤误唤醒,用户未进行交互而设备被唤醒的概率,一般按天计算,如最多一天一次。
➤响应时间,指从用户说完唤醒词后,到设备给出反馈的时间差。
➤功耗水平,即唤醒系统的耗电情况。很多智能设备是通过电池供电,需要满足长时续航,对功耗水平就比较在意。
技术路线
经过长时间的发展,语音唤醒的技术路线大致可归纳为三代,特点如下:
第一代:基于模板匹配的KWS
训练和测试的步骤比较简单,训练就是依据注册语音或者说模板语音进行特征提取,构建模板。测试时,通过特征提取生成特征序列,计算测试的特征序列和模板序列的距离,基于此判断是否唤醒。

第二代:基于HMM-GMM的KWS
将唤醒任务转换为两类的识别任务,识别结果为keyword和non-keyword。

第三代:基于神经网络的方案
神经网络方案又可细分为几类,第一类是基于HMM的KWS,同第二代唤醒方案不同之处在于,声学模型建模从GMM转换为神经网络模型。 第二类融入神经网络的模板匹配,采用神经网络作为特征提取器。第三类是基于端到端的方案,输入语音,输出为各唤醒的概率,一个模型解决。

唤醒的难点
语音唤醒的难点,主要是低功耗要求和高效果需求之间的矛盾。
一方面,目前很多智能设备采用的都是低端芯片,同时采用电池供电,这就要求唤醒所消耗的能源要尽可能的少。
另一方面,用户对体验效果的追求越来越高。目前语音唤醒主要应用于C端,用户群体广泛,且要进行大量远场交互,对唤醒能力提出了很高要求。
要解决两者之间的矛盾,对于低功耗需求,我们采用模型深度压缩策略,减少模型大小并保证效果下降幅度可控;而对于高效果需求,一般是通过模型闭环优化来实现。先提供一个效果可用的启动模型,随着用户的使用,进行闭环迭代更新,整个过程完成自动化,无需人工参与。
典型应用
语音唤醒的应用领域十分广泛,主要是C端产品,比如机器人、音箱、汽车等。比较有代表性的应用模式有如下几种:
➤传统语音交互:先唤醒设备,等设备反馈后(提示音或亮灯),用户认为设备被唤醒了,再发出语音控制命令,缺点在于交互时间长。
➤One-shot:直接将唤醒词和工作命令一同说出,如“叮咚叮咚,我想听周杰伦的歌”,客户端会在唤醒后直接启动识别以及语义理解等服务,缩短交互时间。
➤Zero-shot:将常用用户指定设置为唤醒词,达到用户无感知唤醒,例如直接对车机说“导航到科大讯飞”,这里将一些高频前缀的说法设置成唤醒词。
开源方案
方案 | 说明 | 备注 | 官网 |
---|---|---|---|
vosk | Vosk 在 Kaldi 的基础上进行了封装和改进。它提供了更简单的 API,降低了开发门槛,让开发者能更方便地将语音识别功能集成到自己的应用程序中。 | 通过设置grammar来配置固定的识别词实现唤醒功能或固定词检测 | 教程 |
PocketSphinx | 是 CMU Sphinx 项目的一部分,是一个离线的语音识别和唤醒库,支持多种语言。它可以在资源有限的设备上运行,并且具有一定的自定义能力。 | 通过自带的关键词检测方法addKeyphraseSearch实现 | Android教程 |
Sherpa-onnx | 基于微软开发的 ONNX 运行时的开源语音处理库,除了语音识别、语音合成等功能外也提供了自定义关键词识别。提供了两个模型分别支持英文和中文的功能。 | 可以指定任何关键字,无需重新训练模型 | 教程 |
Snowboy | 轻量级、高度可定制的热词检测引擎,由 KITT.AI 团队开发,主要用于在资源受限的设备上实现语音唤醒功能。Snowboy 提供了一个在线工具,能帮助你训练自定义的唤醒词模型。你只需访问 Snowboy 官网,按照指引录制包含唤醒词的语音样本,系统就会自动训练出对应的模型文件(.pmdl 或 .umdl)。 | 已不在维护(被百度收购)商用收费需要联系snowboy@kitt.ai | snowboy模型训练 |
Porcupine | 是一款高性能、低开销的端到端唤醒词引擎。 | 超过免费额度收费 | |
wekws | 采用端到端的深度学习模型,高效、低延迟的实时语音唤醒服务。不同的唤醒词需要自行训练导出模型。 | 官网 |
Vosk介绍
Vosk 继承了 Kaldi 的语音识别能力,并在此基础上进行了优化和改进,使其更适合在各种设备上实时运行。Vosk 对 Kaldi 的部分功能进行了封装,提供了更简单易用的 API,降低了开发门槛,让开发者可以更轻松地将语音识别功能集成到自己的应用程序中。
接口说明
SetMaxAlternatives
SetMaxAlternatives(int maxAlternatives)方法用于设置语音识别结果中返回的最大替代句子数量。这个设置允许你获取到不仅仅是最可能的识别结果,还可以得到其他可能的替代结果。例如,如果你设置maxAlternatives为3,那么识别器将尝试返回最多三个识别结果,按可能性排序。
setWords
启用 / 禁用单词级别的详细信息。当设置为
true
时,识别结果将包含每个单词的时间戳和置信度。- 时间戳分析:了解每个单词在音频中的出现位置(用于语音对齐或字幕生成)。
- 置信度过滤:丢弃低置信度的单词,提高整体准确率。
setSpeakerModel
方法允许你设置一个说话人识别模型。这使得Vosk不仅能够识别说话的内容,还能识别是谁在说话。这对于需要区分不同说话人或执行说话人验证的应用非常有用。Speaker Model是一个专门的模型,需要与语音识别模型一起使用。
setGrammar
允许你定义一个语法列表,识别器将只识别列表中的词或短语。这对于创建有限词汇或命令控制的应用非常有用,因为它可以大大提高特定词汇的识别准确率并减少错误识别。
PocketSphinx介绍
接口说明
processRaw(short[] SDATA, long NSAMP, boolean no_search, boolean full_utt)
- byte[] buffer
- 含义:包含原始音频数据的字节数组。
- 要求:
- 音频格式必须与解码器配置一致(默认 16kHz、16 位、单声道、小端序)。
- 通常来自麦克风输入或音频文件读取。
- int length
- 含义:要处理的字节数(从
offset
开始)。 - 注意:
- 需确保
offset + length ≤ buffer.length
。 - 建议长度为 10ms 音频的整数倍(16kHz 下为 320 字节)。
- 需确保
- boolean no_search
- 含义:是否仅提取声学特征,不进行语言模型搜索。
- 适用场景:
true
:用于预提取特征(如保存特征用于后续离线处理)。false
:正常识别流程,提取特征并进行语音搜索。
- boolean full_utt
- 含义:是否将当前数据视为完整的语音 utterance。
- 行为:
true
:处理完当前数据后立即结束 utterance,触发识别结果回调。false
:继续累积数据,等待后续调用(适用于流式识别)。
setKeywordThreshold(float threshold)
关键词阈值,控制着关键词搜索(Keyphrase Search)的敏感度。决定关键词被触发的难度。值越小,系统越敏感,更容易触发;值越大,系统越严格,需要更清晰的发音才能触发。
该值是声学模型得分的对数概率阈值(log-probability),单位为 1e-10。
理论范围:1e-100
到 1e-1
(即 10^(-100)
到 10^(-1)
)。
实际有效范围:通常在 1e-50
到 1e-5
之间,具体取决于:
- 关键词长度:较长的关键词需要更小的阈值(如
1e-40
)。 - 环境噪声:嘈杂环境需要更大的阈值(如
1e-10
)。 - 发音清晰度:模糊发音需要更小的阈值。
addGrammarSearch
、addNgramSearch
和 addAllphoneSearch
是三种不同的搜索模式,适用于不同的语音识别场景。以下是它们的核心区别和适用场景:
1. addGrammarSearch(语法搜索)
特点
- 基于有限状态语法(FSG):使用预定义的语法规则限制可能的词汇组合,适合严格结构化的命令。
- 轻量级:识别速度快,资源消耗少,适合嵌入式设备或低功耗场景。
- 高准确率:由于限制了搜索空间,对语法内的命令识别准确率高。
适用场景
- 固定命令集:如智能家居控制("打开灯光"、"关闭电视")。
- 数字拨号:如电话号码、航班号。
- 表单填写:如日期、姓名输入。
示例代码
// 添加语法搜索(需先创建gram文件)
decoder.addGrammarSearch("commands", "/path/to/grammar.gram");
decoder.setSearch("commands");
语法文件示例(JSGF)
#JSGF V1.0;
grammar commands;
public <command> = (turn on | turn off) (the light | the fan | the TV);
2. addNgramSearch(N 元语法搜索)
特点
- 基于统计语言模型:使用大规模文本训练的 N-gram 模型,预测单词序列的概率。
- 灵活性高:支持更自然、开放的语言表达,但需要更大的模型文件。
- 资源消耗大:模型文件通常较大(数十 MB 到 GB 级别),计算复杂度高。
适用场景
- 自由对话:如语音助手、听写应用。
- 长文本识别:如会议记录、语音笔记。
- 领域特定语言:如医疗术语、法律条文。
示例代码
// 添加N-gram搜索
decoder.addNgramSearch("dictation", "/path/to/lm.bin");
decoder.setSearch("dictation");
3. addAllphoneSearch(全音素搜索)
特点
- 基于音素级别识别:直接识别语音中的基本音素(phonemes),而非完整单词。
- 无词典依赖:适用于未知词汇或需要细粒度语音分析的场景。
- 低层级输出:输出音素序列,需要额外处理才能转换为语义。
适用场景
- 语音合成(TTS):生成自然语音。
- 语音学研究:分析发音特征。
- 语音密码验证:基于发音特征而非单词内容。
示例代码
// 添加全音素搜索
decoder.addAllphoneSearch("phones", "/path/to/phone.lm");
decoder.setSearch("phones");
输出示例
识别结果(音素序列):[h ə l oʊ] → 对应单词 "hello"
- 对比表格
特性 | addGrammarSearch | addNgramSearch | addAllphoneSearch |
---|---|---|---|
搜索单位 | 单词(基于语法规则) | 单词(基于统计模型) | 音素(语音基本单位) |
模型大小 | 小(几十 KB) | 大(几十 MB 到 GB) | 中等(取决于音素数量) |
准确率 | 高(语法内) | 中等到高(取决于语料) | 低(需后续处理) |
响应速度 | 快 | 慢 | 中等 |
适用场景 | 固定命令、数字输入 | 自由对话、长文本 | 语音合成、语音学研究 |
典型文件格式 | JSGF、FSG | ARPA、BIN | Phone LM |
- 性能优化建议
- 优先使用语法搜索:对于已知命令集,使用
addGrammarSearch
可显著降低资源消耗。 - 限制 N-gram 模型大小:使用
cmuclmtk
工具修剪模型(如sphinx_lm_convert -i large.lm -o small.lm -prune 0.000001
)。 - 避免不必要的音素搜索:仅在需要细粒度语音分析时使用
addAllphoneSearch
。
根据具体应用场景选择合适的搜索模式,可在准确率和性能之间取得最佳平衡。
Sherpa-Onnx介绍
KeywordSpotterConfig参数说明
- maxActivePaths
- 功能:这个参数用于控制解码器在解码过程中所保留的最大活跃路径数量。在束搜索解码时,解码器会探索多种可能的路径,而
maxActivePaths
限制了同时保留的路径数目。 - 作用:
- 性能优化:通过限制活跃路径数量,能减少内存使用和计算量,提升解码速度。
- 避免过拟合:防止解码器在搜索过程中陷入过多不必要的路径,从而避免过拟合。
- 取值建议:若取值过小,可能会遗漏一些潜在的正确路径,降低关键词检测的准确率;若取值过大,则会增加计算资源的消耗。
- keywordsScore
- 功能:该参数为每个关键词预先设定了一个得分。在关键词检测时,模型会为每个检测到的关键词给出一个得分,而
keywordsScore
可作为一个基础得分或者权重,对最终的关键词得分产生影响。可以把它理解为对每个关键词重要性或者先验概率的一种量化表示。 - 作用:
- 调整关键词优先级:针对不同的关键词,可设置不同的
keywordsScore
,以此调整它们在检测结果中的优先级。 - 优化检测策略:在某些场景下,能够通过调整
keywordsScore
来优化关键词检测的策略。
- 调整关键词优先级:针对不同的关键词,可设置不同的
- 取值建议:取值范围通常为实数,可根据关键词的重要性和实际需求进行调整。例如,对于重要的关键词,可以设置较高的
keywordsScore
。
- keywordsThreshold
- 功能:此参数定义了关键词检测的得分阈值。只有当关键词的得分超过
keywordsThreshold
时,才会被判定为检测到该关键词。 - 作用:
- 控制误检率:通过提高阈值,可以减少误检的情况,但可能会增加漏检的概率;降低阈值则相反。
- 平衡检测性能:需要在误检率和漏检率之间找到一个平衡点,以达到最佳的检测性能。
- 取值建议:取值范围通常为实数,具体取值要根据模型的输出特性和实际应用场景来确定。可以通过实验不同的阈值,观察检测结果的误检率和漏检率,进而选择合适的阈值。
- numTrailingBlanks
- 功能:该参数规定了在检测到关键词后,需要连续出现多少个空白帧(即无关键词的帧),才认为关键词检测结束。
- 作用:
- 消除尾音干扰:避免因音频中的尾音或者噪声被误判为关键词的一部分。
- 准确界定关键词边界:有助于更精确地确定关键词的起始和结束位置。
- 取值建议:取值为正整数,具体数值需要根据音频的特性和实际应用场景来调整。如果音频中尾音较长或者噪声较多,可以适当增大
numTrailingBlanks
的值。
Snowboy介绍
SetSensitivity
- 含义:该方法用于设置唤醒词检测的灵敏度。灵敏度是一个衡量唤醒词检测难易程度的指标,其取值范围通常在 0 到 1 之间(不同版本可能会有细微差异),数值越大表示检测越灵敏,即更容易触发唤醒;数值越小则表示检测越不灵敏,需要更清晰、更准确的唤醒词发音才能触发。
- 作用:通过调整灵敏度,可以在不同的环境和使用场景下优化唤醒词检测的效果。在安静的环境中,可以适当降低灵敏度以减少误触发;而在嘈杂的环境中,可以提高灵敏度以确保能够及时检测到唤醒词。
SetAudioGain
- 含义:
SetAudioGain
方法用于设置音频增益。音频增益是对输入音频信号的放大倍数,通过调整增益可以增强或减弱输入音频的音量。其取值通常是一个大于 0 的浮点数,值大于 1 表示放大音频信号,值小于 1 表示缩小音频信号。 - 作用:在某些情况下,输入音频的音量可能过低或过高,导致唤醒词检测不准确。通过设置音频增益,可以调整输入音频的音量到一个合适的水平,从而提高唤醒词检测的性能。
ApplyFrontend
- 含义:
ApplyFrontend
方法用于启用或禁用前端音频处理功能。前端音频处理是一系列对输入音频进行预处理的操作,例如降噪、回声消除等,目的是提高音频的质量,从而提升唤醒词检测的准确性。该方法接受一个布尔值作为参数,True
表示启用前端音频处理,False
表示禁用。 - 作用:在嘈杂的环境中,启用前端音频处理可以有效地去除背景噪声和回声,使唤醒词更加清晰可辨,从而提高检测的准确性。但在某些情况下,前端音频处理可能会引入一些额外的延迟或失真,因此需要根据实际情况选择是否启用。
结论
通过综合比较vosk和PocketSphinx在唤醒效果、性能和开源能力方便比较适合。其他方案或者是收费、或者已经不在维护,或者效果不是很理想。