注意
单击此处下载完整的示例代码
带有 torchaudio 的 MVDR¶
作者 倪兆恒
概述¶
这是有关如何使用 torchaudio 应用 MVDR 波束成形的教程。
步骤
理想比率掩码 (IRM) 是通过除以清洁/噪声来生成的 magnitude 按混合大小。
我们测试所有三种解决方案 (、 、 ) 的 torchaudio 的 MVDR 模块。
ref_channel
stv_evd
stv_power
我们测试了用于 MVDR 波束成形的单通道和多通道掩模。 在计算时,多通道掩码沿通道维度进行平均 分别是语音和噪声的协方差矩阵。
制备¶
首先,我们导入必要的包并检索数据。
多通道音频示例选自 ConferencingSpeech 数据集。
原始文件名为
SSB07200001\#noise-sound-bible-0038\#7.86_6.16_3.00_3.14_4.84_134.5285_191.7899_0.4735\#15217\#25.16333303751458\#0.2101221178590021.wav
它是用 生成的;
SSB07200001.wav
来自 AISHELL-3 (Apache 许可证 v.2.0)noise-sound-bible-0038.wav
来自 MUSAN (署名 4.0 国际 — CC BY 4.0)
import os
import requests
import torch
import torchaudio
import IPython.display as ipd
torch.random.manual_seed(0)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(torch.__version__)
print(torchaudio.__version__)
print(device)
filenames = [
'mix.wav',
'reverb_clean.wav',
'clean.wav',
]
base_url = 'https://download.pytorch.org/torchaudio/tutorial-assets/mvdr'
for filename in filenames:
os.makedirs('_assets', exist_ok=True)
if not os.path.exists(filename):
with open(f'_assets/{filename}', 'wb') as file:
file.write(requests.get(f'{base_url}/{filename}').content)
外:
1.10.0+cpu
0.10.0+cpu
cpu
生成理想比率掩码 (IRM)¶
加载音频数据¶
注意
MVDR 模块需要 dtype 来产生嘈杂的 STFT。
我们需要将波形的 dtype 转换为torch.cdouble
torch.double
mix = mix.to(torch.double)
noise = noise.to(torch.double)
clean = clean.to(torch.double)
reverb_clean = reverb_clean.to(torch.double)
计算 STFT¶
stft = torchaudio.transforms.Spectrogram(
n_fft=1024,
hop_length=256,
power=None,
)
istft = torchaudio.transforms.InverseSpectrogram(n_fft=1024, hop_length=256)
spec_mix = stft(mix)
spec_clean = stft(clean)
spec_reverb_clean = stft(reverb_clean)
spec_noise = stft(noise)
生成理想比率掩码 (IRM)¶
注意
我们发现直接使用掩码比使用 的平方根。这与 IRM 的定义略有不同。
def get_irms(spec_clean, spec_noise, spec_mix):
mag_mix = spec_mix.abs() ** 2
mag_clean = spec_clean.abs() ** 2
mag_noise = spec_noise.abs() ** 2
irm_speech = mag_clean / (mag_clean + mag_noise)
irm_noise = mag_noise / (mag_clean + mag_noise)
return irm_speech, irm_noise
注意
我们在这里使用混响干净的语音作为目标, 您还可以将其设置为 Dry clean Speech。
irm_speech, irm_noise = get_irms(spec_reverb_clean, spec_noise, spec_mix)
应用 MVDR¶
使用多通道掩码应用 MVDR 波束成形¶
results_multi = {}
for solution in ['ref_channel', 'stv_evd', 'stv_power']:
mvdr = torchaudio.transforms.MVDR(ref_channel=0, solution=solution, multi_mask=True)
stft_est = mvdr(spec_mix, irm_speech, irm_noise)
est = istft(stft_est, length=mix.shape[-1])
results_multi[solution] = est
使用单通道掩码应用 MVDR 波束成形¶
我们以第 1 个通道为例。 通道选择可能取决于麦克风阵列的设计
results_single = {}
for solution in ['ref_channel', 'stv_evd', 'stv_power']:
mvdr = torchaudio.transforms.MVDR(ref_channel=0, solution=solution, multi_mask=False)
stft_est = mvdr(spec_mix, irm_speech[0], irm_noise[0])
est = istft(stft_est, length=mix.shape[-1])
results_single[solution] = est
计算 Si-SDR 分数¶
def si_sdr(estimate, reference, epsilon=1e-8):
estimate = estimate - estimate.mean()
reference = reference - reference.mean()
reference_pow = reference.pow(2).mean(axis=1, keepdim=True)
mix_pow = (estimate * reference).mean(axis=1, keepdim=True)
scale = mix_pow / (reference_pow + epsilon)
reference = scale * reference
error = estimate - reference
reference_pow = reference.pow(2)
error_pow = error.pow(2)
reference_pow = reference_pow.mean(axis=1)
error_pow = error_pow.mean(axis=1)
sisdr = 10 * torch.log10(reference_pow) - 10 * torch.log10(error_pow)
return sisdr.item()
结果¶
单通道蒙版结果¶
for solution in results_single:
print(solution+": ", si_sdr(results_single[solution][None,...], reverb_clean[0:1]))
外:
ref_channel: 15.035907456985868
stv_evd: 16.563734673832553
stv_power: 17.820481909929907
多通道蒙版结果¶
for solution in results_multi:
print(solution+": ", si_sdr(results_multi[solution][None,...], reverb_clean[0:1]))
外:
ref_channel: 13.177373866143256
stv_evd: 12.433610809532858
stv_power: 12.897505397104673