在 TensorFlow 中过滤音频信号
Filtering audio signal in TensorFlow
我正在构建一个基于音频的深度学习模型。作为预处理的一部分,我想增强数据集中的音频。我想做的一项增强是应用 RIR(房间脉冲响应)功能。我正在与 Python 3.9.5
和 TensorFlow 2.8
.
合作
在 Python 中,如果 RIR 作为 n 个抽头的有限脉冲响应 (FIR) 给出,则使用 SciPy lfilter
import numpy as np
from scipy import signal
import soundfile as sf
h = np.load("rir.npy")
x, fs = sf.read("audio.wav")
y = signal.lfilter(h, 1, x)
运行 在所有文件上循环可能需要很长时间。在 TensorFlow 数据集上使用 TensorFlow map
实用程序进行操作:
# define filter function
def h_filt(audio, label):
h = np.load("rir.npy")
x = audio.numpy()
y = signal.lfilter(h, 1, x)
return tf.convert_to_tensor(y, dtype=tf.float32), label
# apply it via TF map on dataset
aug_ds = ds.map(h_filt)
使用tf.numpy_function
:
tf_h_filt = tf.numpy_function(h_filt, [audio, label], [tf.float32, tf.string])
# apply it via TF map on dataset
aug_ds = ds.map(tf_h_filt)
我有两个问题:
- 这种方式是否正确且足够快(50,000 个文件不到一分钟)?
- 有没有更快的方法?例如。用内置的 TensforFlow 函数替换 SciPy 函数。我没有找到
lfilter
或 SciPy's convolve. 的等价物
这是您可以采用的一种方法
请注意,张量流函数旨在接收具有多个通道的批量输入,并且过滤器可以具有多个输入通道和多个输出通道。令 N
为批量大小 I
、输入通道数、F
滤波器宽度、L
输入宽度和 O
通道数输出通道。使用 padding='SAME'
它将形状 (N, L, I)
的输入和形状 (F, I, O)
的过滤器映射到形状 (N, L, O)
.
的输出
import numpy as np
from scipy import signal
import tensorflow as tf
# data to compare the two approaches
x = np.random.randn(100)
h = np.random.randn(11)
# h
y_lfilt = signal.lfilter(h, 1, x)
# Since the denominator of your filter transfer function is 1
# the output of lfiler matches the convolution
y_np = np.convolve(h, x)
assert np.allclose(y_lfilt, y_np[:len(y_lfilt)])
# now let's do the convolution using tensorflow
y_tf = tf.nn.conv1d(
# x must be padded with half of the size of h
# to use padding 'SAME'
np.pad(x, len(h) // 2).reshape(1, -1, 1),
# the time axis of h must be flipped
h[::-1].reshape(-1, 1, 1), # a 1x1 matrix of filters
stride=1,
padding='SAME',
data_format='NWC')
assert np.allclose(y_lfilt, np.squeeze(y_tf)[:len(y_lfilt)])
我正在构建一个基于音频的深度学习模型。作为预处理的一部分,我想增强数据集中的音频。我想做的一项增强是应用 RIR(房间脉冲响应)功能。我正在与 Python 3.9.5
和 TensorFlow 2.8
.
在 Python 中,如果 RIR 作为 n 个抽头的有限脉冲响应 (FIR) 给出,则使用 SciPy lfilter
import numpy as np
from scipy import signal
import soundfile as sf
h = np.load("rir.npy")
x, fs = sf.read("audio.wav")
y = signal.lfilter(h, 1, x)
运行 在所有文件上循环可能需要很长时间。在 TensorFlow 数据集上使用 TensorFlow map
实用程序进行操作:
# define filter function
def h_filt(audio, label):
h = np.load("rir.npy")
x = audio.numpy()
y = signal.lfilter(h, 1, x)
return tf.convert_to_tensor(y, dtype=tf.float32), label
# apply it via TF map on dataset
aug_ds = ds.map(h_filt)
使用tf.numpy_function
:
tf_h_filt = tf.numpy_function(h_filt, [audio, label], [tf.float32, tf.string])
# apply it via TF map on dataset
aug_ds = ds.map(tf_h_filt)
我有两个问题:
- 这种方式是否正确且足够快(50,000 个文件不到一分钟)?
- 有没有更快的方法?例如。用内置的 TensforFlow 函数替换 SciPy 函数。我没有找到
lfilter
或 SciPy's convolve. 的等价物
这是您可以采用的一种方法
请注意,张量流函数旨在接收具有多个通道的批量输入,并且过滤器可以具有多个输入通道和多个输出通道。令 N
为批量大小 I
、输入通道数、F
滤波器宽度、L
输入宽度和 O
通道数输出通道。使用 padding='SAME'
它将形状 (N, L, I)
的输入和形状 (F, I, O)
的过滤器映射到形状 (N, L, O)
.
import numpy as np
from scipy import signal
import tensorflow as tf
# data to compare the two approaches
x = np.random.randn(100)
h = np.random.randn(11)
# h
y_lfilt = signal.lfilter(h, 1, x)
# Since the denominator of your filter transfer function is 1
# the output of lfiler matches the convolution
y_np = np.convolve(h, x)
assert np.allclose(y_lfilt, y_np[:len(y_lfilt)])
# now let's do the convolution using tensorflow
y_tf = tf.nn.conv1d(
# x must be padded with half of the size of h
# to use padding 'SAME'
np.pad(x, len(h) // 2).reshape(1, -1, 1),
# the time axis of h must be flipped
h[::-1].reshape(-1, 1, 1), # a 1x1 matrix of filters
stride=1,
padding='SAME',
data_format='NWC')
assert np.allclose(y_lfilt, np.squeeze(y_tf)[:len(y_lfilt)])