Palavra de ativação / Detecção de palavras-chave

O módulo SpeechWakeWord executa um detector de palavras-chave no dispositivo: você registra uma lista de frases, envia chunks de áudio e recebe detecções. Baseado no transdutor Zipformer em streaming do icefall (3,49M parâmetros, Apache-2.0), compilado para CoreML com paletização INT8.

Apenas inglês

O checkpoint entregue é o fine-tuning KWS sobre gigaspeech. Palavras-chave não inglesas exigem um fine-tuning separado no icefall e reexportação.

Arquitetura

EtapaDetalhes
fbankcompatível com kaldi (25 ms / 10 ms, janela Povey, 80 bins mel, high_freq=-400, sem CMVN)
EncoderZipformer2 causal de 6 estágios (128-dim), entrada 45 frames mel → 8 frames de saída (40 ms / frame) — 3,3 MB INT8
DecoderTransdutor sem estado, vocabulário BPE-500, context size 2 — 525 KB FP16
JoinerProjeção linear + tanh — 160 KB INT8
DecodificaçãoBeam search modificado (beam=4) sobre um ContextGraph Aho-Corasick com as palavras-chave do usuário

Tamanho compilado em disco: ~4 MB no total (encoder.mlmodelc + decoder.mlmodelc + joiner.mlmodelc). Memória em execução: ~6 MB incluindo caches do encoder.

Desempenho

MétricaValorObservações
RTF (CPU + Neural Engine)0,0426× tempo real na série M
Recall (12 palavras-chave)88 %LibriSpeech test-clean, 158 enunciados positivos
Falsos positivos / enunciado0,2760 enunciados negativos
CoreML INT8 vs PyTorch FP3299 %Concordância de emissões

Valores padrão ajustados: acThreshold=0,15, contextScore=0,5, numTrailingBlanks=1. Sobrescritas por palavra-chave são suportadas.

Uso no CLI

Forma de frase simples (BPE greedy — funciona bem para palavras comuns):

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

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

Forma pré-tokenizada (estilo sherpa-onnx — recomendada quando você conhece a decomposição exata em que o modelo foi treinado):

# 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

Ou um arquivo de palavras-chave, uma entrada por linha (# para comentários):

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

API Swift

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

CampoSignificado
phraseFrase de exibição, p. ex. "hey soniqo". Também é a fonte da codificação BPE greedy quando tokens é nil.
acThresholdProbabilidade acústica média exigida sobre o trecho correspondido. 0 → usa o padrão ajustado (0,15).
boostBoost de contexto por token. Valores positivos facilitam disparar a frase. 0 → padrão ajustado (0,5).
tokensLista explícita opcional de peças BPE. Quando não nula, o detector consulta cada peça no tokens.txt do modelo e pula o encoder BPE greedy.
Quando usar tokens pré-tokenizado

O vocabulário KWS do icefall é BPE em maiúsculas. A tokenização greedy de uma frase pode escolher uma decomposição BPE diferente daquela na qual o modelo foi treinado para emitir — "LIGHT UP" é codificado greedy como ▁LI GHT ▁UP, mas a decomposição de treinamento é ▁ L IGHT ▁UP. Quando a detecção em áudio sintetizado por TTS ou leitura limpa perde correspondências óbvias, experimente a forma pré-tokenizada estilo sherpa-onnx.

Downloads do modelo

ModeloParâmetrosTamanhoHuggingFace
KWS-Zipformer-3M3.49M~4 MBaufklarer/KWS-Zipformer-3M-CoreML-INT8

Integração de pipeline

O módulo expõe um protocolo WakeWordProvider que espelha StreamingVADProvider, permitindo que uma pipeline de voz controle ativação via VAD, palavra de ativação ou ambos. WakeWordStreamingAdapter encapsula um detector carregado + uma única sessão em um objeto provider reutilizável.

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

Código fonte