Reza2kn commited on
Commit
4925fb4
·
verified ·
1 Parent(s): 78498dd

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* 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
 
 
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
+ MP-SENet/best_ckpt/g_best_dns filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
@@ -23,7 +23,6 @@ build/
23
  *.swo
24
 
25
  # Project-specific
26
- MP-SENet/
27
  *.wav
28
  *.mp3
29
  *.flac
 
23
  *.swo
24
 
25
  # Project-specific
 
26
  *.wav
27
  *.mp3
28
  *.flac
MP-SENet/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Yexin Lu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
MP-SENet/README.md ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Explicit Estimation of Magnitude and Phase Spectra in Parallel for High-Quality Speech Enhancement
2
+ ### Ye-Xin Lu, Yang Ai, Zhen-Hua Ling
3
+ In our [paper](https://arxiv.org/abs/2305.13686), we proposed MP-SENet: a TF-domain monaural SE model with parallel magnitude and phase spectra denoising.<br>
4
+ A [long-version](https://arxiv.org/abs/2308.08926) MP-SENet was extended to the speech denoising, dereverberation, and bandwidth extension tasks.<br>
5
+ Audio samples can be found at the [demo website](http://yxlu-0102.github.io/MP-SENet).<br>
6
+ We provide our implementation as open source in this repository.
7
+
8
+ ## ⚠️ Note
9
+ There is a small bug in our code, but it does not affect the overall performance of the model.
10
+ If you intend to retrain the model, it’s **strongly recommended** to set `batch_first=True` in the `MultiHeadAttention` module inside [transformer.py](models/transformer.py), which can significantly reduce the memory usage of the model.
11
+
12
+ ## Pre-requisites
13
+ 1. Python >= 3.6.
14
+ 2. Clone this repository.
15
+ 3. Install python requirements. Please refer [requirements.txt](https://github.com/yxlu-0102/MP-SENet/blob/main/requirements.txt).
16
+ 4. Download and extract the [VoiceBank+DEMAND dataset](https://datashare.ed.ac.uk/handle/10283/1942). Resample all wav files to 16kHz, and move the clean and noisy wavs to `VoiceBank+DEMAND/wavs_clean` and `VoiceBank+DEMAND/wavs_noisy`, respectively. You can also directly download the downsampled 16kHz dataset [here](https://drive.google.com/drive/folders/19I_thf6F396y5gZxLTxYIojZXC0Ywm8l).
17
+
18
+ ## Training
19
+ ```
20
+ CUDA_VISIBLE_DEVICES=0,1 python train.py --config config.json
21
+ ```
22
+ Checkpoints and copy of the configuration file are saved in the `cp_mpsenet` directory by default.<br>
23
+ You can change the path by adding `--checkpoint_path` option.
24
+
25
+ ## Inference
26
+ ```
27
+ python inference.py --checkpoint_file [generator checkpoint file path]
28
+ ```
29
+ You can also use the pretrained best checkpoint files we provide in the `best_ckpt` directory.
30
+ <br>
31
+ Generated wav files are saved in `generated_files` by default.
32
+ You can change the path by adding `--output_dir` option.<br>
33
+ Here is an example:
34
+ ```
35
+ python inference.py --checkpoint_file best_ckpt/g_best_vb --output_dir generated_files/MP-SENet_VB
36
+ ```
37
+
38
+ ## Model Structure
39
+ ![model](Figures/model.png)
40
+
41
+ ## Comparison with other SE models
42
+ ![comparison](Figures/table.png)
43
+
44
+ ## Acknowledgements
45
+ We referred to [HiFiGAN](https://github.com/jik876/hifi-gan), [NSPP](https://github.com/YangAi520/NSPP)
46
+ and [CMGAN](https://github.com/ruizhecao96/CMGAN) to implement this.
47
+
48
+ ## Citation
49
+ ```
50
+ @inproceedings{lu2023mp,
51
+ title={{MP-SENet}: A Speech Enhancement Model with Parallel Denoising of Magnitude and Phase Spectra},
52
+ author={Lu, Ye-Xin and Ai, Yang and Ling, Zhen-Hua},
53
+ booktitle={Proc. Interspeech},
54
+ pages={3834--3838},
55
+ year={2023}
56
+ }
57
+
58
+ @article{lu2023explicit,
59
+ title={Explicit estimation of magnitude and phase spectra in parallel for high-quality speech enhancement},
60
+ author={Lu, Ye-Xin and Ai, Yang and Ling, Zhen-Hua},
61
+ journal={Neural Networks},
62
+ volume = {189},
63
+ pages = {107562},
64
+ year={2025}
65
+ }
66
+ ```
MP-SENet/best_ckpt/config.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "num_gpus": 0,
3
+ "batch_size": 4,
4
+ "learning_rate": 0.0005,
5
+ "adam_b1": 0.8,
6
+ "adam_b2": 0.99,
7
+ "lr_decay": 0.99,
8
+ "seed": 1234,
9
+
10
+ "dense_channel": 64,
11
+ "compress_factor": 0.3,
12
+ "num_tsconformers": 4,
13
+ "beta": 2.0,
14
+
15
+ "sampling_rate": 16000,
16
+ "segment_size": 32000,
17
+ "n_fft": 400,
18
+ "hop_size": 100,
19
+ "win_size": 400,
20
+
21
+ "num_workers": 4,
22
+
23
+ "dist_config": {
24
+ "dist_backend": "nccl",
25
+ "dist_url": "tcp://localhost:54321",
26
+ "world_size": 1
27
+ }
28
+ }
MP-SENet/best_ckpt/g_best_dns ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:97a77ba67c5c484c65363bb703ea85962f773ca0819e22ce81b4ec33db5e7206
3
+ size 9138054
MP-SENet/dataset.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import random
3
+ import torch
4
+ import torch.utils.data
5
+ import librosa
6
+
7
+ def mag_pha_stft(y, n_fft, hop_size, win_size, compress_factor=1.0, center=True):
8
+
9
+ hann_window = torch.hann_window(win_size).to(y.device)
10
+ stft_spec = torch.stft(y, n_fft, hop_length=hop_size, win_length=win_size, window=hann_window,
11
+ center=center, pad_mode='reflect', normalized=False, return_complex=True)
12
+ stft_spec = torch.view_as_real(stft_spec)
13
+ mag = torch.sqrt(stft_spec.pow(2).sum(-1)+(1e-9))
14
+ pha = torch.atan2(stft_spec[:, :, :, 1]+(1e-10), stft_spec[:, :, :, 0]+(1e-5))
15
+ # Magnitude Compression
16
+ mag = torch.pow(mag, compress_factor)
17
+ com = torch.stack((mag*torch.cos(pha), mag*torch.sin(pha)), dim=-1)
18
+
19
+ return mag, pha, com
20
+
21
+
22
+ def mag_pha_istft(mag, pha, n_fft, hop_size, win_size, compress_factor=1.0, center=True):
23
+ # Magnitude Decompression
24
+ mag = torch.pow(mag, (1.0/compress_factor))
25
+ com = torch.complex(mag*torch.cos(pha), mag*torch.sin(pha))
26
+ hann_window = torch.hann_window(win_size).to(com.device)
27
+ wav = torch.istft(com, n_fft, hop_length=hop_size, win_length=win_size, window=hann_window, center=center)
28
+
29
+ return wav
30
+
31
+
32
+ def get_dataset_filelist(a):
33
+ with open(a.input_training_file, 'r', encoding='utf-8') as fi:
34
+ training_indexes = [x.split('|')[0] for x in fi.read().split('\n') if len(x) > 0]
35
+
36
+ with open(a.input_validation_file, 'r', encoding='utf-8') as fi:
37
+ validation_indexes = [x.split('|')[0] for x in fi.read().split('\n') if len(x) > 0]
38
+
39
+ return training_indexes, validation_indexes
40
+
41
+
42
+ class Dataset(torch.utils.data.Dataset):
43
+ def __init__(self, training_indexes, clean_wavs_dir, noisy_wavs_dir, segment_size,
44
+ sampling_rate, split=True, shuffle=True, n_cache_reuse=1, device=None):
45
+ self.audio_indexes = training_indexes
46
+ random.seed(1234)
47
+ if shuffle:
48
+ random.shuffle(self.audio_indexes)
49
+ self.clean_wavs_dir = clean_wavs_dir
50
+ self.noisy_wavs_dir = noisy_wavs_dir
51
+ self.segment_size = segment_size
52
+ self.sampling_rate = sampling_rate
53
+ self.split = split
54
+ self.cached_clean_wav = None
55
+ self.cached_noisy_wav = None
56
+ self.n_cache_reuse = n_cache_reuse
57
+ self._cache_ref_count = 0
58
+ self.device = device
59
+
60
+ def __getitem__(self, index):
61
+ filename = self.audio_indexes[index]
62
+ if self._cache_ref_count == 0:
63
+ clean_audio, _ = librosa.load(os.path.join(self.clean_wavs_dir, filename + '.wav'), sr=self.sampling_rate)
64
+ noisy_audio, _ = librosa.load(os.path.join(self.noisy_wavs_dir, filename + '.wav'), sr=self.sampling_rate)
65
+ length = min(len(clean_audio), len(noisy_audio))
66
+ clean_audio, noisy_audio = clean_audio[: length], noisy_audio[: length]
67
+ self.cached_clean_wav = clean_audio
68
+ self.cached_noisy_wav = noisy_audio
69
+ self._cache_ref_count = self.n_cache_reuse
70
+ else:
71
+ clean_audio = self.cached_clean_wav
72
+ noisy_audio = self.cached_noisy_wav
73
+ self._cache_ref_count -= 1
74
+
75
+ clean_audio, noisy_audio = torch.FloatTensor(clean_audio), torch.FloatTensor(noisy_audio)
76
+ norm_factor = torch.sqrt(len(noisy_audio) / torch.sum(noisy_audio ** 2.0))
77
+ clean_audio = (clean_audio * norm_factor).unsqueeze(0)
78
+ noisy_audio = (noisy_audio * norm_factor).unsqueeze(0)
79
+
80
+ assert clean_audio.size(1) == noisy_audio.size(1)
81
+
82
+ if self.split:
83
+ if clean_audio.size(1) >= self.segment_size:
84
+ max_audio_start = clean_audio.size(1) - self.segment_size
85
+ audio_start = random.randint(0, max_audio_start)
86
+ clean_audio = clean_audio[:, audio_start: audio_start+self.segment_size]
87
+ noisy_audio = noisy_audio[:, audio_start: audio_start+self.segment_size]
88
+ else:
89
+ clean_audio = torch.nn.functional.pad(clean_audio, (0, self.segment_size - clean_audio.size(1)), 'constant')
90
+ noisy_audio = torch.nn.functional.pad(noisy_audio, (0, self.segment_size - noisy_audio.size(1)), 'constant')
91
+
92
+ return (clean_audio.squeeze(), noisy_audio.squeeze())
93
+
94
+ def __len__(self):
95
+ return len(self.audio_indexes)
MP-SENet/env.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+
4
+ class AttrDict(dict):
5
+ def __init__(self, *args, **kwargs):
6
+ super(AttrDict, self).__init__(*args, **kwargs)
7
+ self.__dict__ = self
8
+
9
+
10
+ def build_env(config, config_name, path):
11
+ t_path = os.path.join(path, config_name)
12
+ if config != t_path:
13
+ os.makedirs(path, exist_ok=True)
14
+ shutil.copyfile(config, os.path.join(path, config_name))
MP-SENet/models/model.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import numpy as np
4
+ from models.transformer import TransformerBlock
5
+ from utils import LearnableSigmoid2d
6
+ from pesq import pesq
7
+ from joblib import Parallel, delayed
8
+
9
+ class SPConvTranspose2d(nn.Module):
10
+ def __init__(self, in_channels, out_channels, kernel_size, r=1):
11
+ super(SPConvTranspose2d, self).__init__()
12
+ self.pad1 = nn.ConstantPad2d((1, 1, 0, 0), value=0.)
13
+ self.out_channels = out_channels
14
+ self.conv = nn.Conv2d(in_channels, out_channels * r, kernel_size=kernel_size, stride=(1, 1))
15
+ self.r = r
16
+
17
+ def forward(self, x):
18
+ x = self.pad1(x)
19
+ out = self.conv(x)
20
+ batch_size, nchannels, H, W = out.shape
21
+ out = out.view((batch_size, self.r, nchannels // self.r, H, W))
22
+ out = out.permute(0, 2, 3, 4, 1)
23
+ out = out.contiguous().view((batch_size, nchannels // self.r, H, -1))
24
+ return out
25
+
26
+
27
+ class DenseBlock(nn.Module):
28
+ def __init__(self, h, kernel_size=(2, 3), depth=4):
29
+ super(DenseBlock, self).__init__()
30
+ self.h = h
31
+ self.depth = depth
32
+ self.dense_block = nn.ModuleList([])
33
+ for i in range(depth):
34
+ dilation = 2 ** i
35
+ pad_length = dilation
36
+ dense_conv = nn.Sequential(
37
+ nn.ConstantPad2d((1, 1, pad_length, 0), value=0.),
38
+ nn.Conv2d(h.dense_channel*(i+1), h.dense_channel, kernel_size, dilation=(dilation, 1)),
39
+ nn.InstanceNorm2d(h.dense_channel, affine=True),
40
+ nn.PReLU(h.dense_channel)
41
+ )
42
+ self.dense_block.append(dense_conv)
43
+
44
+ def forward(self, x):
45
+ skip = x
46
+ for i in range(self.depth):
47
+ x = self.dense_block[i](skip)
48
+ skip = torch.cat([x, skip], dim=1)
49
+ return x
50
+
51
+
52
+ class DenseEncoder(nn.Module):
53
+ def __init__(self, h, in_channel):
54
+ super(DenseEncoder, self).__init__()
55
+ self.h = h
56
+ self.dense_conv_1 = nn.Sequential(
57
+ nn.Conv2d(in_channel, h.dense_channel, (1, 1)),
58
+ nn.InstanceNorm2d(h.dense_channel, affine=True),
59
+ nn.PReLU(h.dense_channel))
60
+
61
+ self.dense_block = DenseBlock(h, depth=4)
62
+
63
+ self.dense_conv_2 = nn.Sequential(
64
+ nn.Conv2d(h.dense_channel, h.dense_channel, (1, 3), (1, 2), padding=(0, 1)),
65
+ nn.InstanceNorm2d(h.dense_channel, affine=True),
66
+ nn.PReLU(h.dense_channel))
67
+
68
+ def forward(self, x):
69
+ x = self.dense_conv_1(x) # [b, 64, T, F]
70
+ x = self.dense_block(x) # [b, 64, T, F]
71
+ x = self.dense_conv_2(x) # [b, 64, T, F//2]
72
+ return x
73
+
74
+
75
+ class MaskDecoder(nn.Module):
76
+ def __init__(self, h, out_channel=1):
77
+ super(MaskDecoder, self).__init__()
78
+ self.dense_block = DenseBlock(h, depth=4)
79
+ self.mask_conv = nn.Sequential(
80
+ SPConvTranspose2d(h.dense_channel, h.dense_channel, (1, 3), 2),
81
+ nn.InstanceNorm2d(h.dense_channel, affine=True),
82
+ nn.PReLU(h.dense_channel),
83
+ nn.Conv2d(h.dense_channel, out_channel, (1, 2))
84
+ )
85
+ self.lsigmoid = LearnableSigmoid2d(h.n_fft//2+1, beta=h.beta)
86
+
87
+ def forward(self, x):
88
+ x = self.dense_block(x)
89
+ x = self.mask_conv(x)
90
+ x = x.permute(0, 3, 2, 1).squeeze(-1) # [B, F, T]
91
+ x = self.lsigmoid(x)
92
+ return x
93
+
94
+
95
+ class PhaseDecoder(nn.Module):
96
+ def __init__(self, h, out_channel=1):
97
+ super(PhaseDecoder, self).__init__()
98
+ self.dense_block = DenseBlock(h, depth=4)
99
+ self.phase_conv = nn.Sequential(
100
+ SPConvTranspose2d(h.dense_channel, h.dense_channel, (1, 3), 2),
101
+ nn.InstanceNorm2d(h.dense_channel, affine=True),
102
+ nn.PReLU(h.dense_channel)
103
+ )
104
+ self.phase_conv_r = nn.Conv2d(h.dense_channel, out_channel, (1, 2))
105
+ self.phase_conv_i = nn.Conv2d(h.dense_channel, out_channel, (1, 2))
106
+
107
+ def forward(self, x):
108
+ x = self.dense_block(x)
109
+ x = self.phase_conv(x)
110
+ x_r = self.phase_conv_r(x)
111
+ x_i = self.phase_conv_i(x)
112
+ x = torch.atan2(x_i, x_r)
113
+ x = x.permute(0, 3, 2, 1).squeeze(-1) # [B, F, T]
114
+ return x
115
+
116
+
117
+ class TSTransformerBlock(nn.Module):
118
+ def __init__(self, h):
119
+ super(TSTransformerBlock, self).__init__()
120
+ self.h = h
121
+ self.time_transformer = TransformerBlock(d_model=h.dense_channel, n_heads=4)
122
+ self.freq_transformer = TransformerBlock(d_model=h.dense_channel, n_heads=4)
123
+
124
+ def forward(self, x):
125
+ b, c, t, f = x.size()
126
+ x = x.permute(0, 3, 2, 1).contiguous().view(b*f, t, c)
127
+ x = self.time_transformer(x) + x
128
+ x = x.view(b, f, t, c).permute(0, 2, 1, 3).contiguous().view(b*t, f, c)
129
+ x = self.freq_transformer(x) + x
130
+ x = x.view(b, t, f, c).permute(0, 3, 1, 2)
131
+ return x
132
+
133
+
134
+ class MPNet(nn.Module):
135
+ def __init__(self, h, num_tsblocks=4):
136
+ super(MPNet, self).__init__()
137
+ self.h = h
138
+ self.num_tscblocks = num_tsblocks
139
+ self.dense_encoder = DenseEncoder(h, in_channel=2)
140
+
141
+ self.TSTransformer = nn.ModuleList([])
142
+ for i in range(num_tsblocks):
143
+ self.TSTransformer.append(TSTransformerBlock(h))
144
+
145
+ self.mask_decoder = MaskDecoder(h, out_channel=1)
146
+ self.phase_decoder = PhaseDecoder(h, out_channel=1)
147
+
148
+ def forward(self, noisy_amp, noisy_pha): # [B, F, T]
149
+
150
+ x = torch.stack((noisy_amp, noisy_pha), dim=-1).permute(0, 3, 2, 1) # [B, 2, T, F]
151
+ x = self.dense_encoder(x)
152
+
153
+ for i in range(self.num_tscblocks):
154
+ x = self.TSTransformer[i](x)
155
+
156
+ denoised_amp = noisy_amp * self.mask_decoder(x)
157
+ denoised_pha = self.phase_decoder(x)
158
+ denoised_com = torch.stack((denoised_amp*torch.cos(denoised_pha),
159
+ denoised_amp*torch.sin(denoised_pha)), dim=-1)
160
+
161
+ return denoised_amp, denoised_pha, denoised_com
162
+
163
+
164
+ def phase_losses(phase_r, phase_g):
165
+
166
+ ip_loss = torch.mean(anti_wrapping_function(phase_r - phase_g))
167
+ gd_loss = torch.mean(anti_wrapping_function(torch.diff(phase_r, dim=1) - torch.diff(phase_g, dim=1)))
168
+ iaf_loss = torch.mean(anti_wrapping_function(torch.diff(phase_r, dim=2) - torch.diff(phase_g, dim=2)))
169
+
170
+ return ip_loss, gd_loss, iaf_loss
171
+
172
+ def anti_wrapping_function(x):
173
+
174
+ return torch.abs(x - torch.round(x / (2 * np.pi)) * 2 * np.pi)
175
+
176
+
177
+ def pesq_score(utts_r, utts_g, h):
178
+
179
+ pesq_score = Parallel(n_jobs=30)(delayed(eval_pesq)(
180
+ utts_r[i].squeeze().cpu().numpy(),
181
+ utts_g[i].squeeze().cpu().numpy(),
182
+ h.sampling_rate)
183
+ for i in range(len(utts_r)))
184
+ pesq_score = np.mean(pesq_score)
185
+
186
+ return pesq_score
187
+
188
+
189
+ def eval_pesq(clean_utt, esti_utt, sr):
190
+ try:
191
+ pesq_score = pesq(sr, clean_utt, esti_utt)
192
+ except:
193
+ pesq_score = -1
194
+
195
+ return pesq_score
MP-SENet/models/transformer.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn.functional as F
3
+ import torch.nn as nn
4
+ from torch.nn import MultiheadAttention, GRU, Linear, LayerNorm, Dropout
5
+
6
+ class FFN(nn.Module):
7
+ def __init__(self, d_model, bidirectional=True, dropout=0):
8
+ super(FFN, self).__init__()
9
+ self.gru = GRU(d_model, d_model*2, 1, bidirectional=bidirectional)
10
+ if bidirectional:
11
+ self.linear = Linear(d_model*2*2, d_model)
12
+ else:
13
+ self.linear = Linear(d_model*2, d_model)
14
+ self.dropout = Dropout(dropout)
15
+
16
+ def forward(self, x):
17
+ self.gru.flatten_parameters()
18
+ x, _ = self.gru(x)
19
+ x = F.leaky_relu(x)
20
+ x = self.dropout(x)
21
+ x = self.linear(x)
22
+
23
+ return x
24
+
25
+
26
+ class TransformerBlock(nn.Module):
27
+ def __init__(self, d_model, n_heads, bidirectional=True, dropout=0):
28
+ super(TransformerBlock, self).__init__()
29
+
30
+ self.norm1 = LayerNorm(d_model)
31
+ self.attention = MultiheadAttention(d_model, n_heads, dropout=dropout)
32
+ self.dropout1 = Dropout(dropout)
33
+
34
+ self.norm2 = LayerNorm(d_model)
35
+ self.ffn = FFN(d_model, bidirectional=bidirectional)
36
+ self.dropout2 = Dropout(dropout)
37
+
38
+ self.norm3 = LayerNorm(d_model)
39
+
40
+ def forward(self, x, attn_mask=None, key_padding_mask=None):
41
+ xt = self.norm1(x)
42
+ xt, _ = self.attention(xt, xt, xt,
43
+ attn_mask=attn_mask,
44
+ key_padding_mask=key_padding_mask)
45
+ x = x + self.dropout1(xt)
46
+
47
+ xt = self.norm2(x)
48
+ xt = self.ffn(xt)
49
+ x = x + self.dropout2(xt)
50
+
51
+ x = self.norm3(x)
52
+
53
+ return x
54
+
55
+ def main():
56
+ x = torch.randn(4, 64, 401, 201)
57
+ b, c, t, f = x.size()
58
+ x = x.permute(0, 3, 2, 1).contiguous().view(b, f*t, c)
59
+ transformer = TransformerBlock(d_model=64, n_heads=4)
60
+ x = transformer(x)
61
+ x = x.view(b, f, t, c).permute(0, 3, 2, 1)
62
+ print(x.size())
63
+
64
+
65
+ if __name__ == '__main__':
66
+ main()
MP-SENet/utils.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ import torch
4
+ import torch.nn as nn
5
+ import matplotlib
6
+ matplotlib.use("Agg")
7
+ import matplotlib.pylab as plt
8
+
9
+ def plot_spectrogram(spectrogram):
10
+ fig, ax = plt.subplots(figsize=(4, 3))
11
+ im = ax.imshow(spectrogram, aspect="auto", origin="lower",
12
+ interpolation='none')
13
+ plt.colorbar(im, ax=ax)
14
+ fig.canvas.draw()
15
+ plt.close()
16
+
17
+ return fig
18
+
19
+
20
+ def get_padding(kernel_size, dilation=1):
21
+ return int((kernel_size*dilation - dilation)/2)
22
+
23
+
24
+ def get_padding_2d(kernel_size, dilation=(1, 1)):
25
+ return (int((kernel_size[0]*dilation[0] - dilation[0])/2), int((kernel_size[1]*dilation[1] - dilation[1])/2))
26
+
27
+
28
+ class LearnableSigmoid1d(nn.Module):
29
+ def __init__(self, in_features, beta=1):
30
+ super().__init__()
31
+ self.beta = beta
32
+ self.slope = nn.Parameter(torch.ones(in_features))
33
+ self.slope.requiresGrad = True
34
+
35
+ def forward(self, x):
36
+ return self.beta * torch.sigmoid(self.slope * x)
37
+
38
+
39
+ class LearnableSigmoid2d(nn.Module):
40
+ def __init__(self, in_features, beta=1):
41
+ super().__init__()
42
+ self.beta = beta
43
+ self.slope = nn.Parameter(torch.ones(in_features, 1))
44
+ self.slope.requiresGrad = True
45
+
46
+ def forward(self, x):
47
+ return self.beta * torch.sigmoid(self.slope * x)
48
+
49
+
50
+ class Sigmoid2d(nn.Module):
51
+ def __init__(self, in_features, beta=1):
52
+ super().__init__()
53
+ self.beta = beta
54
+ self.slope = torch.ones(in_features, 1)
55
+
56
+ def forward(self, x):
57
+ return self.beta * torch.sigmoid(self.slope * x)
58
+
59
+
60
+ class PLSigmoid(nn.Module):
61
+ def __init__(self, in_features):
62
+ super().__init__()
63
+ self.beta = nn.Parameter(torch.ones(in_features, 1) * 2.0)
64
+ self.slope = nn.Parameter(torch.ones(in_features, 1))
65
+ self.beta.requiresGrad = True
66
+ self.slope.requiresGrad = True
67
+
68
+ def forward(self, x):
69
+ return self.beta * torch.sigmoid(self.slope * x)
70
+
71
+
72
+ def load_checkpoint(filepath, device):
73
+ assert os.path.isfile(filepath)
74
+ print("Loading '{}'".format(filepath))
75
+ checkpoint_dict = torch.load(filepath, map_location=device)
76
+ print("Complete.")
77
+ return checkpoint_dict
78
+
79
+
80
+ def save_checkpoint(filepath, obj):
81
+ print("Saving checkpoint to {}".format(filepath))
82
+ torch.save(obj, filepath)
83
+ print("Complete.")
84
+
85
+
86
+ def scan_checkpoint(cp_dir, prefix):
87
+ pattern = os.path.join(cp_dir, prefix + '????????')
88
+ cp_list = glob.glob(pattern)
89
+ if len(cp_list) == 0:
90
+ return None
91
+ return sorted(cp_list)[-1]
92
+
93
+ def main():
94
+ plsigmoid = PLSigmoid(201)
95
+ a = torch.randn(4, 201, 100)
96
+ print(plsigmoid(a))
97
+
98
+ if __name__ == '__main__':
99
+ main()