这个例子展示了如何使用深度学习网络去噪语音信号。这个例子比较了应用于同一任务的两种类型的网络:全连接网络和卷积网络。
言语去噪的目的是消除语音信号的噪声,同时提高语音的质量和可懂度。该示例展示了使用深度学习网络从语音信号中移除洗衣机噪声。这个例子比较了应用于同一任务的两种类型的网络:全连接网络和卷积网络。
考虑在8 kHz时采样的以下语音信号。
[Cleanaudio,FS] = audioread(“speemdft-16-8-mono-5secs.wav”);声音(cleanAudio fs)
在语音信号中加入洗衣机的噪音。设置噪声功率使信噪比(SNR)为零dB。
噪音= audioread (“洗衣机- 16 - 8 mono - 1000 - secs.mp3”);%从噪声文件中的随机位置提取噪声段= randi(numel(noise) - numel(cleanAudio) + 1,1,1);noiseSegment = noise(ind:ind + numel(cleanAudio) - 1);speechPower =总和(cleanAudio。^ 2);noisePower =总和(noiseSegment。^ 2);noisyAudio = cleanAudio + sqrt(speechPower/noisePower) * noisessegment;
听嘈杂的语音信号。
声音(Noisyaudio,FS)
可视化原始和嘈杂的信号。
t = (1/fs) * (0:numel(cleanAudio)-1);次要情节(2,1,1)情节(t, cleanAudio)标题(“干净音频”) 网格在次要情节(2,1,2)情节(t, noisyAudio)标题(“嘈杂的声音”)包含(“时间(s)”) 网格在
语音去噪的目的是去除语音信号中的洗衣机噪声,同时最小化输出语音中不希望出现的伪影。
此示例使用Mozilla公共语音数据集的子集[1]培训和测试深度学习网络。数据集包含讲短句的主题的48 kHz录制。下载数据集并解压缩下载的文件。
URL =.“http://ssd.mathworks.com/金宝appsupportfiles/audio/commonvoice.zip”;downloadfolder = tempdir;datafolder = fullfile(downloadlefolder,“无法推进”);如果〜存在(DataFolder,'dir') disp ('下载数据集(956 MB)......')解压缩(URL,DownloadFolder)结束
使用audioDatastore
为训练集创建数据存储。要以牺牲性能为代价加快示例的运行时,请设置reduceDataset
到真正的
.
adstrain = audiodataStore(fullfile(datafolder,“火车”),“IncludeSubfolders”,真正的);reduceDataset =真正的;如果reduceDataset adsTrain = shuffle(adsTrain);adsTrain =子集(adsTrain 1:1000);结束
使用读
获取数据存储中第一个文件的内容。
[音频、adsTrainInfo] =阅读(adsTrain);
听语音信号。
声音(音频,adstraininfo.samplerate)
画出语音信号。
图t = (1/adsTrainInfo.SampleRate) * (0:numel(音频)-1);情节(t,音频)标题(“示例性语音信号”)包含(“时间(s)”) 网格在
基本的深度学习训练方案如下图所示。请注意,由于语音通常低于4khz,您首先将干净和嘈杂的音频信号采样到8khz,以减少网络的计算负载。预测器和目标网络信号分别是噪声和纯净音频信号的幅值谱。网络的输出是去噪后信号的幅值谱。回归网络使用预测输入来最小化其输出和输入目标之间的均方误差。去噪后的音频通过输出幅度谱和噪声信号的相位被转换回时域[2].
使用短时傅里叶变换(STFT)将音频转换到频域,窗长为256个样本,重叠率为75%,还有一个汉明窗。通过减少与负频率相对应的频率样本,可以将频谱向量的大小减少到129(因为时域语音信号是真实的,这不会导致任何信息丢失)。预测器的输入由8个连续的带噪声的STFT向量组成,因此每个STFT的输出估计是基于当前带噪声的STFT和之前的7个带噪声的STFT向量来计算的。
本节说明了如何从一个训练文件生成目标和预测信号。
一、定义系统参数:
windowLength = 256;赢得=汉明(windowLength,“周期”);重叠=圆形(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,......“带宽”, 7920);
使用读
从数据存储中获取音频文件的内容。
音频=阅读(adsTrain);
确保音频长度是采样率转换器抽取因子的倍数。
decimationFactor = InputFS / FS;L =楼层(NUMER(音频)/抽取物质);音频=音频(1:DecimationFactor * L);
将音频信号转换为8 kHz。
音频= src(音频);重置(SRC)
从洗衣机噪声向量中创建一个随机噪声段。
Randind = randi(numel(noise) - numel(audio),[1 1]);noise = noise(randind: randind + numel(audio) - 1);
在语音信号中加入噪声,使其信噪比为0 dB。
noisePower =总和(noiseSegment。^ 2);CleanPower = Sum(音频。^ 2);noisesement = noisesegment。* sqrt(CleanPower / Noispower);noisyaudio =音频+ noisesement;
使用st
从原始和嘈杂的音频信号生成幅度STFT向量。
cleanSTFT = stft(音频,'窗户',赢,'overlaplencth',重叠,“FFTLength”, ffTLength);CleanStft = ABS(CleanStft(NumFeatures-1:结束,:));noisySTFT = stft (noisyAudio,'窗户',赢,'overlaplencth',重叠,“FFTLength”, ffTLength);noisySTFT = abs (noisySTFT (numFeatures-1:最终,));
从带噪声的短时傅立叶变换生成8段训练预测信号。连续预测器之间的重叠是7个部分。
noisySTFT = [noisySTFT(:,1:numSegments - 1), noisySTFT];stftSegments = 0 (numFeatures, numSegments, size(noisySTFT,2) - numSegments + 1);为索引= 1:大小(诺斯YSTFT,2) - NumSegments + 1 Stftegments(::,索引)=(诺斯YSTFT(:,索引:索引+ Numegments - 1));结束
设定目标和预测因素。两个变量的最后一个维度对应于由音频文件生成的不同预测器/目标对的数量。每个预测器是129乘8,每个目标是129乘1。
目标= CleanStft;尺寸(目标)
ans =1×2129 544.
预测器= Stftegments;大小(预测器)
ans =1×3129 8 544
为了加快处理速度,使用高数组从数据存储中所有音频文件的语音片段中提取特征序列。与内存中的数组不同,高数组通常保持未求值,直到调用收集
函数。这种延迟评估使您能够快速处理大型数据集。当您最终请求输出使用收集
,Matlab在可能的情况下结合了排队的计算,并通过数据占据最小次数。如果您有并行计算工具箱™,则可以在本地MATLAB会话中或在本地并行池中使用高阵列。如果安装了MATLAB®PartinalServer™,您还可以在群集中运行高阵列计算。
首先,将数据存储转换为一个高数组。
重置(adsTrain) T = tall(adsTrain)
使用“local”配置文件启动并行池(parpool)…连接到并行池(工作人员数量:6)。
t = m×1高级小区{234480×1 double} {210288×1 double} {282864×1 double} {292080×1 double} {410736×1 double} {303600×1 double} {326640×1 double}{233328×1双} ::::::::::::
该显示表明,行数(对应于数据存储中的文件数)M还不知道。M是一个占位符,直到计算完成。
从高表中提取目标和预测量的短时傅里叶变换。此操作将创建新的高数组变量以用于后续计算。这个函数HelpergeneratesPeepeehoisingFeatures.
中高亮显示的步骤STFT目标和预测部分。这Cellfun.
命令适用于HelpergeneratesPeepeehoisingFeatures.
到数据存储中每个音频文件的内容。
(目标,预测)= cellfun (@ (x) HelperGenerateSpeechDenoisingFeatures (x,噪音,src), T,“UniformOutput”、假);
使用收集
评估目标和预测因子。
(目标,预测)=收集(目标,预测);
使用并行池“本地”评估高表达: - PASS 1为1:42秒评估完成1分36秒
将所有特征归一化为零均值和单位标准差是很好的做法。
分别计算预测指标和目标的均值和标准差,并使用它们对数据进行归一化。
预测=猫({}):3,预测指标;noisyMean =意味着(预测(:));noisyStd =性病(预测(:));predictors(:) = (predictors(:) - noisyMean)/noisyStd;目标=猫({}):2、目标;cleanMean =意味着(目标(:));cleanStd =性病(目标(:));targets(:) = (targets(:) - cleanMean)/cleanStd;
根据深度学习网络的预期维度重塑预测器和目标。
预测=重塑(预测、大小(预测,1),大小(预测,2),1,大小(预测,3));目标=重塑(目标1 1、大小(目标1),大小(目标2));
在培训期间,您将使用1%的数据进行验证。验证对于检测网络过度拟合训练数据的情况是有用的。
随机将数据拆分为培训和验证集。
inds = randperm(大小(预测器,4));l =圆形(0.99 *尺寸(预测器,4));TrainPredictors =预测因子(::::,Inds(1:L));三raintargets=目标(::::,INDS(1:L));validatepredictors =预测器(:,:,:,inds(l + 1:结束));validatetargets = targets(:,::,Inds(L + 1:结束));
首先考虑一个由完全连接的层组成的去噪网络。在完全连接层中的每个神经元都与前一层的所有激活相连接。一个完全连通的层将输入乘以一个权值矩阵,然后添加一个偏置向量。权值矩阵和偏置向量的维数由层中神经元的数量和前一层被激活的数量决定。
定义网络的层次。指定输入大小为图像的大小numfeatures.
-经过-NumSegments
(在这个例子中129-by-8)。定义两个隐藏的完全连接的层,每个层都有1024个神经元。由于纯粹的线性系统,请使用整流的线性单元(Relu)层遵循每个隐藏的完全连接的层。批量归一化层标准化输出的平均值和标准偏差。用129神经元添加完全连接的层,然后是回归层。
图层= [imageInputlayer([NumFeatures,NumSegments])全连接列(1024)BatchnormalizationLayer QualtConnectedLayer(1024)BatchnormalizationLayer Rublayer完全连接列(NumFeatures)回归层];
接下来,指定网络的培训选项。集maxepochs.
到3.
这样网络使3通过训练数据。集MiniBatchSize
的128
因此,网络一次查看128个训练信号。指定绘图
作为“训练进步”
当迭代次数增加时,生成显示培训进度的地块。集详细的
到假
禁用将与绘图中显示的数据相对应的表输出打印到命令行窗口。指定洗牌
作为“每个时代”
在每个时代开始时播放训练序列。指定LearnRateSchedule
到“分段”
每次通过一定数量的时期(1)都会通过指定因素(0.9)减少学习率。集ValidationData
验证预测器和目标。集ValidationFrequency
以便每个历元计算一次验证均方误差。这个例子使用自适应矩估计(Adam)求解器。
miniBatchSize = 128;选择= trainingOptions (“亚当”,......“maxepochs”,3,......“initiallearnrate”1 e-5......“MiniBatchSize”,小匹马,......“洗牌”,“每个时代”,......“阴谋”,“训练进步”,......“详细”假的,......“验证职业”、地板(大小(trainPredictors, 4) / miniBatchSize),......“LearnRateSchedule”,“分段”,......“学习ropfactor”, 0.9,......“LearnRateDropPeriod”,1,......“ValidationData”, {validatePredictors, validateTargets});
使用指定的培训选项和图层架构培训网络trainNetwork
.由于训练集很大,训练过程可能需要几分钟。要下载和加载预先训练过的网络,而不是从头开始训练网络,请设置doTraining
到假
.
dotraining =.真正的;如果doTraining denoiseNetFullyConnected = trainNetwork(trainPredictors,trainTargets,layers,options);其他的URL =.“http://ssd.mathworks.com/金宝appsupportfiles/audio/SpeechDenoising.zip”;downloadNetFolder = tempdir;netFolder = fullfile (downloadNetFolder,“SpeechDenoising”);如果~存在(netFolder'dir') disp ('下载预训练网络(1文件- 8mb)…')解压缩(URL,DownloadNetFolder)结束s = load(fullfile(netfolder,“denoisenet.mat”));denoiseNetFullyConnected = s.denoiseNetFullyConnected;cleanMean = s.cleanMean;cleanStd = s.cleanStd;noisyMean = s.noisyMean;noisyStd = s.noisyStd;结束
计算网络中完全连接层的权重数。
numWeights = 0;为index = 1:numel(denoisenetluelyconnected.layers)如果ISA(denoisenetluelyconnected.layers(指数),“nnet.cnn.layer.FullyConnectedLayer”)Numweights = Numpeights + Numel(denoisenetluelyconnected.layers(索引).weights);结束结束流("权重的数量为%d.\n",数字);
权重的数量为2237440。
考虑一个使用卷积层而不是完全连接层的网络[3.].二维卷积层将滑动滤波器应用于输入。该层通过沿输入垂直和水平移动滤波器,计算权重和输入的点积,然后添加偏差项,对输入进行卷积。卷积层通常比完全连接层包含更少的参数。
定义[中描述的完全卷积网络的图层3.,由16个卷积层组成。前15个卷积层为3层一组,重复5次,滤波器宽度分别为9、5、9,滤波器数量分别为18、30、8。最后一个卷积层的滤镜宽度为129和1。在该网络中,只在一个方向(沿频率维度)进行卷积,除第一层外,所有层沿时间维度的滤波器宽度均设为1。与全连接网络类似,卷积层之后是ReLu层和批处理归一化层。
图层= [ImageInputLayer([NumFeatures,NumSegments])卷积2dlayer([9 8],18,“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Rubulayer Repmat(......30岁的[convolution2dLayer (1 [5]“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Rufulayer卷积2dlayer([9 1],8,“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Rufulayer卷积2dlayer([9 1],18,“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Ruilulayer],4,1)卷积2dlayer([5 1],30,“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Rufulayer卷积2dlayer([9 1],8,“步幅”100年[1],“填充”,“相同”)BatchnormalizationLayer Rufulayer卷积2dlayer([129 1],1,“步幅”100年[1],“填充”,“相同”) regressionLayer);
培训选项与完全连接网络的选项相同,不同之处在于允许验证目标信号的尺寸符合回归层预期的尺寸。
选择= trainingOptions (“亚当”,......“maxepochs”,3,......“initiallearnrate”1 e-5......“MiniBatchSize”,小匹马,......“洗牌”,“每个时代”,......“阴谋”,“训练进步”,......“详细”假的,......“验证职业”、地板(大小(trainPredictors, 4) / miniBatchSize),......“LearnRateSchedule”,“分段”,......“学习ropfactor”, 0.9,......“LearnRateDropPeriod”,1,......“ValidationData”,{validatePredictors,permute(validateTargets,[3 1 2 4])});
使用指定的培训选项和图层架构培训网络trainNetwork
.由于训练集很大,训练过程可能需要几分钟。要下载和加载预先训练过的网络,而不是从头开始训练网络,请设置doTraining
到假
.
dotraining =.真正的;如果doTraining denoisenetfully卷积= trainNetwork(trainPredictors,permute(trainTargets,[3 1 2 4]),layers,options);其他的URL =.“http://ssd.mathworks.com/金宝appsupportfiles/audio/SpeechDenoising.zip”;downloadNetFolder = tempdir;netFolder = fullfile (downloadNetFolder,“SpeechDenoising”);如果~存在(netFolder'dir') disp ('下载预训练网络(1文件- 8mb)…')解压缩(URL,DownloadNetFolder)结束s = load(fullfile(netfolder,“denoisenet.mat”));denoisenetlulyconstooldal = s.denoisenetfullycollycollyal;cleanMean = s.cleanMean;cleanStd = s.cleanStd;noisyMean = s.noisyMean;noisyStd = s.noisyStd;结束
计算网络中完全连接层的权重数。
numWeights = 0;为指数= 1:元素个数(denoiseNetFullyConvolutional.Layers)如果isa (denoiseNetFullyConvolutional.Layers(指数),“nnet.cnn.layer.Convolution2DLayer”)Numweights = Numweights + Numel(denoisenetfullyconstoolvolultal.layers(索引)。重量);结束结束流(“卷积层中的权重数为%d\n”,数字);
卷积层中的重量数为31812
在测试数据集中读取。
adstest = audiodataStore(fullfile(datafolder,'测试'),“IncludeSubfolders”,真正的);
从数据存储读取文件的内容。
[cleanAudio, adsTestInfo] =阅读(adsTest);
确保音频长度是采样率转换器抽取因子的倍数。
L =楼层(Numel(Cleanaudio)/ DecimationFactor);CleanAudio = CleanAudio(1:DecimationFactor * L);
将音频信号转换为8 kHz。
CleanAudio = SRC(CleanAudio);重置(SRC)
在这个测试阶段,您腐败了训练阶段的洗衣机噪音的语音。
噪音= audioread (“洗衣机- 16 - 8 mono - 200 - secs.mp3”);
从洗衣机噪声向量中创建一个随机噪声段。
randind = randi(numel(噪声) - numel(cleanaudio),[1 1]);noisesement =噪音(Randind:Randind + Numel(CleanAudio) - 1);
在语音信号中加入噪声,使其信噪比为0 dB。
noisePower =总和(noiseSegment。^ 2);CleanPower = Sum(CleanAudio。^ 2);noisesement = noisesegment。* sqrt(CleanPower / Noispower);Noisyaudio = Cleanaudio + Noisesement;
使用st
从噪声音频信号中生成幅度STFT矢量。
noisySTFT = stft (noisyAudio,'窗户',赢,'overlaplencth',重叠,“FFTLength”, ffTLength);noisyPhase =角(noisySTFT (numFeatures-1:最终,));noisySTFT = abs (noisySTFT (numFeatures-1:最终,));
从带噪声的短时傅立叶变换生成8段训练预测信号。连续预测器之间的重叠是7个部分。
noisySTFT = [noisySTFT(:,1:numSegments-1) noisySTFT];predictors = 0 (numFeatures, numSegments, size(noisySTFT,2) - numSegments + 1);为index = 1 :(大小(诺斯YSTFT,2) - NumSegments + 1)预测器(:,索引)=诺斯YSTFT(:,索引:索引+ NumSegments - 1);结束
通过训练阶段计算的平均值和标准偏差来对预测器进行归一化。
预测器(:) =(预测器(:) - Noisemean)/诺斯YSTD;
通过使用计算去噪幅度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;
将单侧短时傅里叶变换为中心短时傅里叶变换。
STFTFullyConnected = STFTFullyConnected。”。* exp (1 j * noisyPhase);STFTFullyConnected =[连词(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,......'窗户',赢,'overlaplencth',重叠,......“FFTLength”ffTLength,“ConjugateSymmetric”,真正的);denoisedaudiofullyconvolutional = istft(stftfullfollycollyal,......'窗户',赢,'overlaplencth',重叠,......“FFTLength”ffTLength,“ConjugateSymmetric”,真正的);
绘制干净的、有噪声的和去噪的音频信号。
t = (1/fs) * (0:numel(denoisedAudioFullyConnected)-1); / /文件大小图subplot(4,1,1) plot(t,cleanAudio(1:numel(denoisedAudioFullyConnected))) title(“清洁演讲”) 网格在次要情节(1、2)情节(t, noisyAudio(1:元素个数(denoisedAudioFullyConnected)))标题(“吵闹的演讲”) 网格在子图(4,1,3)绘图(T,DenoisedaudiofullyConnected)标题(“去噪语音(全连接层)”) 网格在次要情节(4,4)情节(t, denoisedAudioFullyConvolutional)标题(“去噪(卷积层)”) 网格在Xlabel(“时间(s)”)
绘制干净的、有噪声的和去噪的光谱图。
h =图;次要情节(4 1 1)谱图(ffTLength cleanAudio,赢,重叠,fs);标题(“清洁演讲”) 网格在次要情节(1、2)谱图(ffTLength noisyAudio,赢,重叠,fs);标题(“吵闹的演讲”) 网格在次要情节(4 1 3)谱图(ffTLength denoisedAudioFullyConnected,赢,重叠,fs);标题(“去噪语音(全连接层)”) 网格在子图(4,1,4)频谱图(denoisedaudiofullyconstoolly,Win,重叠,FFTLength,FS);标题(“去噪(卷积层)”) 网格在p = get (h,'位置');套(h,'位置',[p(1) 65 p(3) 800]);
听这嘈杂的演讲。
声音(Noisyaudio,FS)
通过完全连接的图层从网络中聆听去噪语音。
声音(DenoisedAudiofullyConnected,FS)
用卷积层聆听来自网络的去噪语音。
声音(DenoisedAudiofullycollyoollyal,FS)
听干净的演讲。
声音(cleanAudio fs)
您可以通过调用testDenoisingNets
.该函数生成上述突出显示的时域和频域图,并返回干净的、有噪声的和去噪的音频信号。
[cleanAudio, noisyAudio denoisedAudioFullyConnected denoisedAudioFullyConvolutional] = testDenoisingNets (adsTest、denoiseNetFullyConnected denoiseNetFullyConvolutional, noisyMean, noisyStd, cleanMean, cleanStd);
上一节的程序将噪声信号的整个频谱传递到预测
.这不适用于要求低延迟的实时应用程序。
跑步SpeemDenoiseRealtimeApp.
有关如何模拟媒体的媒体的实时版本的示例。该应用程序使用具有完全连接的图层的网络。音频帧长度等于STFT跳尺寸,即0.25 * 256 = 64个样本。
SpeemDenoiseRealtimeApp.
启动设计用于与仿真交互的用户界面(UI)。UI使您能够对参数进行优化,结果会立即反映在模拟中。您还可以启用/禁用噪声门,该噪声门对去噪输出进行操作,以进一步降低噪声,并调整攻击时间、释放时间和噪声门的阈值。你可以从UI中听到嘈杂的、干净的或去噪的音频。
范围绘制干净,嘈杂和去噪的信号,以及噪声门的增益。
[1]https://voice.mozilla.org/en
[2]“基于深度学习的语音去噪实验”,Ding Liu, Paris Smaragdis, Minje Kim, INTERSPEECH, 2014。
[3]“用于语音增强的全卷积神经网络”,Se Rim Park, Jin Won Lee, INTERSPEECH, 2017。