主要内容

使用深度学习网络去噪语音

这个例子展示了如何使用深度学习网络去噪语音信号。该示例比较了应用于同一任务的两种网络类型:全连接网络和卷积网络。

简介

语音去噪的目的是去除语音信号中的噪声,同时提高语音的质量和清晰度。这个例子展示了如何使用深度学习网络从语音信号中去除洗衣机噪音。该示例比较了应用于同一任务的两种网络类型:全连接网络和卷积网络。

问题总结

考虑以下以8千赫采样的语音信号。

[cleanAudio,fs] = audioread(“SpeechDFT-16-8-mono-5secs.wav”);声音(cleanAudio fs)

在语音信号中加入洗衣机的噪音。设置噪声功率,使信噪比(SNR)为0 dB。

噪音= audieread (“洗衣机- 16 - 8 mono - 1000 - secs.mp3”);从噪声文件中的随机位置提取一个噪声段ind = randi(数字(噪音)-数字(cleanAudio) + 1,1,1);noisessegment = noise(ind:ind + numel(cleanAudio) - 1);speechPower = sum(cleanAudio.^2);noisePower = sum(noisessegment .^2);noisyAudio = cleanAudio +√(speechPower/noisePower)* noisessegment;

听嘈杂的语音信号。

声音(noisyAudio fs)

想象原始信号和有噪声的信号。

t = (1/fs)*(0:numel(cleanAudio) - 1);图(1)tiledlayout(2,1) nexttile plot(t,cleanAudio)“干净的声音”网格)nexttile plot(t,noisyAudio)“嘈杂的声音”)包含(“时间(s)”网格)

语音去噪的目标是去除语音信号中的洗衣机噪声,同时最大限度地减少输出语音中的不需要的伪影。

检查数据集

这个例子使用了Mozilla Common Voice数据集的一个子集[1来训练和测试深度学习网络。数据集包含48千赫的受试者说短句的录音。下载数据集并解压缩下载的文件。

downloadFolder = matlab.internal.examples.download万博1manbetxSupportFile(“音频”“commonvoice.zip”);dataFolder = tempdir;unzip(下载文件夹,数据文件夹)dataset = fullfile(数据文件夹,数据文件夹)“无法推进”);

使用audioDatastore为训练集创建一个数据存储。若要以牺牲性能为代价加快示例的运行时,请设置speedupExample真正的

adsTrain = audioDatastore(fullfile(dataset,“训练”), IncludeSubfolders = true);speedupExample =真正的如果speedupExample adsTrain = shuffle(adsTrain);adsTrain =子集(adsTrain,1:1000);结束

使用来获取数据存储中第一个文件的内容。

[audio,adsTrainInfo] = read(adsTrain);

听语音信号。

声音(音频、adsTrainInfo.SampleRate)

绘制语音信号。

图(2)t = (1/adsTrainInfo.SampleRate) *(0:数字(音频)-1);情节(t,音频)标题(“语音信号示例”)包含(“时间(s)”网格)

深度学习系统概述

基本的深度学习训练方案如下所示。请注意,由于语音通常低于4 kHz,您首先将干净和有噪声的音频信号采样到8 kHz,以减少网络的计算负载。预测器网络信号和目标网络信号分别是有噪声音频信号和干净音频信号的幅度谱。网络的输出是去噪信号的幅度谱。回归网络使用预测器输入来最小化其输出和输入目标之间的均方误差。使用输出幅度谱和噪声信号的相位[将去噪音频转换回时域。2].

使用短时间傅里叶变换(STFT)将音频转换到频域,窗口长度为256个样本,重叠率为75%,并使用汉明窗口。通过去掉负频率对应的频率样本,将频谱向量的大小减小到129(因为时域语音信号是真实的,这不会导致任何信息丢失)。预测器输入由8个连续的噪声STFT向量组成,因此每个STFT输出估计是基于当前噪声STFT和前7个噪声STFT向量计算的。

