Update model to v0.2.0: VOCAB_SIZE=98, Bi-CLSTM stride (2,2), best.ckpt validation selection, and N=100 evaluation metrics with 95% CIs
Browse files- README.md +78 -40
- best.ckpt.data-00000-of-00001 +2 -2
- best.ckpt.index +0 -0
- best.ckpt.meta +2 -2
- evaluation_metrics.json +0 -0
- model.tflite +2 -2
README.md
CHANGED
|
@@ -19,54 +19,89 @@ arxiv: 2008.06006
|
|
| 19 |
|
| 20 |
# Textual Echo Cancellation (TEC) β Single Interfering Voice (`TecSingleInterfering`)
|
| 21 |
|
|
|
|
|
|
|
| 22 |
Multi-source attention sequence-to-sequence **Textual Echo Cancellation (TEC)** model trained on 24 kHz **LibriTTS** user speech mixed at 0 dB SNR with reverberant **LJ Speech** (single-speaker TTS interference). Takes the noisy/reverberant microphone spectrogram (`SpeechEncoderV1`) and the lightweight TTS source transcript (`TtsEncoderV2`, < 0.1 KB side input) to reconstruct the clean user speech spectrogram.
|
| 23 |
|
| 24 |
- **GitHub Repository**: [https://github.com/wq2012/tec](https://github.com/wq2012/tec)
|
| 25 |
-
- **PyPI Package**: [`textual-echo-cancellation`](https://pypi.org/project/textual-echo-cancellation/)
|
|
|
|
| 26 |
- **Paper**: [Textual Echo Cancellation (IEEE SLT 2021, arXiv:2008.06006v4)](https://arxiv.org/pdf/2008.06006)
|
| 27 |
- **Audio Demo Page**: [https://google.github.io/speaker-id/publications/TEC/](https://google.github.io/speaker-id/publications/TEC/)
|
| 28 |
|
| 29 |
-
> **Open-Source Reproduction Notice**: This pretrained model was trained using the standalone open-source reproduction library ([`wq2012/tec`](https://github.com/wq2012/tec)) built on [`lingvo`](https://github.com/tensorflow/lingvo) and `tensorflow`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
---
|
| 32 |
|
| 33 |
## Model Performance
|
| 34 |
|
| 35 |
-
### 1. Open-Source Reproduction Evaluation (`TecSingleInterfering`)
|
| 36 |
|
| 37 |
-
Evaluated on 24 kHz **LibriTTS** (`test-clean`, `test-other`
|
| 38 |
|
| 39 |
-
| Metric | `test-clean` | `test-other` |Paper Reference (`TEC (proposed)`) |
|
| 40 |
| :--- | :---: | :---: | :---: |
|
| 41 |
-
| **WER (%) β** | **
|
| 42 |
-
| **MCD (dB) β** | **
|
| 43 |
-
| **Side Input Size (KB) β** | **0.
|
| 44 |
-
| **
|
| 45 |
-
|
| 46 |
-
### 2. Full Comparison Across All Pretrained Models & Baselines
|
| 47 |
-
|
| 48 |
-
| Condition | Method | Hugging Face Model | WER (%) test-clean β | WER (%) test-other β | MCD (dB) test-clean β | MCD (dB) test-other β | Side Input test-clean (KB) β |
|
| 49 |
-
| :--- | :--- | :--- | :---: | :---: | :---: | :---: | :---: |
|
| 50 |
-
| **Single interfering voice** *(LibriTTS + LJSpeech)* | `GroundTruth` | β | 3.
|
| 51 |
-
| | `MicrophoneSignal` | β |
|
| 52 |
-
| | `NlmsAec` (AEC-NLMS) | β |
|
| 53 |
-
| | `NoSideInputSingleInterfering` | [`wq2012/vanilla_seq2seq_single_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_single_interfering) |
|
| 54 |
-
| | `AecSingleInterfering` | [`wq2012/aec_single_interfering`](https://huggingface.co/wq2012/aec_single_interfering) |
|
| 55 |
-
| | **`TecSingleInterfering`** | **[`wq2012/tec_single_interfering`](https://huggingface.co/wq2012/tec_single_interfering)** | **
|
| 56 |
-
| **Multiple interfering voices** *(LibriTTS + VCTK)* | `GroundTruth` | β |
|
| 57 |
-
| | `MicrophoneSignal` | β |
|
| 58 |
-
| | `NlmsAec` (AEC-NLMS) | β |
|
| 59 |
-
| | `NoSideInputMultiInterfering` | [`wq2012/vanilla_seq2seq_multi_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_multi_interfering) |
|
| 60 |
-
| | `AecMultiInterfering` | [`wq2012/aec_multi_interfering`](https://huggingface.co/wq2012/aec_multi_interfering) |
|
| 61 |
-
| | **`TecMultiInterfering`** | **[`wq2012/tec_multi_interfering`](https://huggingface.co/wq2012/tec_multi_interfering)** | **
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
---
|
| 64 |
|
| 65 |
## Files in This Repository
|
| 66 |
|
| 67 |
-
- `best.ckpt.data-00000-of-00001`, `best.ckpt.index`, `best.ckpt.meta`, `checkpoint`: TensorFlow / Lingvo checkpoint for `TecSingleInterfering`.
|
| 68 |
-
- `model.tflite`: Dynamic-range quantized TensorFlow Lite (`.tflite`) FlatBuffer model for
|
| 69 |
-
- `evaluation_metrics.json`: Verified evaluation results (`test-clean` and `test-other`) for `TecSingleInterfering`.
|
| 70 |
|
| 71 |
---
|
| 72 |
|
|
@@ -120,27 +155,30 @@ print("Enhanced log-Mel spectrogram shape:", result["predicted_mel"].shape)
|
|
| 120 |
|
| 121 |
### 5. On-Device Inference with Quantized TFLite (`model.tflite`)
|
| 122 |
|
|
|
|
|
|
|
| 123 |
```python
|
| 124 |
import os
|
| 125 |
import numpy as np
|
| 126 |
-
import tensorflow as tf
|
| 127 |
from huggingface_hub import snapshot_download
|
|
|
|
| 128 |
|
| 129 |
model_dir = snapshot_download(repo_id="wq2012/tec_single_interfering")
|
| 130 |
tflite_path = os.path.join(model_dir, "model.tflite")
|
| 131 |
|
| 132 |
-
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
-
|
| 136 |
-
interpreter.set_tensor(
|
| 137 |
-
detail["index"], np.zeros(detail["shape"], dtype=detail["dtype"])
|
| 138 |
-
)
|
| 139 |
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
enhanced_mel = interpreter.get_tensor(output_details[0]["index"])
|
| 143 |
-
print("TFLite predicted log-Mel shape:", enhanced_mel.shape)
|
| 144 |
```
|
| 145 |
|
| 146 |
---
|
|
|
|
| 19 |
|
| 20 |
# Textual Echo Cancellation (TEC) β Single Interfering Voice (`TecSingleInterfering`)
|
| 21 |
|
| 22 |
+
**This is not an officially supported Google product.**
|
| 23 |
+
|
| 24 |
Multi-source attention sequence-to-sequence **Textual Echo Cancellation (TEC)** model trained on 24 kHz **LibriTTS** user speech mixed at 0 dB SNR with reverberant **LJ Speech** (single-speaker TTS interference). Takes the noisy/reverberant microphone spectrogram (`SpeechEncoderV1`) and the lightweight TTS source transcript (`TtsEncoderV2`, < 0.1 KB side input) to reconstruct the clean user speech spectrogram.
|
| 25 |
|
| 26 |
- **GitHub Repository**: [https://github.com/wq2012/tec](https://github.com/wq2012/tec)
|
| 27 |
+
- **PyPI Package**: [`textual-echo-cancellation` (v0.2.0)](https://pypi.org/project/textual-echo-cancellation/)
|
| 28 |
+
- **Interactive Hugging Face Space Demo**: [https://huggingface.co/spaces/wq2012/tec](https://huggingface.co/spaces/wq2012/tec)
|
| 29 |
- **Paper**: [Textual Echo Cancellation (IEEE SLT 2021, arXiv:2008.06006v4)](https://arxiv.org/pdf/2008.06006)
|
| 30 |
- **Audio Demo Page**: [https://google.github.io/speaker-id/publications/TEC/](https://google.github.io/speaker-id/publications/TEC/)
|
| 31 |
|
| 32 |
+
> **Open-Source Reproduction Notice**: This pretrained model was trained using the standalone open-source reproduction library ([`wq2012/tec`](https://github.com/wq2012/tec)) built on [`lingvo`](https://github.com/tensorflow/lingvo) and `tensorflow`. The original IEEE SLT 2021 paper was conducted using Google's internal codebase and 281k-utterance internal LibriTTS + TTS datasets rather than this open-source reproduction.
|
| 33 |
+
|
| 34 |
+
---
|
| 35 |
+
|
| 36 |
+
## Training Configuration
|
| 37 |
+
|
| 38 |
+
- **Condition**: Single interfering voice (LibriTTS + LJ Speech)
|
| 39 |
+
- **Dataset Splits**: 400 training utterances (`train`), 100 validation utterances (`dev`), 100 `test-clean` utterances, and 100 `test-other` utterances at 24 kHz mixed at 0 dB SNR with synthetic image-method room impulse responses (RT60 = 0.25 s).
|
| 40 |
+
- **Architecture**: Speech encoder (`SpeechEncoderV1`: 2Γ Conv2D + 4Γ Bi-LSTM + 1Γ Bi-CLSTM with stride `(2, 2)`), text encoder (`TtsEncoderV2`: 98-symbol character vocabulary `VOCAB_SIZE = 98`, 3Γ Conv1D + 1Γ Bi-LSTM, for TEC models), multi-source additive location-sensitive + content attention decoder (`SpeechEnhancementDecoderV1`: 1Γ autoregressive ZoneOut LSTM + 2Γ post-attention LSTM + 5Γ5 ConvTranspose2D + 2-layer Highway Postnet).
|
| 41 |
+
- **Trainable Parameters**: `3,962,728`
|
| 42 |
+
- **Checkpoint Selection**: Validation-loss early stopping (`best.ckpt` selected on the 100-utterance `dev` split over 500 training steps with batch size 8 and Adam `lr = 1e-3`).
|
| 43 |
|
| 44 |
---
|
| 45 |
|
| 46 |
## Model Performance
|
| 47 |
|
| 48 |
+
### 1. Open-Source Reproduction Evaluation (`TecSingleInterfering`, N = 100 mixtures per split)
|
| 49 |
|
| 50 |
+
Evaluated on 24 kHz **LibriTTS** (`test-clean`: N = 100 mixtures, 1,041 reference words; `test-other`: N = 100 mixtures, 1,039 reference words) mixed at 0 dB SNR under the **Single interfering voice (LibriTTS + LJ Speech)** condition, using `Qwen3-ASR-0.6B-F16` via `audio.cpp` for ASR WER scoring and 13-MFCC Dynamic Time Warping for MCD (with 10,000-resample non-parametric bootstrap 95% confidence intervals):
|
| 51 |
|
| 52 |
+
| Metric | `test-clean` (N = 100) | `test-other` (N = 100) | Paper Reference (`TEC (proposed)`) |
|
| 53 |
| :--- | :---: | :---: | :---: |
|
| 54 |
+
| **WER (%) β** | **64.07%** (667/1041, 95% CI [56.32, 72.33]) | **85.37%** (887/1039, 95% CI [78.48, 92.38]) | 15.5% / 39.8% |
|
| 55 |
+
| **MCD (dB) β** | **7.99 dB** (95% CI [7.75, 8.24]) | **8.60 dB** (95% CI [8.26, 8.96]) | 7.51 dB / 8.54 dB |
|
| 56 |
+
| **Side Input Size (KB) β** | **0.059 KB** (padded: 0.059 KB) | **0.058 KB** (padded: 0.058 KB) | 0.10 KB |
|
| 57 |
+
| **Complexity (GFLOPS) β** | **3.71 GFLOPS** | **3.50 GFLOPS** | 7.27 GFLOPS (401 frames) |
|
| 58 |
+
|
| 59 |
+
### 2. Full Comparison Across All Pretrained Models & Baselines (N = 100 per split)
|
| 60 |
+
|
| 61 |
+
| Condition | Method | Hugging Face Model | WER (%) test-clean β | WER (%) test-other β | MCD (dB) test-clean β | MCD (dB) test-other β | Side Input test-clean (KB) β | Avg Complexity (GFLOPS) β |
|
| 62 |
+
| :--- | :--- | :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
| 63 |
+
| **Single interfering voice** *(LibriTTS + LJSpeech)* | `GroundTruth` | β | 2.59 [1.54, 3.79] | 6.16 [4.07, 8.47] | 0.00 | 0.00 | 0.000 | 0.00 |
|
| 64 |
+
| | `MicrophoneSignal` | β | 80.79 [72.97, 89.04] | 91.15 [84.42, 98.09] | 8.93 [8.62, 9.24] | 9.56 [9.18, 9.93] | 0.000 | 0.00 |
|
| 65 |
+
| | `NlmsAec` (AEC-NLMS) | β | 70.32 [61.76, 79.26] | 87.49 [79.59, 95.49] | 8.76 [8.46, 9.07] | 9.41 [9.04, 9.79] | 189.494 | 0.05 |
|
| 66 |
+
| | `NoSideInputSingleInterfering` | [`wq2012/vanilla_seq2seq_single_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_single_interfering) | 73.10 [65.02, 81.44] | 86.81 [79.79, 93.88] | 8.08 [7.84, 8.33] | 8.81 [8.45, 9.17] | 0.000 | 3.35 |
|
| 67 |
+
| | `AecSingleInterfering` | [`wq2012/aec_single_interfering`](https://huggingface.co/wq2012/aec_single_interfering) | 8.17 [6.06, 10.42] | 19.35 [15.23, 23.96] | 5.83 [5.59, 6.07] | 6.20 [5.89, 6.53] | 189.494 | 5.11 |
|
| 68 |
+
| | **`TecSingleInterfering`** | **[`wq2012/tec_single_interfering`](https://huggingface.co/wq2012/tec_single_interfering)** | **64.07 [56.32, 72.33]** | **85.37 [78.48, 92.38]** | **7.99 [7.75, 8.24]** | **8.60 [8.26, 8.96]** | **0.059** | **3.71** |
|
| 69 |
+
| **Multiple interfering voices** *(LibriTTS + VCTK)* | `GroundTruth` | β | 2.59 [1.54, 3.79] | 6.35 [4.22, 8.67] | 0.00 | 0.00 | 0.000 | 0.00 |
|
| 70 |
+
| | `MicrophoneSignal` | β | 83.67 [75.45, 91.89] | 91.72 [85.43, 98.27] | 8.07 [7.86, 8.29] | 8.35 [8.06, 8.65] | 0.000 | 0.00 |
|
| 71 |
+
| | `NlmsAec` (AEC-NLMS) | β | 75.02 [66.40, 83.62] | 86.72 [79.65, 94.04] | 7.85 [7.65, 8.06] | 8.17 [7.88, 8.47] | 195.914 | 0.05 |
|
| 72 |
+
| | `NoSideInputMultiInterfering` | [`wq2012/vanilla_seq2seq_multi_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_multi_interfering) | 77.33 [67.79, 86.82] | 84.79 [77.53, 91.94] | 7.58 [7.36, 7.80] | 7.97 [7.65, 8.30] | 0.000 | 3.46 |
|
| 73 |
+
| | `AecMultiInterfering` | [`wq2012/aec_multi_interfering`](https://huggingface.co/wq2012/aec_multi_interfering) | 9.32 [6.42, 12.54] | 21.56 [16.63, 26.85] | 5.08 [4.92, 5.25] | 5.32 [5.07, 5.57] | 195.914 | 5.29 |
|
| 74 |
+
| | **`TecMultiInterfering`** | **[`wq2012/tec_multi_interfering`](https://huggingface.co/wq2012/tec_multi_interfering)** | **65.90 [57.38, 74.18]** | **78.25 [71.17, 85.23]** | **7.19 [7.02, 7.36]** | **7.53 [7.26, 7.82]** | **0.062** | **3.84** |
|
| 75 |
+
|
| 76 |
+
### 3. Text-Content Sensitivity Ablation (N = 100 per split)
|
| 77 |
+
|
| 78 |
+
Verifies that `TtsEncoderV2` actively exploits the semantic and phonetic content of the interfering TTS transcript rather than acting as a content-independent bias:
|
| 79 |
+
|
| 80 |
+
| Split | Side-Input Condition | WER (%) β | MCD (dB) β | ΞWER vs. `matched` | Paired p-value (Bootstrap / Wilcoxon) |
|
| 81 |
+
| :--- | :--- | :---: | :---: | :---: | :---: |
|
| 82 |
+
| `single_test_clean` (`TecSingleInterfering`) | **`matched` (true TTS transcript)** | **64.07%** | **7.99 dB** | β | β |
|
| 83 |
+
| | `shuffled` (mismatched transcript) | 71.66% | 8.06 dB | +7.59% | p < 0.0001 / p = 0.00099 |
|
| 84 |
+
| | `empty` (no text / `Vanilla-Seq2seq`) | 73.10% | 8.08 dB | +9.03% | p < 0.0001 / p = 0.00014 |
|
| 85 |
+
| `multi_test_clean` (`TecMultiInterfering`) | **`matched` (true TTS transcript)** | **65.90%** | **7.19 dB** | β | β |
|
| 86 |
+
| | `shuffled` (mismatched transcript) | 75.31% | 7.46 dB | +9.41% | p < 0.0001 / p = 0.00017 |
|
| 87 |
+
| | `empty` (no text / `Vanilla-Seq2seq`) | 77.33% | 7.58 dB | +11.43% | p < 0.0001 / p = 0.00012 |
|
| 88 |
+
|
| 89 |
+
### 4. Input SNR Ablation on `single_test_clean` (N = 100 mixtures per SNR)
|
| 90 |
+
|
| 91 |
+
| Input SNR | `MicrophoneSignal` WER / MCD | `NlmsAec` WER / MCD | `Vanilla-Seq2seq` WER / MCD | **`TecSingleInterfering` WER / MCD** | `AecSingleInterfering` WER / MCD |
|
| 92 |
+
| :---: | :---: | :---: | :---: | :---: | :---: |
|
| 93 |
+
| **+5 dB** | 34.01% / 7.89 dB | 25.55% / 7.68 dB | 24.88% / 7.01 dB | **21.81% / 6.92 dB** | 6.05% / 5.33 dB |
|
| 94 |
+
| **0 dB** | 80.79% / 8.93 dB | 70.32% / 8.76 dB | 73.10% / 8.08 dB | **64.07% / 7.99 dB** | 8.17% / 5.83 dB |
|
| 95 |
+
| **-5 dB** | 104.80% / 9.91 dB | 103.55% / 9.78 dB | 103.55% / 9.27 dB | **102.50% / 9.20 dB** | 33.14% / 6.92 dB |
|
| 96 |
+
| **-10 dB** | 107.88% / 10.75 dB | 107.78% / 10.65 dB | 106.82% / 10.19 dB | **106.05% / 10.11 dB** | 88.86% / 8.14 dB |
|
| 97 |
|
| 98 |
---
|
| 99 |
|
| 100 |
## Files in This Repository
|
| 101 |
|
| 102 |
+
- `best.ckpt.data-00000-of-00001`, `best.ckpt.index`, `best.ckpt.meta`, `checkpoint`: TensorFlow / Lingvo checkpoint for `TecSingleInterfering` (selected by minimum validation loss on `dev`).
|
| 103 |
+
- `model.tflite`: Dynamic-range quantized TensorFlow Lite (`.tflite`) FlatBuffer model for `TecSingleInterfering` (requires TFLite Flex `SELECT_TF_OPS` runtime for dynamic RNN `TensorList` operations).
|
| 104 |
+
- `evaluation_metrics.json`: Verified N = 100 evaluation results (`test-clean` and `test-other`), 95% bootstrap confidence intervals, paired significance tests, and ablations for `TecSingleInterfering`.
|
| 105 |
|
| 106 |
---
|
| 107 |
|
|
|
|
| 155 |
|
| 156 |
### 5. On-Device Inference with Quantized TFLite (`model.tflite`)
|
| 157 |
|
| 158 |
+
Note: Because the multi-source attention decoder uses dynamic `tf.while_loop` / `TensorList` operations, `model.tflite` is exported with `tf.lite.OpsSet.SELECT_TF_OPS` (Flex delegate) enabled.
|
| 159 |
+
|
| 160 |
```python
|
| 161 |
import os
|
| 162 |
import numpy as np
|
|
|
|
| 163 |
from huggingface_hub import snapshot_download
|
| 164 |
+
from tec import inference
|
| 165 |
|
| 166 |
model_dir = snapshot_download(repo_id="wq2012/tec_single_interfering")
|
| 167 |
tflite_path = os.path.join(model_dir, "model.tflite")
|
| 168 |
|
| 169 |
+
dummy_mel = np.zeros((100, 128), dtype=np.float32)
|
| 170 |
+
enhanced_mel = inference.run_tflite_inference(
|
| 171 |
+
tflite_path=tflite_path,
|
| 172 |
+
mixed_mel=dummy_mel,
|
| 173 |
+
interfering_text="currently in mountain view it is 72 degrees",
|
| 174 |
+
)
|
| 175 |
+
print("TFLite predicted log-Mel shape:", enhanced_mel.shape)
|
| 176 |
+
```
|
| 177 |
|
| 178 |
+
Expected console output:
|
|
|
|
|
|
|
|
|
|
| 179 |
|
| 180 |
+
```text
|
| 181 |
+
TFLite predicted log-Mel shape: (1, 100, 128)
|
|
|
|
|
|
|
| 182 |
```
|
| 183 |
|
| 184 |
---
|
best.ckpt.data-00000-of-00001
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9b70c8e4774c99f56653f8bcc264155322ec87a827134135c05fe05495710e9b
|
| 3 |
+
size 218508068
|
best.ckpt.index
CHANGED
|
Binary files a/best.ckpt.index and b/best.ckpt.index differ
|
|
|
best.ckpt.meta
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:29f418564393534f69aa6825f8ac0b6682f64b98ac0f7c6549a5825b8b1a1ea3
|
| 3 |
+
size 8856377
|
evaluation_metrics.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model.tflite
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:64c04ead4bf71063d479036e791fdaa57482e110ee218a35db4b53a81ec654cb
|
| 3 |
+
size 73675180
|