Freightliner
/

Freightliner szuweifu commited on
Commit
01f74f7
·
0 Parent(s):

Duplicate from nvidia/RE-USE

Browse files

Co-authored-by: Szu-Wei Fu <szuweifu@users.noreply.huggingface.co>

.gitattributes ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ long_noisy_audio/mic_test2.wav filter=lfs diff=lfs merge=lfs -text
37
+ noisy_audio/mic_test2.wav filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,163 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: other
3
+ track_downloads: true
4
+ pipeline_tag: audio-to-audio
5
+ library_name: mamba-ssm
6
+ tags:
7
+ - universal speech enhancement
8
+ - multiple input sampling rates
9
+ - language-agnostic
10
+ ---
11
+ # **<span style="color:#76b900;">🤫 RE-USE: Multilingual Universal Speech Enhancement</span>**
12
+ # Model Overview
13
+
14
+
15
+ ## Description
16
+ In universal speech enhancement, the goal is to restore the **quality** of diverse degraded speech while preserving **fidelity**, ensuring that all other factors remain unchanged, e.g., linguistic content, speaker identity, emotion, accent, and other paralinguistic attributes. Inspired by the **distortion–perception trade-off theory**, our proposed single model achieves a good balance between these two objectives and has the following desirable properties:
17
+
18
+ - Robustness to **diverse degradations**, including additive noise, reverberation, clipping, bandwidth limitation, codec artifacts, packet loss and low-quality mics .
19
+ - Support for **multiple input sampling rates**, including 8, 16, 22.05, 24, 32, 44.1, and 48 kHz.
20
+ - Strong **language-agnostic** capability, enabling effective performance across different languages.
21
+
22
+ This model is for research and development only.
23
+
24
+ ## Usage
25
+ Directly try our [**Gradio Interactive Demo**](https://huggingface.co/spaces/nvidia/RE-USE) by uploading your noisy audio/video !!
26
+
27
+ ## Environment Setup
28
+ 1. (For **Mamba** setup)Pre-built Docker environments can be downloaded [here](https://github.com/RoyChao19477/SEMamba?tab=readme-ov-file#-docker-support) to simplify **Mamba** setup.
29
+
30
+ 2. If you need bandwidth extension:
31
+
32
+ ```bash
33
+ pip install resampy
34
+ ```
35
+ 3. Download and navigate to the HuggingFace repository:
36
+ ```
37
+ huggingface-cli download nvidia/RE-USE --local-dir ./REUSE --local-dir-use-symlinks False
38
+ cd ./REUSE
39
+ ```
40
+
41
+ ## Inference
42
+ Follow the simple steps below to generate enhanced speech using our model:
43
+ 1. Place your noisy speech files in the folder `noisy_audio/`
44
+ 2. Run the following command:
45
+ ```bash
46
+ sh inference.sh
47
+ ```
48
+ 3. The enhanced speech files will be saved in `enhanced_audio/`.
49
+
50
+ That's all !
51
+
52
+ **Note:**
53
+
54
+ a. You can enable bandwidth extension by setting the target bandwidth using the `BWE argument` in the script.
55
+
56
+ ---
57
+
58
+ If your noisy speech files are **long and may cause GPU out-of-memory (OOM)** errors, please use the following procedure instead:
59
+ 1. Place your long noisy speech files in the folder `long_noisy_audio/`
60
+ 2. Run the following command:
61
+ ```bash
62
+ sh inference_chunk.sh
63
+ ```
64
+ 3. The enhanced speech files will be saved in `Long_enhanced_audio/`.
65
+
66
+ **Note:**
67
+
68
+ a. You can enable bandwidth extension by setting the target bandwidth using the `BWE argument` in the script.
69
+
70
+ b. You can also configure the `chunk_size_in_seconds` and `hop_length_portion` directly in the script.
71
+
72
+ ---
73
+
74
+ ## License/Terms of Use
75
+ This model is released under the [NVIDIA One-Way Noncommercial License (NSCLv1)](https://github.com/NVlabs/HMAR/blob/main/LICENSE).
76
+
77
+ ## Deployment Geography
78
+ Global.
79
+
80
+ ## Use Case
81
+ Researchers and general users can use this model to enhance the quality of their speech data.
82
+
83
+ ## Release Date
84
+ Hugging Face 2026/03/18
85
+
86
+ ## References
87
+ [1] [Rethinking Training Targets, Architectures and Data Quality for Universal Speech Enhancement](https://arxiv.org/abs/2603.02641), 2025.
88
+ (Note: The released model checkpoint differs from the one reported in the paper. It incorporates additional degradation types (e.g., microphone response and more codecs) and is fine-tuned on a smaller, high-quality clean subset.)
89
+
90
+ ## Model Architecture
91
+ **Architecture Type:** Convolutional encoder, Convolutional decoder, and Mamba for time–frequency modeling <br>
92
+ **Network Architecture:** Bi-directional Mamba with 30 layers <br>
93
+ **Number of model parameters:** 9.6M <br>
94
+
95
+ ## Input
96
+ Input Type(s): Audio <br>
97
+ Input Format(s): .wav files <br>
98
+ Input Parameters: One-Dimensional (1D) <br>
99
+ Other Properties Related to Input: 8000 Hz - 48000 Hz Mono-channel Audio <br>
100
+
101
+ ## Output
102
+ Output Type(s): Audio <br>
103
+ Output Format: .wav files <br>
104
+ Output Parameters: One-Dimensional (1D) <br>
105
+ Other Properties Related to Output: 8000 Hz - 48000 Hz Mono-channel Audio <br>
106
+
107
+ Our AI models are designed and/or optimized to run on NVIDIA GPU-accelerated systems. By leveraging NVIDIA’s hardware (e.g. GPU cores) and software frameworks (e.g., CUDA libraries), the model achieves faster training and inference times compared to CPU-only solutions.
108
+
109
+ ## Software Integration
110
+ **Runtime Engine(s):**
111
+ * Not Applicable (N/A)
112
+
113
+ **Supported Hardware Microarchitecture Compatibility:**
114
+ * NVIDIA Ampere (A100)
115
+
116
+ **Preferred Operating System(s):**
117
+ * Linux
118
+
119
+ The integration of foundation and fine-tuned models into AI systems requires additional testing using use-case-specific data to ensure safe and effective deployment. Following the V-model methodology, iterative testing and validation at both unit and system levels are essential to mitigate risks, meet technical and functional requirements, and ensure compliance with safety and ethical standards before deployment.
120
+
121
+ ## Model Version(s)
122
+ Current version: 30USEMamba_peak+GAN_tel_mic_1134k
123
+
124
+ ## Training Datasets
125
+ **Data Modality:**
126
+ Audio
127
+
128
+ **Audio Training Data Size:**
129
+ Less than 10,000 Hours
130
+
131
+ * [LibriVox data from DNS5 challenge (EN)](https://github.com/microsoft/DNS-Challenge/tree/master) (~350 hours of speech data)
132
+ * [LibriTTS (EN)](https://openslr.org/60/) (~200 hours of speech data)
133
+ * [VCTK (EN)](https://datashare.ed.ac.uk/handle/10283/3443) (~80 hours of speech data)
134
+ * [WSJ (EN)](https://catalog.ldc.upenn.edu/LDC93S6A) (~85 hours of speech data)
135
+ * [EARS (EN)](https://sp-uhh.github.io/ears_dataset/) (~100 hours of speech data)
136
+ * [Multilingual Librispeech (De, En, Es, Fr)](https://www.openslr.org/94/) (~450 hours of speech data)
137
+ * [CommonVoice 19.0 (De, En, Es, Fr, zh-CN)](https://huggingface.co/datasets/fsicoli/common_voice_19_0) (~1300 hours of speech data)
138
+ * [Audioset+FreeSound noise in DNS5 challenge](https://github.com/microsoft/DNS-Challenge/tree/master) (~180 hours of noise data)
139
+ * [WHAM! Noise](http://wham.whisper.ai/) (~80 hours of noise data)
140
+ * [FSD50K (human voice filtered)](https://huggingface.co/datasets/Fhrozen/FSD50k) (~100 hours of non-speech data)
141
+ * [(Part of) Free Music Archive (medium)](https://github.com/mdeff/fma) (~200 hours of non-speech data)
142
+ * [Simulated RIRs from DNS5 challenge](https://github.com/microsoft/DNS-Challenge/tree/master) (~60k samples of room impulse response)
143
+ * [MicIRP](https://micirp.blogspot.com/p/about-micirp.html) (~70 samples of microphone impulse response)
144
+
145
+ ## Inference
146
+ **Acceleration Engine:** None <br>
147
+ **Test Hardware:** NVIDIA A100
148
+
149
+ ## Ethical Considerations
150
+ NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. When downloaded or used in accordance with our terms of service, developers should work with their internal model team to ensure this model meets requirements for the relevant industry and use case and addresses unforeseen product misuse.
151
+ Please report model quality, risk, security vulnerabilities or NVIDIA AI Concerns [here](https://app.intigriti.com/programs/nvidia/nvidiavdp/detail).
152
+
153
+ ## Citation
154
+ Please consider to cite our paper and this framework, if they are helpful in your research.
155
+
156
+ ```bibtex
157
+ @article{fu2026rethinking,
158
+ title={Rethinking Training Targets, Architectures and Data Quality for Universal Speech Enhancement},
159
+ author={Fu, Szu-Wei and Chao, Rong and Yang, Xuesong and Huang, Sung-Feng and Zezario, Ryandhimas E and Nasretdinov, Rauf and Juki{\'c}, Ante and Tsao, Yu and Wang, Yu-Chiang Frank},
160
+ journal={arXiv preprint arXiv:2603.02641},
161
+ year={2026}
162
+ }
163
+ ```
config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "env_setting": {
3
+ "checkpoint_interval": 5000,
4
+ "dist_cfg": {
5
+ "dist_backend": "nccl",
6
+ "dist_url": "tcp://localhost:19478",
7
+ "world_size": 1
8
+ },
9
+ "num_gpus": 8,
10
+ "num_workers": 20,
11
+ "persistent_workers": true,
12
+ "pin_memory": true,
13
+ "prefetch_factor": 8,
14
+ "seed": 1234,
15
+ "stdout_interval": 5000,
16
+ "validation_interval": 5000
17
+ },
18
+ "model_cfg": {
19
+ "beta": 2.0,
20
+ "compress_factor": "relu_log1p",
21
+ "d_conv": 4,
22
+ "d_state": 16,
23
+ "expand": 4,
24
+ "hid_feature": 64,
25
+ "inner_mamba_nlayer": 1,
26
+ "input_channel": 2,
27
+ "mapping": true,
28
+ "nonlinear": "None",
29
+ "norm_epsilon": 1e-05,
30
+ "num_tfmamba": 30,
31
+ "output_channel": 1
32
+ },
33
+ "stft_cfg": {
34
+ "hop_size": 40,
35
+ "n_fft": 320,
36
+ "sampling_rate": 8000,
37
+ "sfi": true,
38
+ "win_size": 320
39
+ }
40
+ }
inference.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import os
10
+ import argparse
11
+ import torch
12
+ import torchaudio
13
+ import torch.nn as nn
14
+ import librosa
15
+ from models.stfts import mag_phase_stft, mag_phase_istft
16
+ from models.generator_SEMamba_time_d4 import SEMamba
17
+ from utils.util import load_config, pad_or_trim_to_match
18
+ from huggingface_hub import hf_hub_download
19
+ RELU = nn.ReLU()
20
+
21
+ config_path = hf_hub_download(repo_id="nvidia/RE-USE", filename="config.json")
22
+
23
+ def get_filepaths(directory, file_type=None):
24
+ file_paths = [] # List which will store all of the full filepaths.
25
+ # Walk the tree.
26
+ for root, directories, files in os.walk(directory):
27
+ for filename in files:
28
+ # Join the two strings in order to form the full filepath.
29
+ filepath = os.path.join(root, filename)
30
+ if file_type is not None:
31
+ if filepath.split('.')[-1] == file_type:
32
+ file_paths.append(filepath) # Add it to the list.
33
+ else:
34
+ file_paths.append(filepath) # Add it to the list.
35
+ return file_paths # Self-explanatory.
36
+
37
+ def make_even(value):
38
+ value = int(round(value))
39
+ return value if value % 2 == 0 else value + 1
40
+
41
+ def inference(args, device):
42
+ cfg = load_config(args.config)
43
+ n_fft, hop_size, win_size = cfg['stft_cfg']['n_fft'], cfg['stft_cfg']['hop_size'], cfg['stft_cfg']['win_size']
44
+ compress_factor = cfg['model_cfg']['compress_factor']
45
+ sampling_rate = cfg['stft_cfg']['sampling_rate']
46
+
47
+ SE_model = SEMamba.from_pretrained("nvidia/RE-USE", cfg=cfg).to(device)
48
+ SE_model.eval()
49
+
50
+ os.makedirs(args.output_folder, exist_ok=True)
51
+ with torch.no_grad():
52
+ for i, fname in enumerate(get_filepaths(args.input_folder)):
53
+ print(fname)
54
+ try:
55
+ os.makedirs(args.output_folder + fname[0:fname.rfind('/')].replace(args.input_folder,''), exist_ok=True)
56
+ noisy_wav, noisy_sr = torchaudio.load(fname)
57
+ except Exception as e:
58
+ print(f"Warning: cannot read {fname}, skipping. ({e})")
59
+ continue
60
+
61
+ if args.BWE is not None:
62
+ opts = {"res_type": "kaiser_best"}
63
+ noisy_wav = librosa.resample(noisy_wav.cpu().numpy(), orig_sr=noisy_sr, target_sr=int(args.BWE), **opts)
64
+ noisy_sr = int(args.BWE)
65
+
66
+ noisy_wav = torch.FloatTensor(noisy_wav).to(device)
67
+ n_fft_scaled = make_even(n_fft * noisy_sr // sampling_rate)
68
+ hop_size_scaled = make_even(hop_size * noisy_sr // sampling_rate)
69
+ win_size_scaled = make_even(win_size * noisy_sr // sampling_rate)
70
+
71
+ noisy_mag, noisy_pha, noisy_com = mag_phase_stft(
72
+ noisy_wav,
73
+ n_fft=n_fft_scaled,
74
+ hop_size=hop_size_scaled,
75
+ win_size=win_size_scaled,
76
+ compress_factor=compress_factor,
77
+ center=True,
78
+ addeps=False
79
+ )
80
+ amp_g, pha_g, _ = SE_model(noisy_mag, noisy_pha)
81
+ # To remove "strange sweep artifact"
82
+ mag = torch.expm1(RELU(amp_g)) # [1, F, T]
83
+ zero_portion = torch.sum(mag==0, 1)/mag.shape[1]
84
+ amp_g[:,:,(zero_portion>0.5)[0]] = 0
85
+
86
+ audio_g = mag_phase_istft(amp_g, pha_g, n_fft_scaled, hop_size_scaled, win_size_scaled, compress_factor)
87
+ audio_g = pad_or_trim_to_match(noisy_wav.detach(), audio_g, pad_value=1e-8) # Align lengths using epsilon padding
88
+ assert audio_g.shape == noisy_wav.shape, audio_g.shape
89
+
90
+ output_file = os.path.join(args.output_folder + fname.replace(args.input_folder,'').split('.')[0]+'.flac') # save to .flac format
91
+ torchaudio.save(output_file, audio_g.cpu(), noisy_sr)
92
+
93
+ def main():
94
+ print('Initializing Inference Process...')
95
+ parser = argparse.ArgumentParser()
96
+ parser.add_argument('--input_folder')
97
+ parser.add_argument('--output_folder')
98
+ parser.add_argument('--config')
99
+ parser.add_argument('--checkpoint_file', required=True)
100
+ parser.add_argument('--BWE', default=None)
101
+ args = parser.parse_args()
102
+
103
+ global device
104
+ if torch.cuda.is_available():
105
+ device = torch.device('cuda')
106
+ else:
107
+ raise RuntimeError("Currently, CPU mode is not supported.")
108
+
109
+ inference(args, device)
110
+
111
+
112
+ if __name__ == '__main__':
113
+ main()
inference.sh ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ CUDA_VISIBLE_DEVICES='0' python ./inference.py \
2
+ --input_folder ./noisy_audio \
3
+ --output_folder ./enhanced_audio \
4
+ --checkpoint_file ./exp/30x1_lr_00002_norm_05_vq_065_nfft_320_hop_40_NRIR_012_pha_0005_com_04_early_peak_GAN_tel_mic/g_01134000.pth \
5
+ --config ./recipes/USEMamba_30x1_lr_00002_norm_05_vq_065_nfft_320_hop_40_NRIR_012_pha_0005_com_04_early_001.yaml \
6
+ #--BWE 32000 \
inference_chunk.py ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import os
10
+ import argparse
11
+ import torch
12
+ import torchaudio
13
+ import torch.nn as nn
14
+ import librosa
15
+ import math
16
+ from models.stfts import mag_phase_stft, mag_phase_istft
17
+ from models.generator_SEMamba_time_d4 import SEMamba
18
+ from utils.util import load_config, pad_or_trim_to_match
19
+ from huggingface_hub import hf_hub_download
20
+
21
+ RELU = nn.ReLU()
22
+
23
+ config_path = hf_hub_download(repo_id="nvidia/RE-USE", filename="config.json")
24
+
25
+ def get_filepaths(directory, file_type=None):
26
+ file_paths = [] # List which will store all of the full filepaths.
27
+ # Walk the tree.
28
+ for root, directories, files in os.walk(directory):
29
+ for filename in files:
30
+ # Join the two strings in order to form the full filepath.
31
+ filepath = os.path.join(root, filename)
32
+ if file_type is not None:
33
+ if filepath.split('.')[-1] == file_type:
34
+ file_paths.append(filepath) # Add it to the list.
35
+ else:
36
+ file_paths.append(filepath) # Add it to the list.
37
+ return file_paths # Self-explanatory.
38
+
39
+ def make_even(value):
40
+ value = int(round(value))
41
+ return value if value % 2 == 0 else value + 1
42
+
43
+ def inference(args, device):
44
+ cfg = load_config(args.config)
45
+ n_fft, hop_size, win_size = cfg['stft_cfg']['n_fft'], cfg['stft_cfg']['hop_size'], cfg['stft_cfg']['win_size']
46
+ compress_factor = cfg['model_cfg']['compress_factor']
47
+ sampling_rate = cfg['stft_cfg']['sampling_rate']
48
+
49
+ SE_model = SEMamba.from_pretrained("nvidia/RE-USE", cfg=cfg).to(device)
50
+ SE_model.eval()
51
+
52
+ os.makedirs(args.output_folder, exist_ok=True)
53
+ with torch.no_grad():
54
+ for fname in get_filepaths(args.input_folder):
55
+ print(fname)
56
+ try:
57
+ os.makedirs(args.output_folder + fname[0:fname.rfind('/')].replace(args.input_folder,''), exist_ok=True)
58
+ Noisy_wav, noisy_sr = torchaudio.load(fname)
59
+ except Exception as e:
60
+ print(f"Warning: cannot read {fname}, skipping. ({e})")
61
+ continue
62
+
63
+ if args.BWE is not None:
64
+ opts = {"res_type": "kaiser_best"}
65
+ Noisy_wav = librosa.resample(Noisy_wav.cpu().numpy(), orig_sr=noisy_sr, target_sr=int(args.BWE), **opts)
66
+ noisy_sr = int(args.BWE)
67
+
68
+ chunk_size = int(args.chunk_size_in_seconds*noisy_sr) # (in samples)
69
+ hop_length = int(args.hop_length_portion*chunk_size) # (in samples)
70
+ window = torch.hann_window(chunk_size).to(device)
71
+
72
+ n_fft_scaled = make_even(n_fft * noisy_sr // sampling_rate)
73
+ hop_size_scaled = make_even(hop_size * noisy_sr // sampling_rate)
74
+ win_size_scaled = make_even(win_size * noisy_sr // sampling_rate)
75
+
76
+ Noisy_wav = torch.FloatTensor(Noisy_wav).to(device)
77
+ audio_enhanced = torch.zeros_like(Noisy_wav).to(device)
78
+ #norm = torch.zeros_like(Noisy_wav).to(device)
79
+ window_sum = torch.zeros_like(Noisy_wav).to(device)
80
+ for c in range(Noisy_wav.shape[0]): # for multi-channel speech
81
+ noisy_wav = Noisy_wav[c:c+1,:]
82
+ for i in range(max(1, math.ceil((noisy_wav.shape[1]-chunk_size)/hop_length)+1)):
83
+ noisy_wav_chunk = noisy_wav[:, i*hop_length : i*hop_length+chunk_size]
84
+
85
+ noisy_mag, noisy_pha, noisy_com = mag_phase_stft(
86
+ noisy_wav_chunk,
87
+ n_fft=n_fft_scaled,
88
+ hop_size=hop_size_scaled,
89
+ win_size=win_size_scaled,
90
+ compress_factor=compress_factor,
91
+ center=True,
92
+ addeps=False
93
+ )
94
+ amp_g, pha_g, _ = SE_model(noisy_mag, noisy_pha)
95
+ # To remove "strange sweep artifact"
96
+ mag = torch.expm1(RELU(amp_g)) # [1, F, T]
97
+ zero_portion = torch.sum(mag==0, 1)/mag.shape[1]
98
+ amp_g[:,:,(zero_portion>0.5)[0]] = 0
99
+
100
+ audio_g = mag_phase_istft(amp_g, pha_g, n_fft_scaled, hop_size_scaled, win_size_scaled, compress_factor)
101
+ audio_g = pad_or_trim_to_match(noisy_wav_chunk.detach(), audio_g, pad_value=1e-8) # Align lengths using epsilon padding
102
+
103
+ audio_enhanced[c:c+1,i*hop_length:i*hop_length+chunk_size] += audio_g*window[0:audio_g.shape[1]]
104
+ window_sum[c:c+1,i*hop_length:i*hop_length+chunk_size] += window[0:audio_g.shape[1]]
105
+ #norm[c:c+1,i*hop_length:i*hop_length+chunk_size] += 1.0
106
+ nonzero_indices = (window_sum > 1e-8)
107
+ audio_enhanced[:,nonzero_indices[0]] = audio_enhanced[:,nonzero_indices[0]]/window_sum[:,nonzero_indices[0]]
108
+ assert audio_enhanced.shape == Noisy_wav.shape, audio_enhanced.shape
109
+ output_file = os.path.join(args.output_folder + fname.replace(args.input_folder,'').split('.')[0]+'.flac') # save to .flac format
110
+ torchaudio.save(output_file, audio_enhanced.cpu(), noisy_sr)
111
+
112
+ def main():
113
+ print('Initializing Inference Process..')
114
+ parser = argparse.ArgumentParser()
115
+ parser.add_argument('--input_folder')
116
+ parser.add_argument('--output_folder')
117
+ parser.add_argument('--config')
118
+ parser.add_argument('--checkpoint_file')
119
+ parser.add_argument('--chunk_size_in_seconds', type=float)
120
+ parser.add_argument('--hop_length_portion', type=float)
121
+ parser.add_argument('--BWE', default=None)
122
+ args = parser.parse_args()
123
+
124
+ global device
125
+ if torch.cuda.is_available():
126
+ device = torch.device('cuda')
127
+ else:
128
+ raise RuntimeError("Currently, CPU mode is not supported.")
129
+
130
+ inference(args, device)
131
+
132
+ if __name__ == '__main__':
133
+ main()
134
+
inference_chunk.sh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ CUDA_VISIBLE_DEVICES='0' python ./inference_chunk.py \
2
+ --input_folder ./long_noisy_audio \
3
+ --output_folder ./long_enhanced_audio \
4
+ --checkpoint_file ./exp/30x1_lr_00002_norm_05_vq_065_nfft_320_hop_40_NRIR_012_pha_0005_com_04_early_peak_GAN_tel_mic/g_01134000.pth \
5
+ --config ./recipes/USEMamba_30x1_lr_00002_norm_05_vq_065_nfft_320_hop_40_NRIR_012_pha_0005_com_04_early_001.yaml \
6
+ --chunk_size_in_seconds 5\
7
+ --hop_length_portion 0.5\
8
+ #--BWE 32000 \
9
+
long_noisy_audio/mic_test2.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6433420a00163f30a339fc83a191517a82597cf2141cbd310233470e83ce0d7
3
+ size 449896
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:87a4a970ce9aa79d5d92e71899ab034defcf13d93e5e4393ec0dc7db6d4ec048
3
+ size 38592940
models/codec_module_time_d4.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import numpy as np
12
+ from einops import rearrange
13
+
14
+ def get_padding_2d(kernel_size, dilation=(1, 1)):
15
+ """
16
+ Calculate the padding size for a 2D convolutional layer.
17
+
18
+ Args:
19
+ - kernel_size (tuple): Size of the convolutional kernel (height, width).
20
+ - dilation (tuple, optional): Dilation rate of the convolution (height, width). Defaults to (1, 1).
21
+
22
+ Returns:
23
+ - tuple: Calculated padding size (height, width).
24
+ """
25
+ return (int((kernel_size[0] * dilation[0] - dilation[0]) / 2),
26
+ int((kernel_size[1] * dilation[1] - dilation[1]) / 2))
27
+
28
+ class SPConvTranspose2d(nn.Module):
29
+ def __init__(self, in_channels, out_channels, kernel_size, r=1):
30
+ super(SPConvTranspose2d, self).__init__()
31
+ self.pad1 = nn.ConstantPad2d((1, 1, 0, 0), value=0.)
32
+ self.out_channels = out_channels
33
+ self.conv = nn.Conv2d(in_channels, out_channels * r, kernel_size=kernel_size, stride=(1, 1))
34
+ self.r = r
35
+
36
+ def forward(self, x):
37
+ x = self.pad1(x)
38
+ out = self.conv(x)
39
+ batch_size, nchannels, H, W = out.shape
40
+ out = out.view((batch_size, self.r, nchannels // self.r, H, W))
41
+ out = out.permute(0, 2, 3, 4, 1)
42
+ out = out.contiguous().view((batch_size, nchannels // self.r, H, -1))
43
+ return out
44
+
45
+ class DenseBlock(nn.Module):
46
+ """
47
+ DenseBlock module consisting of multiple convolutional layers with dilation.
48
+ """
49
+ def __init__(self, cfg, kernel_size=(3, 3), depth=4):
50
+ super(DenseBlock, self).__init__()
51
+ self.cfg = cfg
52
+ self.depth = depth
53
+ self.dense_block = nn.ModuleList()
54
+ self.hid_feature = cfg['model_cfg']['hid_feature']
55
+
56
+ for i in range(depth):
57
+ dil = 2 ** i
58
+ dense_conv = nn.Sequential(
59
+ nn.Conv2d(self.hid_feature * (i + 1), self.hid_feature, kernel_size,
60
+ dilation=(dil, 1), padding=get_padding_2d(kernel_size, (dil, 1))),
61
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
62
+ nn.PReLU(self.hid_feature)
63
+ )
64
+ self.dense_block.append(dense_conv)
65
+
66
+ def forward(self, x):
67
+ skip = x
68
+ for i in range(self.depth):
69
+ x = self.dense_block[i](skip)
70
+ skip = torch.cat([x, skip], dim=1)
71
+ return x
72
+
73
+ class DenseEncoder(nn.Module):
74
+ """
75
+ DenseEncoder module consisting of initial convolution, dense block, and a final convolution.
76
+ """
77
+ def __init__(self, cfg):
78
+ super(DenseEncoder, self).__init__()
79
+ self.cfg = cfg
80
+ self.input_channel = cfg['model_cfg']['input_channel']
81
+ self.hid_feature = cfg['model_cfg']['hid_feature']
82
+
83
+ self.dense_conv_1 = nn.Sequential(
84
+ nn.Conv2d(self.input_channel, self.hid_feature, (1, 1)),
85
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
86
+ nn.PReLU(self.hid_feature)
87
+ )
88
+
89
+ self.dense_block = DenseBlock(cfg, depth=4)
90
+
91
+ self.dense_conv_2 = nn.Sequential(
92
+ nn.Conv2d(self.hid_feature, self.hid_feature, (1, 3), stride=(4, 2)),
93
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
94
+ nn.PReLU(self.hid_feature)
95
+ )
96
+
97
+ def forward(self, x):
98
+ x = self.dense_conv_1(x) # [batch, hid_feature, time, freq]
99
+ x = self.dense_block(x) # [batch, hid_feature, time, freq]
100
+ x = self.dense_conv_2(x) # [batch, hid_feature, time, freq//2]
101
+ return x
102
+
103
+ class MagDecoder(nn.Module):
104
+ """
105
+ MagDecoder module for decoding magnitude information.
106
+ """
107
+ def __init__(self, cfg):
108
+ super(MagDecoder, self).__init__()
109
+ self.dense_block = DenseBlock(cfg, depth=4)
110
+ self.hid_feature = cfg['model_cfg']['hid_feature']
111
+ self.output_channel = cfg['model_cfg']['output_channel']
112
+ self.n_fft = cfg['stft_cfg']['n_fft']
113
+ self.beta = cfg['model_cfg']['beta']
114
+
115
+ self.up_conv1 = nn.Sequential(
116
+ SPConvTranspose2d(self.hid_feature, self.hid_feature, (1, 3), 2),
117
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
118
+ nn.PReLU(self.hid_feature)
119
+ )
120
+
121
+ self.up_conv2 = nn.Sequential(
122
+ SPConvTranspose2d(self.hid_feature, self.hid_feature, (1, 3), 4),
123
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
124
+ nn.PReLU(self.hid_feature)
125
+ )
126
+
127
+ self.final_conv = nn.Conv2d(self.hid_feature, self.output_channel, (1, 1))
128
+
129
+ def forward(self, x):
130
+ x = self.dense_block(x)
131
+ x = self.up_conv1(x)
132
+ x = self.up_conv2(x.permute(0,1,3,2)).permute(0,1,3,2)
133
+ x = self.final_conv(x)
134
+ return x
135
+
136
+ class PhaseDecoder(nn.Module):
137
+ """
138
+ PhaseDecoder module for decoding phase information.
139
+ """
140
+ def __init__(self, cfg):
141
+ super(PhaseDecoder, self).__init__()
142
+ self.dense_block = DenseBlock(cfg, depth=4)
143
+ self.hid_feature = cfg['model_cfg']['hid_feature']
144
+ self.output_channel = cfg['model_cfg']['output_channel']
145
+
146
+ self.up_conv1 = nn.Sequential(
147
+ SPConvTranspose2d(self.hid_feature, self.hid_feature, (1, 3), 2),
148
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
149
+ nn.PReLU(self.hid_feature)
150
+ )
151
+
152
+ self.up_conv2 = nn.Sequential(
153
+ SPConvTranspose2d(self.hid_feature, self.hid_feature, (1, 3), 4),
154
+ nn.InstanceNorm2d(self.hid_feature, affine=True),
155
+ nn.PReLU(self.hid_feature)
156
+ )
157
+
158
+ self.phase_conv_r = nn.Conv2d(self.hid_feature, self.output_channel, (1, 1))
159
+ self.phase_conv_i = nn.Conv2d(self.hid_feature, self.output_channel, (1, 1))
160
+
161
+ def forward(self, x):
162
+ x = self.dense_block(x)
163
+ x = self.up_conv1(x)
164
+ x = self.up_conv2(x.permute(0,1,3,2)).permute(0,1,3,2)
165
+ x_r = self.phase_conv_r(x)
166
+ x_i = self.phase_conv_i(x)
167
+ x = torch.atan2(x_i, x_r)
168
+ return x
models/generator_SEMamba_time_d4.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ from einops import rearrange
12
+ from huggingface_hub import PyTorchModelHubMixin
13
+ from .mamba_block2_SEMamba import TFMambaBlock
14
+ from .codec_module_time_d4 import DenseEncoder, MagDecoder, PhaseDecoder
15
+
16
+ class SEMamba(nn.Module, PyTorchModelHubMixin):
17
+ """
18
+ SEMamba model for speech enhancement using Mamba blocks.
19
+
20
+ This model uses a dense encoder, multiple Mamba blocks, and separate magnitude
21
+ and phase decoders to process noisy magnitude and phase inputs.
22
+ """
23
+ def __init__(self, cfg):
24
+ """
25
+ Initialize the SEMamba model.
26
+
27
+ Args:
28
+ - cfg: Configuration object containing model parameters.
29
+ """
30
+ super(SEMamba, self).__init__()
31
+ self.cfg = cfg
32
+ self.num_tscblocks = cfg['model_cfg']['num_tfmamba'] if cfg['model_cfg']['num_tfmamba'] is not None else 4 # default tfmamba: 4
33
+
34
+ # Initialize dense encoder
35
+ self.dense_encoder = DenseEncoder(cfg)
36
+
37
+ # Initialize Mamba blocks
38
+ self.TSMamba = nn.ModuleList([TFMambaBlock(cfg) for _ in range(self.num_tscblocks)])
39
+
40
+ # Initialize decoders
41
+ self.mask_decoder = MagDecoder(cfg)
42
+ self.phase_decoder = PhaseDecoder(cfg)
43
+
44
+ def forward(self, noisy_mag, noisy_pha):
45
+ """
46
+ Forward pass for the SEMamba model.
47
+
48
+ Args:
49
+ - noisy_mag (torch.Tensor): Noisy magnitude input tensor [B, F, T].
50
+ - noisy_pha (torch.Tensor): Noisy phase input tensor [B, F, T].
51
+
52
+ Returns:
53
+ - denoised_mag (torch.Tensor): Denoised magnitude tensor [B, F, T].
54
+ - denoised_pha (torch.Tensor): Denoised phase tensor [B, F, T].
55
+ - denoised_com (torch.Tensor): Denoised complex tensor [B, F, T, 2].
56
+ """
57
+ # Reshape inputs
58
+ noisy_mag = rearrange(noisy_mag, 'b f t -> b t f').unsqueeze(1) # [B, 1, T, F]
59
+ noisy_pha = rearrange(noisy_pha, 'b f t -> b t f').unsqueeze(1) # [B, 1, T, F]
60
+
61
+ # Concatenate magnitude and phase inputs
62
+ x = torch.cat((noisy_mag, noisy_pha), dim=1) # [B, 2, T, F]
63
+
64
+ # Prevent unpredictable errors
65
+ B, C, T, F = x.shape
66
+ zeros = torch.zeros(B, C, T, 2, device=x.device)
67
+ x = torch.cat((x, zeros), dim=-1)
68
+ zeros = torch.zeros(B, C, 2, F+2, device=x.device)
69
+ x = torch.cat((x, zeros), dim=-2)
70
+
71
+ # Encode input
72
+ x = self.dense_encoder(x)
73
+
74
+ # Apply Mamba blocks
75
+ for block in self.TSMamba:
76
+ x = block(x)
77
+
78
+ # Decode output
79
+ denoised_mag = rearrange(self.mask_decoder(x), 'b c t f -> b f t c').squeeze(-1)
80
+ denoised_pha = rearrange(self.phase_decoder(x), 'b c t f -> b f t c').squeeze(-1)
81
+
82
+ # Prevent unpredictable errors
83
+ denoised_mag = denoised_mag[:, :F, :T]
84
+ denoised_pha = denoised_pha[:, :F, :T]
85
+
86
+ # Combine denoised magnitude and phase into a complex representation
87
+ denoised_com = torch.stack(
88
+ (denoised_mag * torch.cos(denoised_pha), denoised_mag * torch.sin(denoised_pha)),
89
+ dim=-1
90
+ )
91
+
92
+ return denoised_mag, denoised_pha, denoised_com
models/mamba_block2_SEMamba.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+ import torch.nn.functional as F
12
+ from torch.nn import init
13
+ from torch.nn.parameter import Parameter
14
+ from functools import partial
15
+ from einops import rearrange
16
+ from mamba_ssm import Mamba
17
+
18
+ class MambaBlock(nn.Module):
19
+ def __init__(self, d_model, cfg):
20
+ super(MambaBlock, self).__init__()
21
+
22
+ d_state = cfg['model_cfg']['d_state'] # 16
23
+ d_conv = cfg['model_cfg']['d_conv'] # 4
24
+ expand = cfg['model_cfg']['expand'] # 4
25
+
26
+ self.forward_blocks = Mamba(d_model=d_model, d_state=d_state, d_conv=d_conv, expand=expand)
27
+ self.backward_blocks = Mamba(d_model=d_model, d_state=d_state, d_conv=d_conv, expand=expand)
28
+ self.output_proj = nn.Linear(2 * d_model, d_model)
29
+ self.norm = nn.LayerNorm(d_model)
30
+
31
+ def forward(self, x):
32
+ # x: [B, T, D]
33
+ out_fw = self.forward_blocks(x) + x
34
+
35
+ out_bw = self.backward_blocks(torch.flip(x, dims=[1])) + torch.flip(x, dims=[1])
36
+ out_bw = torch.flip(out_bw, dims=[1])
37
+
38
+ out = torch.cat([out_fw, out_bw], dim=-1)
39
+ out = self.output_proj(out)
40
+
41
+ # LayerNorm
42
+ return self.norm(out)
43
+
44
+
45
+ class TFMambaBlock(nn.Module):
46
+ """
47
+ Temporal-Frequency Mamba block for sequence modeling.
48
+
49
+ Attributes:
50
+ cfg (Config): Configuration for the block.
51
+ time_mamba (MambaBlock): Mamba block for temporal dimension.
52
+ freq_mamba (MambaBlock): Mamba block for frequency dimension.
53
+ tlinear (ConvTranspose1d): ConvTranspose1d layer for temporal dimension.
54
+ flinear (ConvTranspose1d): ConvTranspose1d layer for frequency dimension.
55
+ """
56
+ def __init__(self, cfg):
57
+ super(TFMambaBlock, self).__init__()
58
+ self.cfg = cfg
59
+ self.hid_feature = cfg['model_cfg']['hid_feature']
60
+
61
+ # Initialize Mamba blocks
62
+ self.time_mamba = MambaBlock(d_model=self.hid_feature, cfg=cfg)
63
+ self.freq_mamba = MambaBlock(d_model=self.hid_feature, cfg=cfg)
64
+
65
+ def forward(self, x):
66
+ """
67
+ Forward pass of the TFMamba block.
68
+
69
+ Parameters:
70
+ x (Tensor): Input tensor with shape (batch, channels, time, freq).
71
+
72
+ Returns:
73
+ Tensor: Output tensor after applying temporal and frequency Mamba blocks.
74
+ """
75
+ b, c, t, f = x.size()
76
+ x = x.permute(0, 3, 2, 1).contiguous().view(b*f, t, c)
77
+ x = self.time_mamba(x) + x
78
+ x = x.view(b, f, t, c).permute(0, 2, 1, 3).contiguous().view(b*t, f, c)
79
+ x = self.freq_mamba(x) + x
80
+ x = x.view(b, t, f, c).permute(0, 3, 1, 2)
81
+ return x
models/stfts.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import torch
10
+ import torch.nn as nn
11
+
12
+ def decompress_signed_log1p(y):
13
+ return torch.sign(y) * (torch.expm1(torch.abs(y)))
14
+
15
+ RELU = nn.ReLU()
16
+
17
+ def mag_phase_stft(y, n_fft, hop_size, win_size, compress_factor=1.0, center=True, addeps=False):
18
+ """
19
+ Compute magnitude and phase using STFT.
20
+
21
+ Args:
22
+ y (torch.Tensor): Input audio signal.
23
+ n_fft (int): FFT size.
24
+ hop_size (int): Hop size.
25
+ win_size (int): Window size.
26
+ compress_factor (float, optional): Magnitude compression factor. Defaults to 1.0.
27
+ center (bool, optional): Whether to center the signal before padding. Defaults to True.
28
+ eps (bool, optional): Whether adding epsilon to magnitude and phase or not. Defaults to False.
29
+
30
+ Returns:
31
+ tuple: Magnitude, phase, and complex representation of the STFT.
32
+ """
33
+ eps = 1e-10
34
+ hann_window = torch.hann_window(win_size).to(y.device)
35
+ stft_spec = torch.stft(
36
+ y, n_fft,
37
+ hop_length=hop_size,
38
+ win_length=win_size,
39
+ window=hann_window,
40
+ center=center,
41
+ pad_mode='reflect',
42
+ normalized=False,
43
+ return_complex=True)
44
+
45
+ if addeps==False:
46
+ mag = torch.abs(stft_spec)
47
+ pha = torch.angle(stft_spec)
48
+ else:
49
+ real_part = stft_spec.real
50
+ imag_part = stft_spec.imag
51
+ mag = torch.sqrt(real_part.pow(2) + imag_part.pow(2) + eps)
52
+ pha = torch.atan2(imag_part + eps, real_part + eps)
53
+ # Compress the magnitude
54
+ if compress_factor in ['log1p','relu_log1p', 'signed_log1p']:
55
+ mag = torch.log1p(mag)
56
+ else:
57
+ mag = torch.pow(mag, compress_factor)
58
+ com = torch.stack((mag * torch.cos(pha), mag * torch.sin(pha)), dim=-1)
59
+ return mag, pha, com
60
+
61
+
62
+ def mag_phase_istft(mag, pha, n_fft, hop_size, win_size, compress_factor=1.0, center=True):
63
+ """
64
+ Inverse STFT to reconstruct the audio signal from magnitude and phase.
65
+
66
+ Args:
67
+ mag (torch.Tensor): Magnitude of the STFT.
68
+ pha (torch.Tensor): Phase of the STFT.
69
+ n_fft (int): FFT size.
70
+ hop_size (int): Hop size.
71
+ win_size (int): Window size.
72
+ compress_factor (float, optional): Magnitude compression factor. Defaults to 1.0.
73
+ center (bool, optional): Whether to center the signal before padding. Defaults to True.
74
+
75
+ Returns:
76
+ torch.Tensor: Reconstructed audio signal.
77
+ """
78
+ if compress_factor == 'log1p':
79
+ mag = torch.expm1(mag)
80
+ elif compress_factor == 'signed_log1p':
81
+ mag = decompress_signed_log1p(mag)
82
+ elif compress_factor == 'relu_log1p':
83
+ mag = torch.expm1(RELU(mag))
84
+ else:
85
+ mag = torch.pow(RELU(mag), 1.0 / compress_factor)
86
+ com = torch.complex(mag * torch.cos(pha), mag * torch.sin(pha))
87
+ hann_window = torch.hann_window(win_size).to(com.device)
88
+ wav = torch.istft(
89
+ com,
90
+ n_fft,
91
+ hop_length=hop_size,
92
+ win_length=win_size,
93
+ window=hann_window,
94
+ center=center)
95
+ return wav
noisy_audio/mic_test2.wav ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e6433420a00163f30a339fc83a191517a82597cf2141cbd310233470e83ce0d7
3
+ size 449896
recipes/USEMamba_30x1_lr_00002_norm_05_vq_065_nfft_320_hop_40_NRIR_012_pha_0005_com_04_early_001.yaml ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment Settings
2
+ # These settings specify the hardware and distributed setup for the model training.
3
+ # Adjust `num_gpus` and `dist_config` according to your distributed training environment.
4
+ env_setting:
5
+ num_gpus: 8 # Number of GPUs. Now we don't support CPU mode.
6
+ num_workers: 20 # 0 Number of worker threads for data loading.
7
+ persistent_workers: True # False If you have large RAM, turn this to be True
8
+ prefetch_factor: 8 # null
9
+ seed: 1234 # Seed for random number generators to ensure reproducibility.
10
+ stdout_interval: 5000
11
+ checkpoint_interval: 5000 # save model to ckpt every N steps
12
+ validation_interval: 5000
13
+ dist_cfg:
14
+ dist_backend: nccl # Distributed training backend, 'nccl' for NVIDIA GPUs.
15
+ dist_url: tcp://localhost:19478 # URL for initializing distributed training.
16
+ world_size: 1 # Total number of processes in the distributed training.
17
+ pin_memory: True # If you have large RAM, turn this to be True
18
+
19
+
20
+ # STFT Configuration
21
+ # Configuration for Short-Time Fourier Transform (STFT), crucial for audio processing models.
22
+ stft_cfg:
23
+ sampling_rate: 8000 # Audio sampling rate in Hz.
24
+ n_fft: 320 # FFT components for transforming audio signals.
25
+ hop_size: 40 # Samples between successive frames.
26
+ win_size: 320 # Window size used in FFT.
27
+ sfi: True # Sampline Frequency Independent
28
+
29
+ # Model Configuration
30
+ # Defines the architecture specifics of the model, including layer configurations and feature compression.
31
+ model_cfg:
32
+ hid_feature: 64 # Channels in dense layers.
33
+ compress_factor: relu_log1p # Compression factor applied to extracted features.
34
+ num_tfmamba: 30 # Number of Time-Frequency Mamba (TFMamba) blocks in the model.
35
+ d_state: 16 # Dimensionality of the state vector in Mamba blocks.
36
+ d_conv: 4 # Convolutional layer dimensionality within Mamba blocks.
37
+ expand: 4 # Expansion factor for the layers within the Mamba blocks.
38
+ norm_epsilon: 0.00001 # Numerical stability in normalization layers within the Mamba blocks.
39
+ beta: 2.0 # Hyperparameter for the Learnable Sigmoid function.
40
+ input_channel: 2 # Magnitude and Phase
41
+ output_channel: 1 # Single Channel Speech Enhancement
42
+ inner_mamba_nlayer: 1 # Number of layer of Mamba in Bidirectional Mamba
43
+ nonlinear: None # last activation function for the mag encoder. 'softplus' or 'relu'
44
+ mapping: True # Otherwise, this should be masking model
utils/util.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
4
+ # and proprietary rights in and to this software, related documentation
5
+ # and any modifications thereto. Any use, reproduction, disclosure or
6
+ # distribution of this software and related documentation without an express
7
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
8
+
9
+ import yaml
10
+ import torch
11
+ import os
12
+ import shutil
13
+ import torch.nn.functional as F
14
+
15
+ def load_config(config_path):
16
+ """Load configuration from a YAML file."""
17
+ with open(config_path, 'r') as file:
18
+ return yaml.safe_load(file)
19
+
20
+ def pad_or_trim_to_match(reference: torch.Tensor, target: torch.Tensor, pad_value: float = 1e-6) -> torch.Tensor:
21
+ """
22
+ Extends the target tensor to match the reference tensor along dim=1
23
+ without breaking autograd, by creating a new tensor and copying data in.
24
+ """
25
+ B, ref_len = reference.shape
26
+ _, tgt_len = target.shape
27
+
28
+ if tgt_len == ref_len:
29
+ return target
30
+ elif tgt_len > ref_len:
31
+ return target[:, :ref_len]
32
+
33
+ # Allocate padded tensor with grad support
34
+ padded = torch.full((B, ref_len), pad_value, dtype=target.dtype, device=target.device)
35
+ padded[:, :tgt_len] = target # This preserves gradient tracking
36
+
37
+ return padded