STFT目标和预测器

本节说明如何从一个训练文件中生成目标信号和预测信号。

首先,定义系统参数:

windowLength = 256;win = hamming(windowLength,“周期”);重叠= round(0.75*windowLength);fftLength = windowLength;inputFs = 48e3;Fs = 8e3;numFeatures = fftLength/2 + 1;numSegments = 8;

创建一个dsp。SampleRateConverter对象将48 kHz音频转换为8 kHz。

src = dsp.SampleRateConverter(InputSampleRate=inputFs,OutputSampleRate=fs,Bandwidth=7920);

使用从数据存储中获取音频文件的内容。

音频= read(adsTrain);

确保音频长度是采样率转换器抽取因子的倍数。

decimationFactor = inputFs/fs;L =地板(数字(音频)/decimationFactor);音频=音频(1:decimationFactor*L);

将音频信号转换为8千赫。

音频= src(音频);重置(src)

从洗衣机噪声向量中创建一个随机噪声段。

Randind = randi(数字(噪音)-数字(音频),[1 1]);noisessegment =噪音(randind:randind +数字(音频)- 1);

在语音信号中添加噪声,使信噪比为0 dB。

noisePower = sum(noisessegment .^2);cleanPower = sum(音频.^2);noiseSegment = noiseSegment.*sqrt(cleanPower/noisePower);noisyAudio =音频+ noisessegment;

使用stft从原始和噪声音频信号中生成幅度STFT向量。

cleanSTFT = stft(音频,窗口=win,OverlapLength=重叠,fftLength=fftLength);cleanSTFT = abs(cleanSTFT(numFeatures-1:end,:));noisySTFT = stft(noisyAudio,Window=win,OverlapLength=overlap,fftLength=fftLength);noisySTFT = abs(noisySTFT(numFeatures-1:end,:));

从噪声STFT中生成8段训练预测器信号。连续预测因子之间的重叠为7段。

noisySTFT = [noisySTFT(:,1:numSegments - 1),noisySTFT];stftSegments = 0 (numFeatures,numSegments,size(noisySTFT,2) - numSegments + 1);index = 1:size(noisySTFT,2) - numSegments + 1 stftSegments(:,:,index) = noisySTFT(:,index:index + numSegments - 1);结束

设置目标和预测因素。两个变量的最后一个维度对应于由音频文件生成的不同预测器/目标对的数量。每个预测器是129乘8,每个目标是129乘1。

目标= cleanSTFT;大小(目标)
ans =1×2129 544
predictors = stftSegments;大小(预测)
ans =1×3129 8 544

使用Tall数组提取特征

为了加快处理速度,可以使用tall数组从数据存储中所有音频文件的语音段中提取特征序列。与内存中数组不同,高数组通常在调用收集函数。这种延迟计算使您能够快速处理大型数据集。当您最终请求输出时使用收集, MATLAB在可能的情况下组合队列计算,并采用最少的数据遍历次数。如果您有并行计算工具箱™,您可以在本地MATLAB会话或本地并行池中使用高数组。如果安装了MATLAB®Parallel Server™,还可以在集群上运行高数组计算。

首先,将数据存储转换为一个高数组。

reset(adsTrain) T = tall(adsTrain)
使用“本地”配置文件启动并行池(parpool)…连接到平行池(工人数量:6)。T = M×1高细胞数组{234480×1双}{210288×1双}{282864×1双}{292080×1双}{410736×1双}{303600×1双}{326640×1双}{233328×1双}::::

显示显示的行数(对应于数据存储中的文件数)M还不知道。M是一个占位符,直到计算完成。

从高表中提取目标和预测幅度STFT。此操作将创建新的tall数组变量以用于后续计算。这个函数HelperGenerateSpeechDenoisingFeatures方法中已突出显示的步骤STFT目标和预测器部分。的cellfun命令适用于HelperGenerateSpeechDenoisingFeatures到数据存储中每个音频文件的内容。

