龙空技术网

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

哥廷根数学学派 548

前言:

此时各位老铁们对“音频信号去噪研究方法”可能比较讲究,同学们都需要剖析一些“音频信号去噪研究方法”的相关内容。那么小编在网上网罗了一些有关“音频信号去噪研究方法””的相关文章,希望兄弟们能喜欢,姐妹们快快来了解一下吧!

本文介绍了使用自动编码器对语音信号进行降噪,不会涉及数学细节,只给一个初步了解。

自编码器是一种简单的人工神经网络 (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)

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

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

后续会讲解

基于自编码器的语音信号降噪 - 哥廷根数学学派的文章 - 知乎

标签: #音频信号去噪研究方法