Palabra de activación / Detección de palabras clave

El módulo SpeechWakeWord ejecuta un detector de palabras clave en el dispositivo: registra una lista de frases, empuja fragmentos de audio y recibe detecciones. Basado en el transductor Zipformer en streaming de icefall (3,49M parámetros, Apache-2.0), compilado a CoreML con paletización INT8.

Solo inglés

El checkpoint enviado es el fine-tuning KWS sobre gigaspeech. Las palabras clave no inglesas requieren un fine-tuning de icefall independiente y una re-exportación.

Arquitectura

EtapaDetalles
fbankcompatible con kaldi (25 ms / 10 ms, ventana Povey, 80 bins mel, high_freq=-400, sin CMVN)
EncoderZipformer2 causal de 6 etapas (128-dim), entrada 45 frames mel → 8 frames de salida (40 ms / frame) — 3,3 MB INT8
DecoderTransductor sin estado, vocabulario BPE-500, context size 2 — 525 KB FP16
JoinerProyección lineal + tanh — 160 KB INT8
DecodificaciónBeam search modificado (beam=4) sobre un ContextGraph Aho-Corasick con las palabras clave del usuario

Tamaño compilado en disco: ~4 MB en total (encoder.mlmodelc + decoder.mlmodelc + joiner.mlmodelc). Memoria en ejecución: ~6 MB incluyendo las cachés del encoder.

Rendimiento

MétricaValorNotas
RTF (CPU + Neural Engine)0,0426× tiempo real en serie M
Recall (12 palabras clave)88 %LibriSpeech test-clean, 158 enunciados positivos
Falsos positivos / enunciado0,2760 enunciados negativos
CoreML INT8 vs PyTorch FP3299 %Acuerdo de emisiones

Valores por defecto ajustados: acThreshold=0,15, contextScore=0,5, numTrailingBlanks=1. Se admiten sobreescrituras por palabra clave.

Uso del CLI

Forma de frase plana (BPE greedy — funciona bien para palabras comunes):

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

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

Forma pre-tokenizada (estilo sherpa-onnx — recomendado cuando conoces la descomposición exacta con la que se entrenó el modelo):

# 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

O un archivo de palabras clave, una entrada por línea (# para comentarios):

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 visualización, p. ej. "hey soniqo". También se usa como origen para la codificación BPE greedy cuando tokens es nil.
acThresholdProbabilidad acústica media requerida sobre el tramo coincidente. 0 → usa el valor por defecto ajustado (0,15).
boostRefuerzo de contexto por token. Valores positivos facilitan el disparo de la frase. 0 → valor por defecto ajustado (0,5).
tokensLista explícita opcional de piezas BPE. Cuando no es nil, el detector busca cada pieza en el tokens.txt del modelo y omite el codificador BPE greedy.
Cuándo usar tokens pre-tokenizados

El vocabulario KWS de icefall es BPE en mayúsculas. La tokenización greedy de una frase puede elegir una descomposición BPE distinta de la que se entrenó al modelo para emitir — "LIGHT UP" se codifica greedy como ▁LI GHT ▁UP, pero la descomposición de entrenamiento es ▁ L IGHT ▁UP. Cuando la detección sobre audio sintetizado por TTS o lectura limpia pierde coincidencias obvias, prueba la forma pre-tokenizada estilo sherpa-onnx.

Descargas del modelo

ModeloParámetrosTamañoHuggingFace
KWS-Zipformer-3M3.49M~4 MBaufklarer/KWS-Zipformer-3M-CoreML-INT8

Integración en pipeline

El módulo expone un protocolo WakeWordProvider que refleja StreamingVADProvider, de modo que una pipeline de voz puede controlar la activación mediante VAD, palabra de activación o ambas. WakeWordStreamingAdapter envuelve un detector cargado + una única sesión en un objeto provider reutilizable.

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

Código fuente