基于深度学习(深层自编码器)的语音信号降噪方法

自编码器是一种简单的人工神经 络 (ANN),经过训练可以学习输入数据的编码表示,这种无监督机制不需要标签。自编码器由两个神经 络组成,前半部分称为编码器,后半部分称为解码器。两个神经 络都由具有激活函数的单个或多个隐藏层组成。编码器和解码器的隐藏层数量通常是对称的,以确保输出的维度与输入的维度一致,如下图所示。

编码器获取输入数据,从数据中学习重要特征并输出输入的向量表示。编码器利用卷积/或最大池层以降低输入数据的维度。

?与编码器不同,解码器将低维数据扩展到高维。误差函数一般如下

?在本实验中,主要使用 `librosa` 和 `soundfile` 模块进行声学处理,`tensorflow` 和 `keras` 模块用于训练自编码器。首先导入相关模块:

import osimport matplotlibimport pylabimport librosaimport librosa.displayimport soundfile as sfimport numpy as npimport matplotlib.pyplot as pltimport kerasfrom keras.datasets import mnistfrom keras.layers import Dense, Flatten, Reshape, Input, InputLayerfrom keras.models import Sequential, Modelfrom keras.layers import Conv2D, MaxPooling2D, Conv2DTransposefrom tqdm.keras import TqdmCallbackimport tensorflow as tffrom keras.backend import clear_session

首先我们先用简单的MNIST数据集搞一下

(train_X, train_y), (test_X, test_y) = mnist.load_data()train_X = train_X.astype('float32') / 255.test_X = test_X.astype('float32') / 255.print('X_train: ' + str(train_X.shape))print('Y_train: ' + str(train_y.shape))print('X_test:  '  + str(test_X.shape))print('Y_test:  '  + str(test_y.shape))for i in range(3):    plt.subplot(1,3,i+1)    plt.imshow(train_X[i], cmap=plt.get_cmap('gray'))

X_train: (60000, 28, 28) Y_train: (60000,) X_test: (10000, 28, 28) Y_test: (10000,)

?在MNIST数据集中添加一些椒盐噪声

noise_factor = 0.2train_X_noisy = train_X + noise_factor * tf.random.normal(shape=train_X.shape) test_X_noisy = test_X + noise_factor * tf.random.normal(shape=test_X.shape) train_X_noisy = tf.clip_by_value(train_X_noisy, clip_value_min=0., clip_value_max=1.).numpy()test_X_noisy = tf.clip_by_value(test_X_noisy, clip_value_min=0., clip_value_max=1.).numpy()

查看一下带噪图像

n = 10plt.figure(figsize=(20, 2))for i in range(n):    ax = plt.subplot(1, n, i + 1)    plt.title("original + noise")    plt.imshow(tf.squeeze(test_X_noisy[i]))    plt.gray()plt.show()

?接下来构建自编码器

def build_autoencoder(img_shape, code_size):    # 编码器    encoder = Sequential()    encoder.add(InputLayer(img_shape))    encoder.add(Flatten())    encoder.add(Dense(code_size, activation='relu'))    # 解码器    decoder = Sequential()    decoder.add(InputLayer((code_size,)))    decoder.add(Dense(np.prod(img_shape)))    decoder.add(Reshape(img_shape))    return encoder, decoderIMG_SHAPE = train_X[0].shapeencoder, decoder = build_autoencoder(IMG_SHAPE, 1000)inp = Input(IMG_SHAPE)code = encoder(inp)reconstruction = decoder(code)autoencoder = Model(inp,reconstruction)autoencoder.compile(optimizer='adamax', loss='mse')print(autoencoder.summary())

?开始训练

history = autoencoder.fit(x=train_X_noisy, y=train_X, epochs=30,                validation_data=[test_X_noisy, test_X])

看一下训练过程

plt.plot(history.history['loss'])plt.plot(history.history['val_loss'])plt.title('model loss')plt.ylabel('loss')plt.xlabel('epoch')plt.legend(['train', 'test'], loc='upper left')plt.show()

带噪图像与重建后的图像

img = train_X_noisy[0]code = encoder.predict(img[None])[0]reco = decoder.predict(code[None])[0]plt.subplot(1,2,1)plt.title("Noise")plt.imshow(img)plt.subplot(1,2,2)plt.title("Reconstructed")plt.imshow(reco)

?接下来我们进行语音信号的降噪

首先导入语音信号

sig, fs = librosa.load('./audio/hello.wav') save_path = 'hello.jpg'pylab.axis('off') pylab.axes([0., 0., 1., 1.], frameon=False, xticks=[], yticks=[])M = librosa.feature.melspectrogram(y=sig, sr=fs)librosa.display.specshow(librosa.power_to_db(M, ref=np.max))pylab.savefig(save_path, bbox_inches=None, pad_inches=0)pylab.close()

看一下Mel谱谱图

plt.figure()librosa.display.specshow(librosa.power_to_db(M, ref=np.max))plt.colorbar()

?将Mel谱转换回幅度谱图,并将其保存为 wav 文件

S = librosa.feature.inverse.mel_to_stft(M)y = librosa.griffinlim(S)sf.write('./audio/reconstructed_hello.wav', y, fs)

在Mel谱中加入椒盐噪声

from skimage.util import random_noisenoise_img = random_noise(M, mode='s&p',amount=0.2)noise_img = np.array(255*noise_img, dtype = 'float32')

带噪谱图

plt.figure()librosa.display.specshow(librosa.power_to_db(noise_img, ref=np.max))plt.colorbar()

?

train_x = noise_img[np.newaxis,:,:]train_y = M[np.newaxis,:,:]

建立多层自编码器

def build_autoencoder(img_shape, code_size):    # 编码器    encoder = Sequential()    encoder.add(InputLayer(img_shape))    encoder.add(Flatten())    encoder.add(Dense(code_size, activation='relu'))    encoder.add(Dense(code_size, activation='relu'))    # 解码器    decoder = Sequential()    decoder.add(InputLayer((code_size,)))    encoder.add(Dense(code_size, activation='relu'))    decoder.add(Dense(np.prod(img_shape))) # np.prod(img_shape) is the same as 32*32*3, it's more generic than saying 3072    decoder.add(Reshape(img_shape))    return encoder, decoderIMG_SHAPE = train_x[0].shapeencoder, decoder = build_autoencoder(IMG_SHAPE, 1000)inp = Input(IMG_SHAPE)code = encoder(inp)reconstruction = decoder(code)autoencoder = Model(inp,reconstruction)autoencoder.compile(optimizer='adamax', loss='mse')

开始训练

history = autoencoder.fit(x=train_x, y=train_y, epochs=100)

可视化

img = noise_imgcode = encoder.predict(img[None])[0]reco = decoder.predict(code[None])[0]plt.subplot(1,3,1)plt.title("Noise")plt.imshow(img)plt.subplot(1,3,2)plt.title("Actual")plt.imshow(M)plt.subplot(1,3,3)plt.title("Reconstructed")plt.imshow(reco)

?还可以重构回时域

# recon_S = librosa.feature.inverse.mel_to_stft(reco*255)# recon_y = librosa.griffinlim(recon_S)# # write output# sf.write('reconstructed_noise_hello.wav', recon_y, fs)

哈哈,还可以试试猫/狗的语音信号降噪

?此外,还可以利用卷积自动编码器对猫/狗的语音信号降噪

?后续会讲解

基于自编码器的语音信号降噪 – 哥廷根数学学派的文章 – 知乎
https://zhuanlan.zhihu.com/p/556513015

声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!

(0)
上一篇 2022年8月16日
下一篇 2022年8月16日

相关推荐