Skip to content

Commit e0ab67b

Browse files
Add End-to-End (E2E) Model Training
1 parent 56c4687 commit e0ab67b

28 files changed

Lines changed: 4386 additions & 1923 deletions

CHANGELOG.md

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,44 @@ All notable changes to this project will be documented in this file.
44

55
---
66

7+
## [3.0.0] - 2026-08-19
8+
9+
### Added
10+
11+
- **End-to-End (E2E) Training** - train wake word models directly on raw PCM audio waveforms. The model learns its own feature extraction internally, eliminating the need for pre-computed mel-spectrogram embeddings or a separate embedding model.
12+
- Three E2E architectures available via `model_type`:
13+
- `e2e_dnn` - Lightweight DNN with a `RawAudioFrontend` (fastest, smallest)
14+
- `e2e_cnn` - CNN with a `RawAudioFrontend` and `RawAudioBackbone` (balanced accuracy/size)
15+
- `e2e_quartznet` - QuartzNet-style blocks with configurable `e2e_quartznet_config` (most expressive)
16+
- E2E-specific config parameters: `mode: "e2e"`, `clip_samples` (fixed audio length in samples), `e2e_frontend_channels`, `e2e_frontend_depth`, `e2e_quartznet_config`
17+
- E2E data pipeline uses `data_generation_manifest` (augmented WAV clips) and `data_manifest` (WAV directories) instead of `feature_generation_manifest` / `.npy` files
18+
- E2E ONNX export includes a `mode: "e2e"` metadata tag and patches `MelSpectrogram` layers for ONNX-safe STFT
19+
- **Colab notebook**: `notebooks/Train_Your_First_E2E_Wake_Word_Model.ipynb`
20+
- **Example config**: `examples/e2e_training_config.yaml`
21+
22+
- **E2E Inference in `NanoInterpreter`** - E2E models are auto-detected via the `mode` metadata tag in the ONNX file. When an E2E model is loaded, the interpreter sets `preprocessor = None` (no mel-spectrogram extraction needed), accumulates raw audio in an internal buffer, and runs inference directly on raw PCM clips of `clip_samples` length once enough audio is collected. This means E2E models require **zero external dependencies** - no embedding model, no mel-spectrogram model, nothing. A single `.onnx` file is fully self-contained.
23+
24+
- **Custom E2E Architectures** - `model_type: "custom"` now works in E2E mode. Provide a `custom_model_config` with `module_path` and `class_name` pointing to any PyTorch `nn.Module` that accepts raw waveform input and returns an embedding. The custom class receives `input_shape`, `embedding_dim`, `dropout_prob`, `activation_fn`, `config`, and `frontend_channels` kwargs (with signature-based filtering).
25+
26+
- **E2E Cascade Support** - E2E models can be used in 2-stage cascade mode just like embedding models. The gate model can be an E2E model or a lightweight embedding model; the interpreter automatically detects each model's type.
27+
28+
- **E2E Remote Verifier** - the WebSocket server supports a new `e2e` pipeline mode (`--pipeline e2e`). The edge device sends raw PCM audio and the server runs the full E2E model directly. Also added `_TAG_AUDIO = 0x03` wire protocol tag for raw audio transmission in both `full` and `e2e` pipeline modes.
29+
30+
- **E2E Distillation** - `distill_model_e2e()` trains a tiny `e2e_dnn` student model from an E2E teacher, producing a compact `_lite.onnx` gate model. Configurable via `distillation:` block (`student_layer_size`, `student_n_blocks`, `student_embedding_dim`, `student_dropout_prob`).
31+
32+
### Changed
33+
34+
- `NanoInterpreter` now accepts `vad_threshold` and `enable_noise_reduction` as kwargs on `load_model()`, in addition to the existing constructor parameters.
35+
- `predict_clip()` auto-detects E2E models via `self.preprocessor is None` and routes raw audio directly to `predict()` without chunking for feature extraction.
36+
- ONNX export now writes `mode` metadata (`"e2e"` or `"embedding"`) to the model file for reliable detection at inference time.
37+
38+
---
39+
740
## [2.1.0] - 2026-05-13
841

