大家遇到语音识别中的关键词识别/唤醒词识别是怎么处理的呢?

0 阅读7分钟

大家遇到语音识别中的关键词识别/唤醒词识别是怎么处理的呢?

前言

最近接到一个开发需求:给我们的安卓 APP 加一个离线语音唤醒功能。要求很明确:纯离线可用、不需要授权、性能好、误触发率不能太高。

本以为这是个很简单的需求,毕竟现在 AI 这么发达,一个小小的唤醒词能有多难?结果没想到,我整整踩了两个星期的坑,试遍了市面上几乎所有的方案,最后才终于找到了一个完美的解决方案。

今天把这个过程分享出来,希望能帮到同样有这个需求的同学。

一、我试过的那些坑

1. 大厂云服务方案

第一个想到的就是阿里云、腾讯云、百度这些大厂的语音服务。

优点:识别准确率高,生态完善。

缺点:

  • 必须联网:我们的核心需求就是离线使用,很多场景下用户没有网络
  • 收费贵:按调用次数收费,量大了成本很高
  • 隐私问题:用户的语音数据要上传到云端,有隐私风险
  • 不灵活:自定义关键词需要额外付费,而且限制很多

直接 pass。

2. 大厂离线 SDK 方案

然后试了百度、讯飞的离线语音唤醒 SDK。

优点:识别准确率高,集成相对简单。

缺点:

  • 需要授权:商业使用需要购买授权,年费动辄几万到几十万
  • 体积大:一个 SDK 就要几十 MB,大大增加了 APP 的安装包大小
  • 不透明:黑盒运行,出了问题根本不知道怎么调试
  • 限制多:对使用场景和设备有很多限制

也 pass。

3. 通用开源语音识别方案

然后试了 Whisper、Kaldi 这些通用的语音识别模型。

优点:功能强大,完全开源,支持自定义关键词。

缺点:

  • 模型太大:最小的 Whisper tiny 也有 70 多 MB,安卓上跑起来非常卡
  • 功耗太高:CPU 占用率很高,手机发热严重,续航直接减半
  • 延迟大:识别一次需要几百毫秒,体验很差
  • 误触发率高:本来是做连续语音识别的,用来做唤醒词完全不合适

也 pass。

4. 专门的开源唤醒词方案

然后试了几个专门做唤醒词的开源项目:

  • Porcupine:效果最好,但商业使用收费,而且很贵
  • Snowboy:已经停止维护了,中文效果很差
  • SpeechBrain:太复杂,学习成本高,而且模型也不小

就在我快要放弃的时候,我发现了OpenWakeWord

二、OpenWakeWord:一个被低估的神器

OpenWakeWord 是一个专门为端侧设备设计的轻量级唤醒词引擎。

它的优点简直就是为我们的需求量身定做的:

  • 模型极小:生成的模型不到 1MB
  • 性能极高:安卓上 CPU 占用率不到 5%,几乎不耗电
  • 纯离线:所有推理都在本地完成,不需要联网,完全保护用户隐私
  • 跨平台:支持安卓、前端、Python、Windows、Linux、macOS
  • MIT 许可证:完全免费,商业使用也没有任何限制

我当时简直欣喜若狂,以为终于找到了解决方案。结果没想到,更大的坑还在后面。

三、最大的痛点:误触发率

OpenWakeWord 什么都好,就是有一个致命的问题:中文误触发率高得离谱

我用默认的方法训练了一个 "小燕子" 的模型,结果一天能误触发二三十次。有人在旁边聊天会触发,电视声音会触发,甚至有时候手机外放的声音都会触发。

我查了很多资料,试了各种方法:

  • 下载了上万条杂音、环境音、日常对话作为负样本
  • 调整置信度阈值,从 0.5 调到 0.9
  • 增加平滑窗口和最小触发帧数

结果都没用。很多时候,模型会把完全不相关的声音判定为关键词,而且输出 100% 的置信度。

后来我才发现,问题出在 OpenWakeWord 的模型本身:它是在英文数据集上训练的,根本分不清中文的声母和韵母。而且它的训练方式会导致模型严重过自信,输出的置信度完全不可信。

四、我的解决方案:动态相对置信度算法

