The reason for this repo is pretty straight forward: you're using Atlas Voice or your own custom rolled voice assistant and saying "Hey Jarvis" feels a bit to Hollywood fanboi-ish. This repo will allow you to train whatever word you want to use. It's a Dockerized (and native linux) training pipeline for custom audio trigger models. Compatible with OpenAI Whisper and Faster Whisper and based on the outstanding OpenWakeWord work by David Scripka.
If you want to skip all the formalities of training and use "Hey Atlas" as your trigger word, see "Releases" in the right pane. Both the .onnx and .tflite models can be downloaded.
Training OpenWakeWord models in 2026 is a dependency nightmare. The training pipeline requires PyTorch 1.13.1, TensorFlow 2.8.1, and dozens of other packages pinned to 2022-era versions that have since aged out of compatibility with modern Python. The train-wakeword.sh script will build a complete dockerized training solution. The train.sh script does the exact same thing, but installs native dependencies with no docker requirement. Both scripts freeze the working environment of openWakeWord to commit 368c037 (main on February 1, 2026).
To build a Docker container that downloads training data, generates synthetic speech samples, augments them with common noise, trains a neural network, and outputs a model file (~200KB) that can listen for your custom trigger word.
- NVIDIA GPU with CUDA support
- Docker with nvidia-container-toolkit
- ~45GB free disk space (20GB training data + container workspace)
All packages and dependencies are handled inside the container.
If you use the bare-metal train.sh path instead, you also need Python 3.10 on the host (python3.10, python3.10-venv, python3.10-dev). PyTorch 1.13.1 and TensorFlow 2.8.1 only ship cp310 wheels - Python 3.11+ will fail at the pip install step. On Ubuntu-based systems the script can install 3.10 from the deadsnakes PPA for you.
git clone https://github.com/briankelley/atlas-voice-training.git
cd atlas-voice-training
./train-wakeword.shLaunch the main script and it'll walk you through the process:
- Builds the Docker image (first run only, cached after that)
- Asks if you want to proceed with the ~20GB training data download
- Asks for your wake word with advice on what works best
- Shows default training settings (configurable)
- Launches training inside the container
- Models saved to
docker-output/
═══════════════════════════════════════════════════════
Training Complete!
Wake word: "Hey Atlas"
Models:
hey_atlas.onnx (201K)
hey_atlas.tflite (207K)
Accuracy: 81.07% (how well it tells your wake word apart from everything else)
Recall: 62.20% (how often it catches your wake word; higher = less repeating yourself)
FP/hr: 1.24 (phantom activations per hour when you're not speaking the wake word)
Output directory: /output/
═══════════════════════════════════════════════════════
Copy the .tflite file to ~/.local/share/openwakeword/ for use with OpenWakeWord.
The trained model handles wake word detection only. To build a full voice input pipeline, you also need:
| Package | Purpose |
|---|---|
| OpenWakeWord | Loads the .tflite model and listens for the wake word |
| faster-whisper | Speech-to-text transcription after the wake word triggers |
| sounddevice | Audio capture from your microphone |
Use a two-word phrase. This was a big factor in model quality across every configuration I tested. A prefix like "Hey" or "Okay" gives the model a stronger acoustic signature.
| Wake Word | Accuracy | Recall | FP/hr | Verdict |
|---|---|---|---|---|
| "Hey Atlas" (50k samples) | 81.10% | 62.48% | 2.12 | Best overall |
| "Globe Master" (50k samples) | 81.07% | 62.20% | 1.24 | Two-word phrase, consistent |
| "Hey Atlas" (100k samples) | 77.47% | 55.08% | 0.62 | More conservative, worse recall |
| "Atlas" (50k, 3 aug rounds) | 71.64% | 43.54% | 2.57 | Single word, consistently worse |
| "Atlas" (50k, 64 neurons) | 71.94% | 44.04% | 2.48 | Extra neurons didn't help |
No combination of augmentation rounds, sample count, or neuron depth made the model more accurate when the "Hey" prefix was dropped.
The defaults produce the best balance of accuracy and recall based on empirical testing. You can change this before training. Hat tip to @dscripka for great defaults.
| Setting | Default | Purpose | Testing Notes |
|---|---|---|---|
| Samples | 50,000 | Number of synthetic speech clips generated | Doubling to 100k didn't improve accuracy or recall |
| Augmentation rounds | 2 | Times each clip is re-processed with noise/reverb | 3 rounds produced no measurable improvement |
| Training steps | 100,000 | Neural network training iterations | 150k steps didn't improve results |
| Layer size | 32 | Neurons per hidden layer | 64 neurons produced identical results to 32 |
Training data is hosted on HuggingFace and downloaded automatically in standalone mode (~20GB as a single tarball).
| File | Size | Purpose |
|---|---|---|
| ACAV100M features | 17 GB | 2,000 hours of pre-computed negative examples |
| MUSAN music | 4.6 GB | Background audio for augmentation |
| MIT Room Impulse Responses | 300 MB | Room reverb simulation (pre-converted to 16kHz) |
| Validation features | 177 MB | False positive testing during training |
| Piper TTS model | 200 MB | Synthetic speech generation |
| Embedding models | ~10 MB | OpenWakeWord melspectrogram and embedding inference |
All training data is bundled in a single ~20GB tarball and downloaded automatically.
Training runs in three phases inside the container (start to finish with defaults and broadband is ~1h on a 4090):
- Generate clips - Piper TTS creates thousands of synthetic pronunciations of your wake word with varying voices, speeds, and pitch
- Augment clips - Each clip is layered with room reverb, background noise, and acoustic conditions (runs on CPU)
- Train model - A neural network learns to distinguish your wake word from everything else (runs on GPU)
The output is an ONNX model and a TFLite model, both under 250KB.
| File | Purpose |
|---|---|
train-wakeword.sh |
What you run - interactive host wrapper (run this on your rig) |
train.sh |
Bare-metal path - installs and runs everything natively without Docker |
container-entrypoint.sh |
Runs inside the Docker container |
Dockerfile.training |
Builds the training environment |
validate_model.py |
Compare model accuracy against test data |
torch==1.13.1- no wheels for Python 3.12+pyarrow- brokedatasetsAPI (pinned<15.0.0)fsspec- brokedatasetsglob patterns (pinned<2024.1.0)webrtcvad- needs C compilation, undocumented dependency onbuild-essentialpython3.10-venv- version-specific package naming- HuggingFace download leaves
.cachedirectories that break training - MIT RIR files nested in
16khz/subdirectory - MIT RIR files are 32kHz, training expects 16kHz
- Docker shared memory - PyTorch DataLoader needs
--shm-size=32g - HuggingFace rate limiting from repeated individual file downloads
- Training segfaults on cleanup after model is already saved (harmless)
- Python output buffering in Docker hides progress (
PYTHONUNBUFFERED=1)
- Training scripts and configs: Apache 2.0
- ACAV100M features: CC-BY-NC-SA-4.0 (non-commercial)
- MUSAN: CC BY 4.0
Note: The CC-BY-NC-SA-4.0 license on ACAV100M means trained models inherit a non-commercial restriction.
- OpenWakeWord by David Scripka (this repo uses a pinned fork)
- Piper Sample Generator by David Scripka (pinned fork)
- Piper TTS by Rhasspy
- MUSAN corpus
- MIT Room Impulse Responses