«Гектор» — tiny Ukrainian wake word for ESP32
Release v1.0 · October 2026
A tiny on-device model trained specifically to detect the Ukrainian word «Гектор» (Hektor) on an ESP32 microcontroller. It needs no cloud and no PC, takes 87 KB of flash and about 34 KB of RAM, and is estimated to listen continuously at a few percent of one ESP32-S3 core.
Built with microWakeWord as an int8 streaming network for TensorFlow Lite Micro. It works with ESPHome's micro_wake_word out of the box.
It is the wake word of Hektor, a six-legged walking robot: ESP32-S3 spine, INMP441 microphones, 18 servos, and a voice assistant (Deepgram STT → LLM → TTS over WebRTC). The robot only listens after it hears its name.
| Wake word | «Гектор», «Гекторе», «Гектор, » |
| Model | MixedNet, streaming, int8 — 87 KB flash |
| RAM | tensor arena 33.8 KB (30.6 KB minimum) |
| Compute | ~39 k MAC per 30 ms step ≈ 1.3 MMAC/s |
| Input | 16 kHz mono, 40 mel bins, 10 ms step |
| Default cutoff | 0.8, sliding window 5 (150 ms) |
Quick start
ESPHome
micro_wake_word:
models:
- model: https://huggingface.co/MartynU/hektor-micro-wakeword-esp32/resolve/main/manifest.json
Python (desktop, Raspberry Pi)
from huggingface_hub import snapshot_download
from pymicro_wakeword import MicroWakeWord, MicroWakeWordFeatures
path = snapshot_download("MartynU/hektor-micro-wakeword-esp32")
model = MicroWakeWord.from_config(f"{path}/manifest.json")
features = MicroWakeWordFeatures()
def on_audio(chunk: bytes): # 16 kHz, mono, int16
for f in features.process_streaming(chunk):
if model.process_streaming(f):
print("Гектор!")
model.reset()
Evaluation
Test speakers and voices are held out from training. "Live" is the author speaking to the robot, captured by the robot's own INMP441 microphone and sent over Wi-Fi, i.e. the real deployment path.
Cutoff 0.8, sliding window 5:
| Test set | n | Result |
|---|---|---|
| Recall, live voice via robot mic | 22 | 95.5 % (21/22) |
| Recall, live voice + command | 23 | 95.7 % |
| Recall, tempo-augmented speech (0.6–0.85×) | 978 | 83.6 % |
| Recall, voice clones (FireRed) | 355 | 68.5 % |
| Recall, Piper TTS voices | 3000 | 55.5 % |
| Recall, cloud TTS voices (Cartesia, ElevenLabs, Gemini) | 160 | 33.8 % |
| Recall, all held-out positives | 4518 | 62.1 % |
| False accepts, negative clips | 2146 | 4.2 % |
| False accepts, near-homophone «гектар» | 71 | 1.4 % |
| False accepts / hour, DiPCo dinner-party speech | 5.3 h | 1.5 |
| False accepts / hour, robot room ambient | 14 min | 0 |
Choosing a cutoff
| Cutoff | Live recall | FA/h DiPCo |
|---|---|---|
| 0.7 | 95.5 % | 3.7 |
| 0.8 (default) | 95.5 % | 1.5 |
| 0.9 | 90.9 % | 0.4 |
| 0.95 | 86.4 % | 0 |
Full numbers for every group and both window sizes are in eval.json.
How it was built and tested
Test method
Every number on this page comes from an evaluation that copies how the model runs on the chip. Each clip is padded with 1 s of −60 dBFS noise before and 0.5 s after. It then goes through the micro-frontend (40 mel bins, 30 ms window, 10 ms step) and the streaming int8 model in 30 ms steps. A sliding average of the last N outputs fires when it crosses the cutoff, the same way ESPHome does it.
- Recall is measured on held-out voices that were never used in training. The key set is the author's live voice recorded through the robot's own microphone and Wi-Fi link.
- False accepts per hour come from streaming 5.3 h of DiPCo dinner-party conversation (one trigger per rising edge, 1 s refractory). A second figure comes from 14 minutes of the robot's room recorded through its own ears and checked with Whisper to contain no wake word.
- All three training runs below were re-scored on the same final test set.
Three training runs
Run 1: baseline (6 Oct 2026). The microWakeWord training notebook with tweaks taken from a published Russian wake word trainer: class weights 1.5 / 1, SpecAugment, residual connections, background SNR −5…20 dB and never-silent padding. Only 9 live clips existed, oversampled ×3. The checkpoint was chosen by recall against false accepts on dinner-party speech. Synthetic voices worked, but live recall was 59 %. The model knew TTS but not a real person through a real microphone.
Run 2: push live recall (6 Oct 2026). Live clips oversampled ×5. Piper TTS negatives removed. The checkpoint and cutoff chosen on room noise recorded through the robot's ears. Live recall rose to 73 %, but false accepts on conversation jumped to 42 per hour. Validating only on a quiet room taught the model that "not silence" means "Гектор". Lesson learned: removing negatives and tuning on silence is a trap.
Run 3: more real data, balanced validation (7 Oct 2026) → this release.
- 93 live recordings (70 for training, 23 held out), collected with a recording bot that runs through the robot's own ears.
- Three phrase forms: «Гектор», «Гекторе» and «Гектор, ».
- Piper negatives restored, plus 347 new hard negatives.
- Live clips make up about 10 % of positives in each batch, with a 3× loss weight.
- Validation set: robot room noise plus 1 h of dinner-party speech. The checkpoint was chosen for ≤ 0.5 false accepts per hour first, then for maximum recall.
- 10 000 steps, 38 minutes on a Colab T4.
Result: live recall 95.5 %, 1.5 false accepts per hour on conversation, 0 in the room.
| Run | Cutoff | Live recall | FA/h DiPCo | FA/h room |
|---|---|---|---|---|
| 1 | 0.6 | 59.1 % | 0 | 0 |
| 2 | 0.5 | 72.7 % | 42.6 | 4.3 |
| 3 (v1.0) | 0.8 | 95.5 % | 1.5 | 0 |
Before microWakeWord
Before microWakeWord the project went through nine openWakeWord versions. Synthetic TTS voices were easy for them, but the author's live voice through the robot microphone was not. On the same 22 live test clips, the best openWakeWord model (v4d) caught 41 % at a low 0.2 threshold, against 95.5 % for this model. The gap came from the robot's microphone chain, the distance and real fast speech. Moving to microWakeWord, giving live and re-recorded clips more weight, and adding tempo augmentation closed it.
Training data
About 10.3 k positive training clips of three phrases: «Гектор», «Гекторе» and «Гектор, »:
- Piper TTS voices and cloud TTS (Cartesia, ElevenLabs, Gemini) with varied emotion and speed;
- voice clones of the author made with FireRed;
- tempo augmentation 0.6–0.85×, because live speech is faster than TTS (0.5–0.7 s vs 0.8–1.2 s per word);
- re-recordings through the robot's ears: TTS played back in a room and captured by the robot's INMP441 microphone at 1.5 m and 3 m;
- 70 live recordings of the author through the robot, with a 3× loss weight.
Negatives: about 10.5 k own clips (similar-sounding words, everyday phrases and commands from TTS, Piper, the author's speech and robot-mic recordings) plus the precomputed negative spectrograms from kahrendt/microwakeword (speech, dinner party, no-speech). Augmentation used MIT room impulse responses, AudioSet and FMA background, and the robot's own room noise.
Every clip has a provenance record (source, TTS model, voice, phrase, date). Raw audio is not published.
The code behind all of this — clip generation, the three training runs with their configs, the evaluation scripts and the recording bots — is open source: hexapod-hektor/hektor-micro-wakeword-esp32.
Training: microWakeWord @4665173, 10 000 steps, batch 128, lr 0.001, class weights 1.5 / 1.0, SpecAugment 2×5 time and frequency. The checkpoint was selected for ≤ 0.5 false accepts per hour on room ambient, then for maximum recall. Trained on a Google Colab T4. Full config: training_parameters.yaml.
Limitations
- Speaker-dependent. The live test set is a single speaker (the author), 22 clips. On unseen synthetic voices recall drops to 62 %. Expect lower recall for other speakers, children and different accents until the model is trained on more real voices.
- Bare «Гектор» is harder than «Гекторе» (55 % vs 78 % on held-out synthetic voices at 0.8). The vocative form with its extra syllable triggers more reliably.
- The room-ambient false-accept figure comes from only 14 minutes of audio.
- Running on the robot's own ESP32-S3 is the next step. Today Hektor runs this model on the host (via
pymicro-wakeword) on audio streamed from the ESP32-S3 microphone. On-device timing is estimated from the MAC count and will be measured on the chip in the next release.
License
CC BY-NC 4.0. The model was trained with negative data from kahrendt/microwakeword, which is licensed CC BY-NC 4.0, so this model is for non-commercial use. For a commercial wake word, the same pipeline can be retrained on commercially licensed negatives.
Author
Martyn: backend engineer moving into embedded systems. Hektor is built from scratch: hardware, ESP-IDF firmware, the voice pipeline and this model. Pipeline code: GitHub.
- Downloads last month
- 19
Collection including MartynU/hektor-micro-wakeword-esp32
Evaluation results
- Recall, live speech via robot mic (n=22, cutoff 0.8) on Hektor held-out test set (live, robot microphone)self-reported95.500
- False accepts / hour, DiPCo dinner-party speech (5.3 h) on Hektor held-out test set (live, robot microphone)self-reported1.500
- False accepts / hour, robot room ambient (14 min) on Hektor held-out test set (live, robot microphone)self-reported0.000