既然调阈值没用,那我就换个思路:不看绝对置信度,看相对置信度

我发现,对于真正的关键词,模型的输出会呈现一个明显的峰值:关键词得分会突然从 0 升到 0.9 以上,然后再降下来。而误触发通常是平稳的高值,没有明显的峰值。

基于这个观察,我设计了一个动态相对置信度算法:

  1. 计算关键词得分的指数移动平均值(EMA),作为背景基线
  2. 当某一帧的得分超过背景基线的 3 倍时,才视为候选
  3. 再结合同一帧的关键词得分和非关键词得分的差值,做最终判断

python

运行

# 核心代码片段
background_ema = 0.0
alpha = 0.02  # 平滑系数

def detect(frame_output):
    global background_ema
    non_keyword_score, keyword_score = frame_output
    
    # 更新背景基线
    background_ema = alpha * keyword_score + (1 - alpha) * background_ema
    
    # 动态相对置信度判断
    if (keyword_score > 0.6 and 
        keyword_score - non_keyword_score > 0.5 and 
        keyword_score / background_ema > 3.0):
        return True
    return False

这个简单的改动,直接把误触发率降低了 90%

从原来的每天二三十次,降到了每天 1-2 次。而且召回率几乎没有下降,真正的关键词几乎都能准确识别。

五、开源我的运行时代码

为了方便大家使用,我把优化后的运行时代码开源到了 GitHub 上:

👉 github.com/voicute/onn…

这个运行时的特点:

  • 纯 ONNX Runtime 实现,没有任何其他依赖
  • 内置了我优化的动态相对置信度算法
  • 与原版 OpenWakeWord 生成的模型 100% 兼容
  • 目前已经在安卓、前端浏览器、Python三个环境下完整测试通过
  • MIT 许可证,完全免费商用

使用非常简单,只需要几行代码:

python

运行

from onnx_wakeword import OnnxWakeWord

ww = OnnxWakeWord("xiaoyanzi.onnx")

while True:
    audio_frame = get_audio_frame()
    if ww.detect(audio_frame):
        print("唤醒成功!")

安卓和前端的示例代码也都在 GitHub 仓库里,复制粘贴就能跑。

注:目前主要支持安卓、前端和 Python 环境,嵌入式设备(ESP32、树莓派等)的支持正在开发中,后续会逐步推出。

六、更进一步:一键生成模型

虽然有了运行时,但自己训练模型还是有点折腾:

  • 需要配置复杂的 PyTorch 训练环境
  • 需要收集和整理正样本、负样本数据集
  • 需要反复调整各种训练参数和后处理参数
  • 对电脑性能要求很高,没有好的显卡训练一次要几个小时

如果你不想折腾这些,可以用这个在线工具:

👉 www.voicute.com/

你只需要输入你的关键词,点击生成,15 分钟后就能下载一个训练好的 ONNX 模型。然后用我上面开源的运行时代码,直接就能在安卓、前端或 Python 环境中运行。

  • ✅ 不需要任何机器学习知识
  • ✅ 不需要自己收集任何录音
  • ✅ 生成的模型完全离线可用
  • ✅ 第一次生成完全免费

我自己实际测试了几十个关键词,效果都非常好。误触发率和我自己手动训练了几天的模型差不多,而且生成的模型和我的开源运行时完美兼容。

七、总结

经过两个星期的踩坑,我终于找到了一个完美的安卓离线语音唤醒解决方案:

  • 用 OpenWakeWord 作为基础模型
  • 用动态相对置信度算法解决误触发问题
  • 用一键生成网站解决训练难的问题
  • 用开源运行时解决部署难的问题

这个方案完全满足了我们的需求:纯离线、免费、轻量、低功耗、低误触发率。而且已经在我们的安卓 APP 上稳定运行了一个多月。

如果你也有离线语音唤醒的需求,不妨试试这个方案。有任何问题都可以在 GitHub 上提 issue,我会尽量回复。

最后,如果你觉得这个项目对你有帮助,欢迎给我的 GitHub 点个 star,这对我是最大的鼓励。

👉 **GitHub:github.com/voicute/onn…**👉 一键生成模型:www.voicute.com/

#语音识别 #安卓开发 #前端 #AI #开源 #关键词唤醒 #离线语音