唤醒词 / 关键词识别

SpeechWakeWord 模块在设备上运行关键词识别器:你注册一组短语,推入音频分段并接收检测结果。基于 icefall 的流式 Zipformer 转换器(3.49M 参数,Apache-2.0),通过 INT8 调色板量化编译为 CoreML。

仅支持英语

随附的检查点为 gigaspeech KWS 微调。非英语关键词需要单独的 icefall 微调并重新导出。

架构

阶段详情
fbankkaldi 兼容(25 ms / 10 ms、Povey 窗、80 mel bins、high_freq=-400、无 CMVN)
编码器6 阶段因果 Zipformer2(128 维),45 个 mel 帧输入 → 8 帧输出(每帧 40 ms)——3.3 MB INT8
解码器无状态转换器,BPE-500 词表,上下文大小 2——525 KB FP16
Joiner线性 + tanh 输出投影——160 KB INT8
解码在用户关键词的 Aho-Corasick ContextGraph 上执行改进 beam search(beam=4)

磁盘上的编译大小:共计 ~4 MBencoder.mlmodelc + decoder.mlmodelc + joiner.mlmodelc)。运行时内存:包含编码器状态缓存约 ~6 MB。

性能

指标说明
RTF(CPU + Neural Engine)0.04M 系列芯片上 26× 实时
Recall(12 个关键词)88%LibriSpeech test-clean,158 个正样本
误报 / 话语0.2760 个负样本
CoreML INT8 对比 PyTorch FP3299%发射一致率

调优默认值:acThreshold=0.15contextScore=0.5numTrailingBlanks=1。支持按关键词覆盖设置。

CLI 使用

纯短语形式(贪心 BPE——对常见词效果良好):

audio wake recording.wav --keywords "hey soniqo"

audio wake recording.wav --keywords "hey soniqo:0.15:0.5" "cancel"

预先分词形式(sherpa-onnx 风格——推荐在你确切知道模型训练所用分解时使用):

# Format: "phrase|piece1 piece2 ...:threshold:boost"
audio wake recording.wav \
    --keywords "LIGHT UP|▁ L IGHT ▁UP:0.25:2.0"

# Multiple keywords + JSON output
audio wake recording.wav \
    --keywords "LIGHT UP|▁ L IGHT ▁UP:0.25:2.0" \
               "LOVELY CHILD|▁LOVE LY ▁CHI L D:0.25:2.0" \
    --json

或者一个关键词文件,每行一个条目(# 为注释):

audio wake recording.wav --keywords-file keywords.txt

Swift API

import SpeechWakeWord

// Load the model with your keyword list.
let detector = try await WakeWordDetector.fromPretrained(
    keywords: [
        KeywordSpec(phrase: "hey soniqo", acThreshold: 0.15, boost: 0.5),
        KeywordSpec(phrase: "cancel")
    ]
)

// Streaming: push chunks, consume detections as they fire.
let session = try detector.createSession()
for chunk in micAudioChunks {                   // Float32 @ 16 kHz
    for detection in try session.pushAudio(chunk) {
        print("[\(detection.time(frameShiftSeconds: 0.04))s] \(detection.phrase)")
    }
}

// Batch: single shot over a full buffer.
let detections = try detector.detect(audio: samples, sampleRate: 16000)

KeywordSpec

字段含义
phrase显示短语,例如 "hey soniqo"。当 tokens 为 nil 时,也作为贪心 BPE 编码的来源。
acThreshold匹配跨度上所需的平均声学概率。0 → 使用调优默认值(0.15)。
boost按 token 的上下文增益。正值更容易触发短语。0 → 调优默认值(0.5)。
tokens可选显式 BPE 片段列表。若不为 nil,检测器在模型的 tokens.txt 中逐片查找,并跳过贪心 BPE 编码器。
何时使用预先分词的 tokens

icefall KWS 词表是大写 BPE。对一条短语的贪心分词可能选出与模型训练发射不同的 BPE 分解——"LIGHT UP" 贪心编码为 ▁LI GHT ▁UP,而训练分解是 ▁ L IGHT ▁UP。如果在 TTS 合成或干净朗读语音上检测漏掉了明显的匹配,请尝试 sherpa-onnx 风格的预先分词形式。

模型下载

模型参数大小HuggingFace
KWS-Zipformer-3M3.49M~4 MBaufklarer/KWS-Zipformer-3M-CoreML-INT8

Pipeline 集成

模块提供与 StreamingVADProvider 形状一致的 WakeWordProvider 协议,使语音 pipeline 可以通过 VAD、唤醒词或两者共同开启激活。WakeWordStreamingAdapter 将已加载的检测器 + 单个会话封装为可复用的 provider 对象。

let adapter = try WakeWordStreamingAdapter(detector: detector)
// pipeline.configure(wakeWord: adapter)

源代码