wq2012 commited on
Commit
52182d6
Β·
1 Parent(s): 2ff9383

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 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`. It does not use Google's proprietary internal codebase or internal training data infrastructure.
 
 
 
 
 
 
 
 
 
 
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`) mixed at 0 dB SNR with synthetic room impulse responses (RT60 = 0.25 s) 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:
38
 
39
- | Metric | `test-clean` | `test-other` |Paper Reference (`TEC (proposed)`) |
40
  | :--- | :---: | :---: | :---: |
41
- | **WER (%) ↓** | **21.61%** (43/199) | **46.89%** (83/177) | 15.5% / 39.8% |
42
- | **MCD (dB) ↓** | **8.24 dB** | **9.28 dB** | 7.51 dB / 8.54 dB |
43
- | **Side Input Size (KB) ↓** | **0.076 KB** | **0.068 KB** | 0.10 KB |
44
- | **Computational Complexity ↓** | **7.27 GFLOPS** | **7.27 GFLOPS** | 7.27 GFLOPS |
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.52 | 6.78 | 0.00 | 0.00 | 0.000 |
51
- | | `MicrophoneSignal` | β€” | 90.45 | 114.12 | 12.86 | 14.61 | 0.000 |
52
- | | `NlmsAec` (AEC-NLMS) | β€” | 88.44 | 107.34 | 12.80 | 14.48 | 243.465 |
53
- | | `NoSideInputSingleInterfering` | [`wq2012/vanilla_seq2seq_single_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_single_interfering) | 45.23 | 91.53 | 9.58 | 11.34 | 0.000 |
54
- | | `AecSingleInterfering` | [`wq2012/aec_single_interfering`](https://huggingface.co/wq2012/aec_single_interfering) | 12.06 | 23.16 | 8.85 | 9.86 | 243.465 |
55
- | | **`TecSingleInterfering`** | **[`wq2012/tec_single_interfering`](https://huggingface.co/wq2012/tec_single_interfering)** | **21.61** | **46.89** | **8.24** | **9.28** | **0.076** |
56
- | **Multiple interfering voices** *(LibriTTS + VCTK)* | `GroundTruth` | β€” | 5.03 | 7.82 | 0.00 | 0.00 | 0.000 |
57
- | | `MicrophoneSignal` | β€” | 34.17 | 48.97 | 7.67 | 7.70 | 0.000 |
58
- | | `NlmsAec` (AEC-NLMS) | β€” | 28.64 | 34.98 | 7.92 | 8.40 | 186.922 |
59
- | | `NoSideInputMultiInterfering` | [`wq2012/vanilla_seq2seq_multi_interfering`](https://huggingface.co/wq2012/vanilla_seq2seq_multi_interfering) | 31.16 | 42.39 | 7.93 | 8.72 | 0.000 |
60
- | | `AecMultiInterfering` | [`wq2012/aec_multi_interfering`](https://huggingface.co/wq2012/aec_multi_interfering) | 8.54 | 22.22 | 7.80 | 7.88 | 186.922 |
61
- | | **`TecMultiInterfering`** | **[`wq2012/tec_multi_interfering`](https://huggingface.co/wq2012/tec_multi_interfering)** | **26.63** | **45.27** | **7.96** | **8.40** | **0.037** |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 on-device inference.
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
- interpreter = tf.lite.Interpreter(model_path=tflite_path)
133
- interpreter.allocate_tensors()
 
 
 
 
 
 
134
 
135
- for detail in interpreter.get_input_details():
136
- interpreter.set_tensor(
137
- detail["index"], np.zeros(detail["shape"], dtype=detail["dtype"])
138
- )
139
 
140
- interpreter.invoke()
141
- output_details = interpreter.get_output_details()
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:8adfb75321640c66f6e4344e6754743171675a6b7994210d04512d61dde4d56a
3
- size 217680676
 
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:5ea8dfba4a6a390e6d9d49e67bffaaa4885dd022f35d1d9cb0c4b12a3d389eb8
3
- size 5482187
 
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:5324b5e776335d0ed1c5098445c2dd26e3c502d6210df684a6c7fa70d39b8b5d
3
- size 72746680
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:64c04ead4bf71063d479036e791fdaa57482e110ee218a35db4b53a81ec654cb
3
+ size 73675180