这个例子展示了如何使用深度学习网络去噪语音信号。这个例子比较了应用于同一任务的两种类型的网络:全连接网络和卷积网络。
语音去噪的目的是去除语音信号中的噪声,同时提高语音的质量和清晰度。这个例子展示了使用深度学习网络从语音信号中去除洗衣机噪声。这个例子比较了应用于同一任务的两种类型的网络:全连接网络和卷积网络。
考虑以下在8khz采样的语音信号。
[cleanAudio, fs] = audioread (“SpeechDFT-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 Common Voice数据集的一个子集[1来训练和测试深度学习网络。该数据集包含受试者说短句的48千赫录音。下载数据集并解压缩下载的文件。
url =“http://ssd.mathworks.com/金宝appsupportfiles/audio/commonvoice.zip”;downloadFolder = tempdir;dataFolder = fullfile (downloadFolder,“无法推进”);如果~存在(dataFolder“dir”) disp (“下载数据集(956mb)…”解压缩(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,“周期”);重叠= round(0.75 * windowLength);ffTLength = windowLength;inputFs = 48 e3;fs = 8 e3;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 =地板(元素个数(音频)/ decimationFactor);音频=音频(1:decimationFactor * L);
转换音频信号到8千赫。
音频= src(音频);重置(src)
从洗衣机噪声向量中创建一个随机噪声段。
Randind = randi(numel(noise) - numel(audio),[1 1]);noise = noise(randind: randind + numel(audio) - 1);
在语音信号中加入噪声,使其信噪比为0 dB。
noisePower =总和(noiseSegment。^ 2);cleanPower =总和(音频。^ 2);* sqrt(cleanPower/noisePower);noisyAudio = audio + noisessegment;
使用stft
从原始的噪声音频信号中生成幅度STFT矢量。
cleanSTFT = stft(音频,“窗口”,赢了,“OverlapLength”重叠,“FFTLength”, ffTLength);cleanSTFT = abs (cleanSTFT (numFeatures-1:最终,));noisySTFT = stft (noisyAudio,“窗口”,赢了,“OverlapLength”重叠,“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:size(noisySTFT,2) - numSegments + 1 stftSegments(:,:,index) = (noisySTFT(:,index:index + numSegments - 1);结束
设定目标和预测因素。两个变量的最后一个维度对应于由音频文件生成的不同预测器/目标对的数量。每个预测器是129乘8,每个目标是129乘1。
目标= cleanSTFT;大小(目标)
ans =1×2129 544
预测= stftSegments;大小(预测)
ans =1×3129 8 544
为了加快处理速度,使用高数组从数据存储中所有音频文件的语音片段中提取特征序列。与内存中的数组不同,高数组通常保持未求值,直到调用收集
函数。这种延迟评估使您能够快速处理大型数据集。当您最终请求输出使用收集
, MATLAB在可能的情况下结合了排队计算,并获取通过数据的最小次数。如果您有Parallel Computing Toolbox™,您可以在本地MATLAB会话或本地并行池中使用高数组。如果您已经安装了MATLAB®Parallel Server™,您还可以在集群上运行高数组计算。
首先,将数据存储转换为一个高数组。
重置(adsTrain) T = tall(adsTrain)
使用“local”配置文件启动并行池(parpool)…连接到并行池(工作人员数量:6)。
T = M×1高细胞数组{234480×1双}{210288×1双}{282864×1双}{292080×1双}{410736×1双}{303600×1双}{326640×1双}{233328×1双}::::
该显示表明,行数(对应于数据存储中的文件数)M还不知道。M是一个占位符,直到计算完成。
从高表中提取目标和预测量的短时傅里叶变换。此操作将创建新的高数组变量以用于后续计算。这个函数HelperGenerateSpeechDenoisingFeatures
中高亮显示的步骤STFT目标和预测部分。的cellfun
命令适用于HelperGenerateSpeechDenoisingFeatures
到数据存储中每个音频文件的内容。
(目标,预测)= cellfun (@ (x) HelperGenerateSpeechDenoisingFeatures (x,噪音,src), T,“UniformOutput”、假);
使用收集
评价指标和预测指标。
(目标,预测)=收集(目标,预测);
使用Parallel Pool 'local'计算tall表达式:- Pass 1 of 1: Completed in 42 sec
将所有特征归一化为零均值和单位标准差是很好的做法。
分别计算预测指标和目标的均值和标准差,并使用它们对数据进行归一化。
预测=猫({}):3,预测指标;noisyMean =意味着(预测(:));noisyStd =性病(预测(:));predictors(:) = (predictors(:) - noisyMean)/noisyStd;目标=猫({}):2、目标;cleanMean =意味着(目标(:));cleanStd =性病(目标(:));targets(:) = (targets(:) - cleanMean)/cleanStd;
根据深度学习网络的预期维度重塑预测器和目标。
预测=重塑(预测、大小(预测,1),大小(预测,2),1,大小(预测,3));目标=重塑(目标1 1、大小(目标1),大小(目标2));
在培训期间,您将使用1%的数据进行验证。验证对于检测网络过度拟合训练数据的情况是有用的。
将数据随机分割为训练集和验证集。
第1 = randperm(大小(预测,4));L = round(0.99 * size(predictors,4));trainPredictors =预测(:,:,:,第1 (1:L));trainTargets =目标(:,:,:,第1 (1:L));validatePredictors =预测(:,:,:,第1 (L + 1:结束));validateTargets =目标(:,:,:,第1 (L + 1:结束));
首先考虑一个由完全连接的层组成的去噪网络。在完全连接层中的每个神经元都与前一层的所有激活相连接。一个完全连通的层将输入乘以一个权值矩阵,然后添加一个偏置向量。权值矩阵和偏置向量的维数由层中神经元的数量和前一层被激活的数量决定。
定义网络的层次。指定输入大小为图像的大小NumFeatures
——- - - - - -NumSegments
(本例中为129 × 8)。定义两个隐藏的完全连接层,每个层有1024个神经元。由于纯粹的线性系统,跟随每一个隐藏的全连接层与整流线性单元(ReLU)层。批处理归一化层对输出的平均值和标准偏差进行归一化。添加一个有129个神经元的完全连接层,然后是一个回归层。
layers = [imageInputLayer([numFeatures,numSegments]) fulllyconnectedlayer (1024) batchNormalizationLayer relullayer fulllyconnectedlayer (1024) batchNormalizationLayer relullayer fulllyconnectedlayer (numFeatures) regressionLayer];
接下来,为网络指定训练选项。集MaxEpochs
来3.
这样网络使3通过训练数据。集MiniBatchSize
的128
这样一来,这个网络一次就能看到128个训练信号。指定情节
作为“训练进步”
生成随着迭代次数增加而显示训练进度的图。集详细的
来假
禁用将与绘图中显示的数据相对应的表输出打印到命令行窗口。指定洗牌
作为“every-epoch”
在每个纪元开始时打乱训练序列。指定LearnRateSchedule
来“分段”
每通过一定数量的纪元(1),学习率就降低一个指定的因子(0.9)。集ValidationData
到验证预测因子和目标。集ValidationFrequency
以便每个历元计算一次验证均方误差。这个例子使用自适应矩估计(Adam)求解器。
miniBatchSize = 128;选择= trainingOptions (“亚当”,...“MaxEpochs”3,...“InitialLearnRate”1 e-5...“MiniBatchSize”miniBatchSize,...“洗牌”,“every-epoch”,...“阴谋”,“训练进步”,...“详细”假的,...“ValidationFrequency”、地板(大小(trainPredictors, 4) / miniBatchSize),...“LearnRateSchedule”,“分段”,...“LearnRateDropFactor”, 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 =加载(fullfile (netFolder“denoisenet.mat”));denoiseNetFullyConnected = s.denoiseNetFullyConnected;cleanMean = s.cleanMean;cleanStd = s.cleanStd;noisyMean = s.noisyMean;noisyStd = s.noisyStd;结束
计算网络中完全连接层的权重数。
numWeights = 0;为指数= 1:元素个数(denoiseNetFullyConnected.Layers)如果isa (denoiseNetFullyConnected.Layers(指数),“nnet.cnn.layer.FullyConnectedLayer”) numWeights = numWeights + nummel (denoiseNetFullyConnected.Layers(index).Weights);结束结束流("权重的数量为%d.\n", numWeights);
重量的数量是2237440。
考虑一个使用卷积层而不是完全连接层的网络[3.].二维卷积层将滑动滤波器应用于输入。该层通过沿输入垂直和水平移动滤波器,计算权重和输入的点积,然后添加偏差项,对输入进行卷积。卷积层通常比完全连接层包含更少的参数。
定义中描述的全卷积网络的层次[3.,由16个卷积层组成。前15个卷积层为3层一组,重复5次,滤波器宽度分别为9、5、9,滤波器数量分别为18、30、8。最后一个卷积层的滤镜宽度为129和1。在该网络中,只在一个方向(沿频率维度)进行卷积,除第一层外,所有层沿时间维度的滤波器宽度均设为1。与全连接网络类似,卷积层之后是ReLu层和批处理归一化层。
images = [imageInputLayer([numFeatures,numSegments]))“步”100年[1],“填充”,“相同”) batchNormalizationLayer reluLayer repmat(...30岁的[convolution2dLayer (1 [5]“步”100年[1],“填充”,“相同”reluLayer卷积2dlayer ([9 1],8,“步”100年[1],“填充”,“相同”reluLayer卷积2dlayer ([9 1],18,“步”100年[1],“填充”,“相同”) batchNormalizationLayer reluLayer],4,1) convolution2dLayer([5 1],30,“步”100年[1],“填充”,“相同”reluLayer卷积2dlayer ([9 1],8,“步”100年[1],“填充”,“相同”reluLayer卷积2dlayer ([129 1],1,“步”100年[1],“填充”,“相同”) regressionLayer);
训练选项与全连接网络的选项相同,除了验证目标信号的维度被排列成与回归层预期的维度一致。
选择= trainingOptions (“亚当”,...“MaxEpochs”3,...“InitialLearnRate”1 e-5...“MiniBatchSize”miniBatchSize,...“洗牌”,“every-epoch”,...“阴谋”,“训练进步”,...“详细”假的,...“ValidationFrequency”、地板(大小(trainPredictors, 4) / miniBatchSize),...“LearnRateSchedule”,“分段”,...“LearnRateDropFactor”, 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 =加载(fullfile (netFolder“denoisenet.mat”));denoiseNetFullyConvolutional = s.denoiseNetFullyConvolutional;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 + nummel (denoiseNetFullyConvolutional.Layers(index).Weights);结束结束流(“卷积层中的权重数为%d\n”, numWeights);
卷积层中的权值为31812
读取测试数据集。
adsTest = audioDatastore (fullfile (dataFolder“测试”),“IncludeSubfolders”,真正的);
从数据存储中读取文件的内容。
[cleanAudio, adsTestInfo] =阅读(adsTest);
确保音频长度是采样率转换器抽取因子的倍数。
L =地板(元素个数(cleanAudio) / decimationFactor);cleanAudio = cleanAudio (1: decimationFactor * L);
转换音频信号到8千赫。
cleanAudio = src (cleanAudio);重置(src)
在这个测试阶段,你用没有在训练阶段使用的洗衣机噪音来破坏语言。
噪音= audioread (“洗衣机- 16 - 8 mono - 200 - secs.mp3”);
从洗衣机噪声向量中创建一个随机噪声段。
randind = randi(numel(noise) - numel(cleanAudio), [1 1]);noiseSegment = noise(randind: randind + numel(cleanAudio) - 1);
在语音信号中加入噪声,使其信噪比为0 dB。
noisePower =总和(noiseSegment。^ 2);cleanPower =总和(cleanAudio。^ 2);* sqrt(cleanPower/noisePower);noisyAudio = cleanAudio + noisessegment;
使用stft
从噪声音频信号中生成幅度STFT矢量。
noisySTFT = stft (noisyAudio,“窗口”,赢了,“OverlapLength”重叠,“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:(size(noisySTFT,2) - numSegments + 1) predictors(:,:,index) = noisySTFT(:,index:index + numSegments - 1);结束
用在训练阶段计算的平均值和标准偏差对预测器进行归一化。
predictors(:) = (predictors(:) - noisyMean) / noisyStd;
利用短时傅立叶变换计算去噪幅度预测
两个训练有素的网络。
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。利用噪声短时傅立叶变换矢量的相位重构时域信号。
denoisedAudioFullyConnected = istft (STFTFullyConnected,...“窗口”,赢了,“OverlapLength”重叠,...“FFTLength”ffTLength,“ConjugateSymmetric”,真正的);denoisedAudioFullyConvolutional = istft (STFTFullyConvolutional,...“窗口”,赢了,“OverlapLength”重叠,...“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)标题(去噪语音(卷积层)网格)在包含(“时间(s)”)
绘制干净的、有噪声的和去噪的光谱图。
h =图;次要情节(4 1 1)谱图(ffTLength cleanAudio,赢,重叠,fs);标题(“干净的演讲》网格)在次要情节(1、2)谱图(ffTLength noisyAudio,赢,重叠,fs);标题(《吵闹的演讲》网格)在次要情节(4 1 3)谱图(ffTLength denoisedAudioFullyConnected,赢,重叠,fs);标题(“去噪语音(全连接层)”网格)在次要情节(4,4)谱图(ffTLength denoisedAudioFullyConvolutional,赢,重叠,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]“基于深度学习的语音去噪实验”,Ding Liu, Paris Smaragdis, Minje Kim, INTERSPEECH, 2014。
[3]“用于语音增强的全卷积神经网络”,Se Rim Park, Jin Won Lee, INTERSPEECH, 2017。