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.
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
| Etapa | Detalhes |
|---|---|
| fbank | compatível com kaldi (25 ms / 10 ms, janela Povey, 80 bins mel, high_freq=-400, sem CMVN) |
| Encoder | Zipformer2 causal de 6 estágios (128-dim), entrada 45 frames mel → 8 frames de saída (40 ms / frame) — 3,3 MB INT8 |
| Decoder | Transdutor sem estado, vocabulário BPE-500, context size 2 — 525 KB FP16 |
| Joiner | Projeção linear + tanh — 160 KB INT8 |
| Decodificação | Beam 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étrica | Valor | Observações |
|---|---|---|
| RTF (CPU + Neural Engine) | 0,04 | 26× tempo real na série M |
| Recall (12 palavras-chave) | 88 % | LibriSpeech test-clean, 158 enunciados positivos |
| Falsos positivos / enunciado | 0,27 | 60 enunciados negativos |
| CoreML INT8 vs PyTorch FP32 | 99 % | 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
| Campo | Significado |
|---|---|
phrase | Frase de exibição, p. ex. "hey soniqo". Também é a fonte da codificação BPE greedy quando tokens é nil. |
acThreshold | Probabilidade acústica média exigida sobre o trecho correspondido. 0 → usa o padrão ajustado (0,15). |
boost | Boost de contexto por token. Valores positivos facilitam disparar a frase. 0 → padrão ajustado (0,5). |
tokens | Lista 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. |
tokens pré-tokenizadoO 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
| Modelo | Parâmetros | Tamanho | HuggingFace |
|---|---|---|---|
| KWS-Zipformer-3M | 3.49M | ~4 MB | aufklarer/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
- Sources/SpeechWakeWord — módulo Swift
- docs/models/kws-zipformer.md — notas de arquitetura
- docs/inference/wake-word.md — pipeline de inferência
- Upstream: receita KWS k2-fsa/icefall / pkufool/keyword-spotting-models