[targets,predictors] = cellfun(@(x)HelperGenerateSpeechDenoisingFeatures(x,noise,src),T,UniformOutput=false);

使用收集评估目标和预测因素。

[目标,预测器]= gather(目标,预测器);
使用并行池“本地”评估tall表达式:-通过1 / 1:在52秒内完成评估在1分53秒内完成

将所有特征归一化为零均值和统一标准差是一个很好的实践。

分别计算预测因子和目标的平均值和标准差,并使用它们对数据进行归一化。

Predictors = cat(3, Predictors {:});noisyMean = mean(predictors(:));noisyStd = std(predictors(:)));predictors(:) = (predictors(:) - noisyMean)/noisyStd;target = cat(2, Targets {:});cleanMean = mean(目标(:));cleanStd = std(目标(:));targets(:) = (targets(:) - cleanMean)/cleanStd;

将预测器和目标重塑为深度学习网络所期望的维度。

Predictors =重塑(Predictors,size(Predictors,1),size(Predictors,2),1,size(Predictors,3));目标=重塑(目标,1,1,大小(目标,1),大小(目标,2));

在培训期间,您将使用1%的数据进行验证。验证对于检测网络过度拟合训练数据的情况很有用。

随机将数据分成训练集和验证集。

Inds = randperm(size(predictors,4));L = round(0.99*size(predictors,4));trainPredictors = predictors(:,:,:,inds(1:L));trainTargets = targets(:,:,:,inds(1:L));validatePredictors = predictors(:,:,:,inds(L+1:end));validateTargets = targets(:,:,:,inds(L+1:end));

全连通层语音去噪

首先考虑一个由全连接层组成的去噪网络。全连接层中的每个神经元都连接到前一层的所有激活。全连接层将输入乘以权重矩阵,然后添加偏置向量。权重矩阵和偏置向量的维数由该层中的神经元数量和前一层的激活数量决定。

定义网络的层。指定输入大小为图片大小NumFeatures——- - - - - -NumSegments(在这个例子中是129乘8)。定义两个隐藏的全连接层,每个层有1024个神经元。由于是纯线性系统,每个隐藏的全连接层后面都有一个整流线性单元(ReLU)层。批归一化层对输出的均值和标准差进行归一化。添加一个有129个神经元的完全连接层,然后是回归层。

layers = [imageInputLayer([numFeatures,numSegments]) fullyConnectedLayer(1024) batchNormalizationLayer reluLayer fullyConnectedLayer(1024) batchNormalizationLayer reluLayer fullyConnectedLayer(numFeatures) regressionLayer];

接下来,为网络指定训练选项。集MaxEpochs3.这样网络对训练数据进行了3次遍历。集MiniBatchSize128这样网络一次就能看到128个训练信号。指定情节作为“训练进步”生成随迭代次数增加而显示训练进度的图。集详细的禁用将与图中显示的数据相对应的表输出打印到命令行窗口。指定洗牌作为“every-epoch”在每个纪元开始时,对训练序列进行洗牌。指定LearnRateSchedule“分段”每次经过一定数量的epoch(1)时,将学习率降低指定的因子(0.9)。集ValidationData到验证预测器和目标。集ValidationFrequency使验证均方误差每epoch计算一次。本例使用自适应矩估计(Adam)求解器。

miniBatchSize = 128;选项= trainingOptions(“亚当”...MaxEpochs = 3,...InitialLearnRate e-5 = 1,...MiniBatchSize = MiniBatchSize,...洗牌=“every-epoch”...情节=“训练进步”...Verbose = false,...ValidationFrequency =地板(大小(trainPredictors 4) / miniBatchSize),...LearnRateSchedule =“分段”...LearnRateDropFactor = 0.9,...LearnRateDropPeriod = 1,...ValidationData = {validatePredictors, validateTargets});

使用指定的训练选项和层结构训练网络trainNetwork.由于训练集很大,训练过程可能需要几分钟。要下载和加载预训练的网络,而不是从头开始训练网络,请设置downloadPretrainedSystem真正的

