conv-hardened: add frame-by-frame streaming graphs (fp32 + signed int8, 17 FIFO states); document both NPU deploy paths (windowed 1.15 ms/frame PESQ 2.998; streaming 16 ms hop PESQ 2.982)
Browse files
README.md
CHANGED
|
@@ -52,7 +52,8 @@ has (topology verified on Neural-ART).
|
|
| 52 |
`feat_window (B,3,132,257) -> est_mag (B,64,257)`, window = receptive field
|
| 53 |
68 + 64 emitted frames) that **compiles to Neural-ART** — the artifact handed
|
| 54 |
to stedgeai. The hardened primitives also quantize far better (int8 drop
|
| 55 |
-
−0.016 vs −0.115 for `conv/`).
|
|
|
|
| 56 |
* **`conv-hardened-deep/`** is the **best model overall**: the hardened recipe,
|
| 57 |
deeper (3 blocks) with an extra dilation stage (receptive field 196 frames ≈
|
| 58 |
3.1 s) and **ReLU6** activations (bounded ranges quantize better; exports as
|
|
@@ -62,6 +63,33 @@ has (topology verified on Neural-ART).
|
|
| 62 |
(int8 except the decoder's QDQ nodes, PESQ **3.052** — the int8 loss is
|
| 63 |
decoder-localized; the decoder then runs as float epochs on the board).
|
| 64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
Code + full write-up: [https://github.com/LarocheC/eco8-neaixt](https://github.com/LarocheC/eco8-neaixt) — see
|
| 66 |
[RESULTS_LISENNET.md](https://github.com/LarocheC/eco8-neaixt/blob/main/RESULTS_LISENNET.md).
|
| 67 |
|
|
@@ -71,10 +99,12 @@ Code + full write-up: [https://github.com/LarocheC/eco8-neaixt](https://github.c
|
|
| 71 |
and `g_best_int8_static.onnx` (whole-utterance mask sub-network,
|
| 72 |
`feat (B,3,T,F) -> est_mag (B,T,F)`). `conv/` additionally has
|
| 73 |
`g_best_streaming_fp32.onnx` and `g_best_streaming_int8_static.onnx` (single
|
| 74 |
-
frame + explicit state I/O
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
|
|
|
|
|
|
| 78 |
|
| 79 |
## Loading (PyTorch)
|
| 80 |
|
|
@@ -108,14 +138,19 @@ feat_window = np.zeros((1, 3, 132, 257), np.float32) # last 68+64 feature fram
|
|
| 108 |
est_mag = sess.run(["est_mag"], {"feat_window": feat_window})[0] # (1, 64, 257)
|
| 109 |
```
|
| 110 |
|
| 111 |
-
## Running the
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
```python
|
| 114 |
import numpy as np, onnxruntime as ort
|
| 115 |
from huggingface_hub import hf_hub_download
|
| 116 |
|
| 117 |
sess = ort.InferenceSession(
|
| 118 |
-
hf_hub_download("claroche1/LiSenNet", "conv/
|
| 119 |
providers=["CPUExecutionProvider"],
|
| 120 |
)
|
| 121 |
state_in = [i for i in sess.get_inputs() if i.name != "feat"] # FIFO states
|
|
|
|
| 52 |
`feat_window (B,3,132,257) -> est_mag (B,64,257)`, window = receptive field
|
| 53 |
68 + 64 emitted frames) that **compiles to Neural-ART** — the artifact handed
|
| 54 |
to stedgeai. The hardened primitives also quantize far better (int8 drop
|
| 55 |
+
−0.016 vs −0.115 for `conv/`). It also ships a **frame-by-frame streaming**
|
| 56 |
+
graph — see below.
|
| 57 |
* **`conv-hardened-deep/`** is the **best model overall**: the hardened recipe,
|
| 58 |
deeper (3 blocks) with an extra dilation stage (receptive field 196 frames ≈
|
| 59 |
3.1 s) and **ReLU6** activations (bounded ranges quantize better; exports as
|
|
|
|
| 63 |
(int8 except the decoder's QDQ nodes, PESQ **3.052** — the int8 loss is
|
| 64 |
decoder-localized; the decoder then runs as float epochs on the board).
|
| 65 |
|
| 66 |
+
## Two deploy paths (`conv-hardened/`) — throughput vs latency
|
| 67 |
+
|
| 68 |
+
The hardened variant ships **both** NPU-deployable graphs. They are the same
|
| 69 |
+
trained weights; they differ only in how much audio each inference call consumes.
|
| 70 |
+
Both are measured on an STM32N6570-DK (STM32N657, MCU 800 MHz / NPU 1 GHz,
|
| 71 |
+
stedgeai 4.0.1); PESQ is the full 824-utterance VBD test split, int8 + noisy
|
| 72 |
+
phase.
|
| 73 |
+
|
| 74 |
+
| graph | shape | algorithmic latency | latency/frame | RTF | PESQ |
|
| 75 |
+
| ----- | ----- | ------------------- | ------------: | --: | ---: |
|
| 76 |
+
| `g_best_windowed_int8_static.onnx` | `feat_window (B,3,132,257) -> est_mag (B,64,257)` | 1.02 s block | **1.15 ms** | 0.072 | **2.998** |
|
| 77 |
+
| `g_best_streaming_int8_static.onnx` | `feat (B,3,1,257) + 17 states -> est_mag (B,1,257) + 17 states` | **one 16 ms hop** | 2.79 ms | 0.174 | **2.982** |
|
| 78 |
+
|
| 79 |
+
* the **windowed** graph is stateless and the throughput champion (1.15 ms per
|
| 80 |
+
emitted frame), but buffers 1.02 s of audio per call — use it when block
|
| 81 |
+
latency is acceptable;
|
| 82 |
+
* the **streaming** graph is true frame-by-frame — one 16 ms hop in, one enhanced
|
| 83 |
+
frame out, with 17 bounded FIFO state tensors carried on-device (47 KiB weights
|
| 84 |
+
+ 147 KiB activations, entirely on-chip). It costs ~2.4× more compute per frame
|
| 85 |
+
but drops algorithmic latency by ~64×, which makes it the best-quality
|
| 86 |
+
*streaming* speech enhancer measured on this NPU.
|
| 87 |
+
|
| 88 |
+
Both are signed QInt8 (the Neural-ART recipe). The streaming graph is calibrated
|
| 89 |
+
by threading the real FIFO state through the trained model, so the state tensors
|
| 90 |
+
see realistic ranges; its int8 cost is −0.018 PESQ vs the same-protocol FP32
|
| 91 |
+
streaming reference (3.000).
|
| 92 |
+
|
| 93 |
Code + full write-up: [https://github.com/LarocheC/eco8-neaixt](https://github.com/LarocheC/eco8-neaixt) — see
|
| 94 |
[RESULTS_LISENNET.md](https://github.com/LarocheC/eco8-neaixt/blob/main/RESULTS_LISENNET.md).
|
| 95 |
|
|
|
|
| 99 |
and `g_best_int8_static.onnx` (whole-utterance mask sub-network,
|
| 100 |
`feat (B,3,T,F) -> est_mag (B,T,F)`). `conv/` additionally has
|
| 101 |
`g_best_streaming_fp32.onnx` and `g_best_streaming_int8_static.onnx` (single
|
| 102 |
+
frame + explicit state I/O — CPU/onnxruntime reference only; this variant's
|
| 103 |
+
streaming graph does not compile to Neural-ART). `conv-hardened/` has **both**
|
| 104 |
+
NPU deploy graphs: `g_best_windowed_{fp32,int8_static}.onnx` (stateless windowed)
|
| 105 |
+
and `g_best_streaming_{fp32,int8_static}.onnx` (frame-by-frame, 17 FIFO states) —
|
| 106 |
+
see the two-deploy-paths table above. The ONNX graphs are the mask sub-network
|
| 107 |
+
only — STFT, feature build and phase recovery stay host-side.
|
| 108 |
|
| 109 |
## Loading (PyTorch)
|
| 110 |
|
|
|
|
| 138 |
est_mag = sess.run(["est_mag"], {"feat_window": feat_window})[0] # (1, 64, 257)
|
| 139 |
```
|
| 140 |
|
| 141 |
+
## Running the streaming graph frame-by-frame (`conv-hardened/`, `conv/`)
|
| 142 |
+
|
| 143 |
+
One 16 ms hop in, one enhanced frame out; the FIFO state tensors are threaded
|
| 144 |
+
from each call's outputs into the next call's inputs (start-of-stream = zeros).
|
| 145 |
+
Point it at `conv-hardened/` for the NPU-deployable graph (PESQ 2.982), or
|
| 146 |
+
`conv/` for the CPU-only reference.
|
| 147 |
|
| 148 |
```python
|
| 149 |
import numpy as np, onnxruntime as ort
|
| 150 |
from huggingface_hub import hf_hub_download
|
| 151 |
|
| 152 |
sess = ort.InferenceSession(
|
| 153 |
+
hf_hub_download("claroche1/LiSenNet", "conv-hardened/g_best_streaming_int8_static.onnx"),
|
| 154 |
providers=["CPUExecutionProvider"],
|
| 155 |
)
|
| 156 |
state_in = [i for i in sess.get_inputs() if i.name != "feat"] # FIFO states
|
conv-hardened/g_best_streaming_fp32.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a3e6ab2cf828f5f7f65d1b1e3f74ba9f8a19751152af114c620a3db83a5b55de
|
| 3 |
+
size 261749
|
conv-hardened/g_best_streaming_int8_static.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:10abffb4c1b00b8ee4de2ceb03dbcbbbd5a149dd27bb6e4adec96b668d017b55
|
| 3 |
+
size 363756
|