942
### Added
1043

11-
- **Unified CLI (`nanowakeword`)** single entry point for the entire pipeline. No more separate commands for different tasks. Context is inferred from the flags you provide:
44+
- **Unified CLI (`nanowakeword`)** - single entry point for the entire pipeline. No more separate commands for different tasks. Context is inferred from the flags you provide:
1245
```bash
1346
nanowakeword -c config.yaml -T # train
1447
nanowakeword -c config.yaml -d # distill standalone
@@ -17,13 +50,13 @@ All notable changes to this project will be documented in this file.
1750
```
1851
The old `nanowakeword-train` command is kept as a backward-compatible alias.
1952

20-
- **Knowledge Distillation (`--distill` / `-d`)** automatically generates a lightweight `_lite.onnx` gate model from any trained teacher using temperature-scaled KL divergence. Two modes:
53+
- **Knowledge Distillation (`--distill` / `-d`)** - automatically generates a lightweight `_lite.onnx` gate model from any trained teacher using temperature-scaled KL divergence. Two modes:
2154
- Post-training: add `-d` alongside `-T` and the lite model is built right after training
2255
- Standalone: run `nanowakeword -c config.yaml -d` on an already-trained model, no retraining needed
2356
- Default student: ~12K parameters, ~50KB ONNX (~5–10x smaller than a typical teacher)
2457
- Fully configurable via `distillation:` config block (`steps`, `temperature`, `alpha`, `student_layer_size`, `student_embedding_dim`, etc.)
2558

26-
- **2-Stage Cascade Inference** the lite model acts as a lightweight gatekeeper (Stage 1). The full model only runs when the gate fires, saving CPU on always-on systems:
59+
- **2-Stage Cascade Inference** - the lite model acts as a lightweight gatekeeper (Stage 1). The full model only runs when the gate fires, saving CPU on always-on systems:
2760
```python
2861
# Auto-discovers my_model_lite.onnx in the same folder
2962
interpreter = NanoInterpreter.load_model("my_model.onnx", cascade=True)
@@ -36,14 +69,14 @@ All notable changes to this project will be documented in this file.
3669
)
3770
```
3871

39-
- **RemoteVerifier WebSocket server** host the full model (or the entire pipeline) on any machine and have edge devices connect to it. Three pipeline modes:
40-
- `verifier_only` (default) edge sends pre-computed features, server runs only the wake word model
41-
- `full` edge sends raw audio, server runs mel + embedding + wake word model
72+
- **RemoteVerifier WebSocket server** - host the full model (or the entire pipeline) on any machine and have edge devices connect to it. Three pipeline modes:
73+
- `verifier_only` (default) - edge sends pre-computed features, server runs only the wake word model
74+
- `full` - edge sends raw audio, server runs mel + embedding + wake word model
4275
```bash
4376
nanowakeword --model my_model.onnx --pipeline full --port 8765
4477
```
4578

46-
- **Distributed inference in `NanoInterpreter.load_model()`** new `remote_verifier` and `remote_pipeline` parameters:
79+
- **Distributed inference in `NanoInterpreter.load_model()`** - new `remote_verifier` and `remote_pipeline` parameters:
4780
```python
4881
# Gate local, verifier remote
4982
NanoInterpreter.load_model(
@@ -59,29 +92,29 @@ All notable changes to this project will be documented in this file.
5992
remote_pipeline="full",
6093
)
6194

62-
# No local model server handles everything
95+
# No local model - server handles everything
6396
NanoInterpreter.load_model(remote_verifier="ws://server:8765", remote_pipeline="full")
6497
```
6598