downloadPretrainedSystem =如果downloadPretrainedSystem downloadFolder = matlab.internal.examples.download万博1manbetxSupportFile(“音频”“SpeechDenoising.zip”);dataFolder = tempdir;unzip(下载文件夹,数据文件夹)netFolder = fullfile(数据文件夹,数据文件夹)“SpeechDenoising”);s = load(fullfile(netFolder)“denoisenet.mat”));denoiseNetFullyConnected = s.denoiseNetFullyConnected;cleanMean = s.cleanMean;cleanStd = s.cleanStd;noisyMean = s.noisyMean;noisyStd = s.noisyStd;其他的denoiseNetFullyConnected = trainNetwork(trainPredictors,trainTargets,layers,options);结束

计算网络全连接层中的权重数。

numWeights = 0;index = 1: nummel (denoiseNetFullyConnected.Layers)如果isa (denoiseNetFullyConnected.Layers(指数),“nnet.cnn.layer.FullyConnectedLayer”) numWeights = numWeights + nummel (denoiseNetFullyConnected.Layers(index).Weights);结束结束disp ("权重数= "+ numWeights);
权重数= 2237440

卷积层语音去噪

考虑一个使用卷积层而不是全连接层的网络[3.].2-D卷积层对输入应用滑动滤波器。该层通过沿着输入垂直和水平移动滤波器和计算权重和输入的点积来卷积输入,然后添加一个偏置项。卷积层通常比全连接层包含更少的参数。

定义[中描述的全卷积网络的层3.],由16个卷积层组成。前15个卷积层是3层的组,重复5次,滤波器宽度分别为9、5和9,滤波器数量分别为18、30和8。最后一个卷积层的过滤器宽度为129,过滤器为1。在这个网络中,卷积只在一个方向上执行(沿频率维),并且对除第一个层外的所有层沿时间维的滤波器宽度设置为1。与全连接网络类似,卷积层之后是ReLu层和批归一化层。

layers =[imageInputLayer([numFeatures,numSegments]) convolution2dLayer([9 8],18,Stride=[1 100],Padding=“相同”) reluLayer repmat(...[convolution2dLayer([5 1],30,Stride=[1 100],Padding= .“相同”) batchNormalizationLayer reluLayer convolution2dLayer([9 1],8,Stride=[1 100],Padding=“相同”) batchNormalizationLayer reluLayer convolution2dLayer([9 1],18,Stride=[1 100],Padding=“相同”) batchNormalizationLayer relullayer],4,1) convolution2dLayer([5 1],30,Stride=[1 100],Padding=“相同”) batchNormalizationLayer reluLayer convolution2dLayer([9 1],8,Stride=[1 100],Padding=“相同”) batchNormalizationLayer reluLayer convolution2dLayer([129 1],1,Stride=[1 100],Padding=“相同”) regressionLayer];

训练选项与全连接网络的选项相同,除了验证目标信号的维度被排列以与回归层预期的维度一致。

选项= trainingOptions(“亚当”...MaxEpochs = 3,...InitialLearnRate e-5 = 1,...MiniBatchSize = MiniBatchSize,...洗牌=“every-epoch”...情节=“训练进步”...Verbose = false,...ValidationFrequency =地板(大小(trainPredictors 4) / miniBatchSize),...LearnRateSchedule =“分段”...LearnRateDropFactor = 0.9,...LearnRateDropPeriod = 1,...ValidationData={validatePredictors,permute(validateTargets,[3 1 2 4])});

使用指定的训练选项和层结构训练网络trainNetwork.由于训练集很大,训练过程可能需要几分钟。要下载和加载预训练的网络,而不是从头开始训练网络,请设置downloadPretrainedSystem真正的

