كلمة الاستيقاظ / رصد الكلمات المفتاحية

تشغّل وحدة SpeechWakeWord راصد كلمات مفتاحية على الجهاز: تسجّل قائمة من العبارات، تُمرّر أجزاء الصوت، فتتلقّى الاكتشافات. مبني على مُحوِّل Zipformer للبثّ من icefall (3.49M معامل، Apache-2.0)، مُصرَّف إلى CoreML مع palettization بنمط INT8.

الإنجليزية فقط

نقطة التحقّق المُرفقة هي التهيئة الدقيقة لـ KWS على gigaspeech. تستلزم الكلمات المفتاحية بغير الإنجليزية تهيئة دقيقة منفصلة في icefall وإعادة تصدير.

البنية المعمارية

المرحلةالتفاصيل
fbankمتوافق مع kaldi (25 ms / 10 ms، نافذة Povey، 80 mel bins، high_freq=-400، دون CMVN)
EncoderZipformer2 سببي بستّ مراحل (128-dim)، 45 إطار mel دخل → 8 إطارات خرج (40 ms / إطار) — 3.3 MB INT8
Decoderمُحوِّل دون حالة، مفردات BPE-500، حجم سياق 2 — 525 KB FP16
Joinerإسقاط خطّي + tanh — 160 KB INT8
فكّ الترميزBeam search المُعدَّل (beam=4) على ContextGraph بأسلوب Aho-Corasick من الكلمات المفتاحية للمستخدم

الحجم المُصرَّف على القرص: ~4 MB إجمالًا (encoder.mlmodelc + decoder.mlmodelc + joiner.mlmodelc). الذاكرة وقت التشغيل: ~6 MB بما في ذلك مخابئ حالة الـ encoder.

الأداء

المقياسالقيمةملاحظات
RTF (CPU + Neural Engine)0.0426× الزمن الحقيقي على شرائح M
الاستدعاء (12 كلمة مفتاحية)88%LibriSpeech test-clean، 158 منطوقًا إيجابيًا
الإيجابيات الكاذبة / منطوق0.2760 منطوقًا سلبيًا
CoreML INT8 مقابل PyTorch FP3299%توافق في الإصدار

القيم الافتراضية المضبوطة: acThreshold=0.15، contextScore=0.5، numTrailingBlanks=1. مدعوم تجاوز هذه القيم لكلّ كلمة مفتاحية على حدة.

استخدام CLI

صيغة العبارة الصرفة (BPE الجشع — تعمل جيدًا للكلمات الشائعة):

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

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

الصيغة المُرمَّزة مسبقًا (أسلوب sherpa-onnx — مُوصى به حين تعرف التفكيك الدقيق الذي درّب عليه النموذج):

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

# Multiple keywords + JSON output
speech 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

أو ملفّ كلمات مفتاحية، إدخال واحد في كلّ سطر (# للتعليقات):

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

واجهة 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

الحقلالمعنى
phraseعبارة العرض، مثل "hey soniqo". تُستخدم أيضًا مصدرًا لترميز BPE الجشع عندما يكون tokens هو nil.
acThresholdالاحتمال الصوتي الوسطي المطلوب على المقطع المتطابق. 0 ← استخدام القيمة الافتراضية المضبوطة (0.15).
boostتعزيز السياق لكلّ token. القيم الموجبة تسهّل إطلاق العبارة. 0 ← القيمة الافتراضية المضبوطة (0.5).
tokensقائمة قِطَع BPE صريحة اختيارية. حين لا تكون nil، يبحث الراصد عن كلّ قطعة في tokens.txt للنموذج ويتجاوز مُرمِّز BPE الجشع.
متى تستخدم tokens المُرمَّزة مسبقًا

مفردات KWS الخاصّة بـ icefall هي 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

التكامل مع خطّ الأنابيب

تُتيح الوحدة بروتوكول WakeWordProvider الذي يحاكي StreamingVADProvider، بحيث يمكن لخطّ أنابيب صوتيّ أن يضبط التفعيل عبر VAD أو كلمة الاستيقاظ أو كليهما. يغلّف WakeWordStreamingAdapter راصدًا مُحمَّلًا + جلسة واحدة في كائن provider قابل لإعادة الاستخدام.

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

الكود المصدري