6699
- **`NanoInterpreter` API improvements:**
67-
- `model` parameter replaces `model_path` (backward compatible positional usage still works)
100+
- `model` parameter replaces `model_path` (backward compatible - positional usage still works)
68101
- New properties: `score`, `verifier_score`, `gate_score`, `model_name`, `gate_name`, `is_cascade`, `info`
69-
- `detected(threshold)` method clean boolean check
102+
- `detected(threshold)` method - clean boolean check
70103
- `listen()` now supports `blocking=False` (background thread), `on_audio` callback, and `on_score` callback
71-
- `stop()` terminates a non-blocking `listen()` loop
72-
- `__repr__` `print(interpreter)` shows useful state
104+
- `stop()` - terminates a non-blocking `listen()` loop
105+
- `__repr__` - `print(interpreter)` shows useful state
73106

74-
- **`DetectionResult` object** `predict()` now returns a rich result object instead of a plain dict. Supports both attribute access (`.score`, `.gate_score`, `.detected`) and dict-compatible access (`.get()`, `result["name"]`) for full backward compatibility.
107+
- **`DetectionResult` object** - `predict()` now returns a rich result object instead of a plain dict. Supports both attribute access (`.score`, `.gate_score`, `.detected`) and dict-compatible access (`.get()`, `result["name"]`) for full backward compatibility.
75108

76-
- **`--info` flag** inspect any `.onnx` model without loading the interpreter:
109+
- **`--info` flag** - inspect any `.onnx` model without loading the interpreter:
77110
```bash
78111
nanowakeword --info my_model.onnx
79112
# Shows: name, type (lite/full), file size, parameter count, architecture type, input/output shapes
80113
```
81114

82-
- **Collate function robustness** training no longer crashes when `.npy` feature files have slightly different frame counts. The collate function now pads/truncates to the most common length in each batch.
115+
- **Collate function robustness** - training no longer crashes when `.npy` feature files have slightly different frame counts. The collate function now pads/truncates to the most common length in each batch.
83116

84-
- **Buffer warmup guard** the interpreter no longer crashes on the first few audio chunks when a model requires more feature frames than the buffer currently holds (e.g., a 45-frame model on startup).
117+
- **Buffer warmup guard** - the interpreter no longer crashes on the first few audio chunks when a model requires more feature frames than the buffer currently holds (e.g., a 45-frame model on startup).
85118

86119
### Changed
87120

@@ -125,7 +158,7 @@ All notable changes to this project will be documented in this file.
125158

126159
### Fixed
127160

128-
- ONNX export failure for modern architectures upgraded default opset to 17
161+
- ONNX export failure for modern architectures - upgraded default opset to 17
129162
- `average_models` crash with BatchNorm layers (`num_batches_tracked` type mismatch)
130163
- TCN initialization `TypeError` with `nn.Sequential` and lambda functions
131164

@@ -140,7 +173,7 @@ All notable changes to this project will be documented in this file.
140173

141174
### Added
142175

143-
- **Training resumption** `--resume <path>` CLI flag + `checkpointing:` config block. Saves full training state (model, optimizer, scheduler, step, loss history).
176+
- **Training resumption** - `--resume <path>` CLI flag + `checkpointing:` config block. Saves full training state (model, optimizer, scheduler, step, loss history).
144177

145178
### Fixed
146179

@@ -154,9 +187,9 @@ Major re-architecture of the training framework.
154187

155188
### Added
156189

157-
- `auto_train` autonomous training with EMA-based stability tracking and checkpoint ensembling (SWA)
158-
- `ConfigProxy` every training parameter controllable from a single YAML file
159-
- Memory-mapped training stream terabyte-scale feature sets from disk
190+
- `auto_train` - autonomous training with EMA-based stability tracking and checkpoint ensembling (SWA)
191+
- `ConfigProxy` - every training parameter controllable from a single YAML file
192+
- Memory-mapped training - stream terabyte-scale feature sets from disk
160193
- Live terminal training dashboard
161194
- Strategic batch composition engine (`batch_composition` config)
162195
- Standardized ONNX export with `InferenceWrapper` (output shape `[B, 1, 1]`)

0 commit comments

Comments
 (0)