downloadPretrainedSystem =如果downloadPretrainedSystem downloadFolder = matlab.internal.examples.download万博1manbetxSupportFile(“音频”“SpeechDenoising.zip”);dataFolder = tempdir;unzip(下载文件夹,数据文件夹)netFolder = fullfile(数据文件夹,数据文件夹)“SpeechDenoising”);s = load(fullfile(netFolder)“denoisenet.mat”));denoiseNetFullyConvolutional = s.denoiseNetFullyConvolutional;cleanMean = s.cleanMean;cleanStd = s.cleanStd;noisyMean = s.noisyMean;noisyStd = s.noisyStd;其他的denoiseNetFullyConvolutional = trainNetwork(trainPredictors,permute(trainTargets,[3 1 2 4]),layers,options);结束

计算网络全连接层中的权重数。

numWeights = 0;index = 1:numel(denoiseNetFullyConvolutional.Layers)如果isa (denoiseNetFullyConvolutional.Layers(指数),“nnet.cnn.layer.Convolution2DLayer”) numWeights = numWeights + nummel (denoiseNetFullyConvolutional.Layers(index).Weights);结束结束disp (卷积层的权重数=+ numWeights);
卷积层中的权重数= 31812

测试去噪网络

读入测试数据集。

adsTest = audioDatastore(fullfile(dataset,“测试”), IncludeSubfolders = true);

从数据存储中读取文件的内容。

[cleanAudio,adsTestInfo] = read(adsTest);

确保音频长度是采样率转换器抽取因子的倍数。

L = floor(numel(cleanAudio)/decimationFactor);cleanAudio = cleanAudio(1:decimationFactor*L);

将音频信号转换为8千赫。

cleanAudio = src(cleanAudio);重置(src)

在这个测试阶段,你用没有在训练阶段使用的洗衣机噪音破坏语音。

噪音= audieread (“洗衣机- 16 - 8 mono - 200 - secs.mp3”);

从洗衣机噪声向量中创建一个随机噪声段。

randind = randi(数字(噪音)-数字(cleanAudio), [1 1]);noisessegment = noise(randind:randind + numel(cleanAudio) - 1);

在语音信号中添加噪声,使信噪比为0 dB。

noisePower = sum(noisessegment .^2);cleanPower = sum(cleanAudio.^2);noiseSegment = noiseSegment.*sqrt(cleanPower/noisePower);noisyAudio = cleanAudio + noisessegment;

使用stft从噪声音频信号中生成幅度STFT向量。

noisySTFT = stft(noisyAudio,Window=win,OverlapLength=overlap,fftLength=fftLength);noisyPhase = angle(noisySTFT(numFeatures-1:end,:));noisySTFT = abs(noisySTFT(numFeatures-1:end,:));

从噪声STFT中生成8段训练预测器信号。连续预测因子之间的重叠为7段。

noisySTFT = [noisySTFT(:,1:numSegments-1) noisySTFT];predictors = 0 (numFeatures,numSegments,size(noisySTFT,2) - numSegments + 1);index = 1:(size(noisySTFT,2) - numSegments + 1) predictors(:,:,index) = noisySTFT(:,index:index + numSegments - 1);结束

用训练阶段计算的均值和标准差对预测因子进行归一化。

predictors(:) = (predictors(:) - noisyMean)/noisyStd;

计算去噪后的幅值STFT预测用两个训练好的网络。

predictors =重塑(predictors,[numFeatures,numSegments,1,size(predictors,3)]);STFTFullyConnected = predict(denoiseNetFullyConnected,predictors);STFTFullyConvolutional = predict(denoiseNetFullyConvolutional,predictors);

通过训练阶段使用的平均值和标准偏差来缩放输出。

STFTFullyConnected(:) = cleanStd*STFTFullyConnected(:) + cleanMean;STFTFullyConvolutional(:) = cleanStd*STFTFullyConvolutional(:) + cleanMean;

将单侧STFT转换为居中STFT。

