ウェイクワード / キーワード検出

SpeechWakeWord モジュールはオンデバイスのキーワードスポッターを実行します:フレーズのリストを登録し、音声チャンクをプッシュして検出結果を受け取ります。icefall のストリーミング Zipformer トランスデューサー(3.49M パラメータ、Apache-2.0)をベースに、INT8 パレット化で CoreML にコンパイルされています。

英語のみ

提供されるチェックポイントは gigaspeech KWS のファインチューンです。英語以外のキーワードには、別途 icefall のファインチューンと再エクスポートが必要です。

アーキテクチャ

ステージ詳細
fbankkaldi 互換(25 ms / 10 ms、Povey 窓、80 メル bins、high_freq=-400、CMVN なし)
エンコーダー6 ステージの因果 Zipformer2(128 次元)、45 メルフレーム入力 → 8 フレーム出力(40 ms / フレーム)— 3.3 MB INT8
デコーダーステートレスなトランスデューサー、BPE-500 語彙、コンテキストサイズ 2 — 525 KB FP16
Joiner線形 + tanh 出力プロジェクション — 160 KB INT8
デコードユーザーキーワードの Aho-Corasick ContextGraph 上での修正ビーム探索(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

またはキーワードファイル、1 行に 1 エントリ(コメントは #):

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トークンあたりのコンテキストブースト。正の値はフレーズのトリガーを容易にします。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

パイプライン統合

モジュールは StreamingVADProvider を反映した WakeWordProvider プロトコルを公開しており、音声パイプラインで VAD、ウェイクワード、またはその両方によるアクティベーションをゲートできます。WakeWordStreamingAdapter は、ロード済みの検出器 + 単一セッションを再利用可能な provider オブジェクトにラップします。

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

ソース