STFTFullyConnected = (STFTFullyConnected.').*exp(1j*noisyPhase);STFTFullyConnected = [conj(STFTFullyConnected(end-1:-1:2,:));STFTFullyConnected];STFTFullyConvolutional = squeeze(STFTFullyConvolutional).*exp(1j*noisyPhase);STFTFullyConvolutional = [conj(STFTFullyConvolutional(end-1:-1:2,:));STFTFullyConvolutional];

计算去噪后的语音信号。istft执行逆STFT。利用噪声STFT矢量的相位重构时域信号。

denoisedAudioFullyConnected = istft(STFTFullyConnected,Window=win,OverlapLength=overlap,fftLength=fftLength,共轭对称=true);denoisedAudioFullyConvolutional = istft(STFTFullyConvolutional,Window=win,OverlapLength=overlap,fftLength=fftLength,共轭对称=true);

绘制干净、有噪声和去噪的音频信号。

t = (1/fs)*(0:numel(denoisedAudioFullyConnected)-1);图(3)tiledlayout(4,1) nexttile plot(t,cleanAudio(1:numel(denoisedAudioFullyConnected))“干净的演讲》网格)nexttile plot(t,noisyAudio(1:numel(降噪音频)))《吵闹的演讲》网格)nexttile plot(t,denoisedAudioFullyConnected)去噪语音(全连接层)网格)nexttile plot(t,denoisedAudioFullyConvolutional)去噪语音(卷积层)网格)包含(“时间(s)”

绘制干净、有噪声和去噪的声谱图。

H =图(4);tiledlayout(4,1) nexttile频谱图(cleanAudio,win,overlap,fftLength,fs);标题(“干净的演讲》网格)nexttile光谱图(noisyAudio赢,重叠,fftLength, fs);标题(《吵闹的演讲》网格)nexttile光谱图(denoisedAudioFullyConnected赢,重叠,fftLength, fs);标题(去噪语音(全连接层)网格)nexttile光谱图(denoisedAudioFullyConvolutional赢,重叠,fftLength, fs);标题(去噪语音(卷积层)网格)P = get(h,“位置”);集(h,“位置”,[p(1) 65 p(3) 800]);

听那嘈杂的讲话。

声音(noisyAudio fs)

从全连接层的网络中收听去噪的语音。

声音(denoisedAudioFullyConnected fs)

用卷积层听网络去噪后的语音。

声音(denoisedAudioFullyConvolutional fs)

听干净的演讲。

声音(cleanAudio fs)

您可以通过调用来测试来自数据存储的更多文件testDenoisingNets.该函数生成上面突出显示的时域和频域图,并返回干净的、有噪声的和去噪的音频信号。

[cleanAudio,noisyAudio,denoisedAudioFullyConnected,denoisedAudioFullyConvolutional] = testDenoisingNets(adsTest,denoiseNetFullyConnected,denoiseNetFullyConvolutional,noisyMean,noisyStd,cleanMean,cleanStd);

实时应用程序

前一节中的过程将噪声信号的整个频谱传递给预测.这不适用于需要低延迟的实时应用程序。

运行speechDenoisingRealtimeApp例如,如何模拟一个流,实时版本的去噪网络。该应用程序使用全连接层的网络。音频帧长度等于STFT跳长,即0.25 * 256 = 64个样本。

speechDenoisingRealtimeApp启动一个用于与模拟交互的用户界面(UI)。UI允许您调整参数,结果立即反映在模拟中。您还可以启用/禁用在去噪输出上运行的噪声门,以进一步降低噪声,以及调整噪声门的攻击时间、释放时间和阈值。您可以从UI中收听有噪声的、干净的或去噪的音频。

该范围绘制干净,噪声和去噪信号,以及噪声门的增益。

参考文献

[1]https://voice.mozilla.org/en

[2]“基于深度学习的语音去噪实验”,刘丁,Paris Smaragdis, Minje Kim, INTERSPEECH, 2014。

[3]“一种用于语音增强的全卷积神经网络”,Se Rim Park, Jin Won Lee, INTERSPEECH, 2017。