主要内容

学习使用深度学习的预强调过滤器

这个例子展示了如何使用卷积深度网络学习语音识别的预强调滤波器。该示例使用可学习的短时傅里叶变换(STFT)层来获得适合用于二维卷积层的时频表示。使用可学习的STFT可以对预强调过滤器权重进行基于梯度的优化。

数据

克隆或下载免费语音数字数据集(FSDD),可在https://github.com/Jakobovski/free-spoken-digit-dataset.FSDD是一个开放的数据集,这意味着它可以随着时间的推移而增长。本例使用了在2020年8月20日提交的版本,该版本包含了从6位说话者获得的3000个英语数字0到9的录音。采样频率为8000hz。

这个示例假设您已经将数据下载到与值对应的文件夹中tempdir在MATLAB。如果使用不同的文件夹,请将该文件夹名称替换为tempdir在下面的代码中。使用audioDatastore管理数据访问,并确保将数据随机划分为训练集和测试集。

pathToRecordingsFolder = fullfile(tempdir,“free-spoken-digit-dataset”“录音”);ads = audioDatastore(pathToRecordingsFolder);

使用filenames2labels函数从FSDD文件中获取标签的分类向量。显示数据集中每个标签的计数。

lbls = filenames2labels(ads,ExtractBefore=“_”);ads.Labels = lbls;countlabels (lbls)
ans =10×3表标签计数百分比_____ _____ _______ 0 300 10 1 300 10 2 300 10 3 300 10 4 300 10 5 300 10 6 300 10 7 300 10 8 300 10 9 300 10

将FSDD分割为训练集和测试集,在每个子集中保持相等的类比例。为了获得可重复的结果,请将随机数生成器设置为默认值。80%,也就是2400个录音被用于训练。剩下的600份录音,占总数的20%,被保留用于测试。在创建训练集和测试集之前,对数据存储中的文件进行一次洗牌。

rng默认的;广告= shuffle(广告);[adsTrain,adsTest] = splitEachLabel(ads,0.8,0.2);

FSDD中的录音长度不相等。使用转换,以便从数据存储中读取的每个数据都被填充或截断为8192个样本。数据还被转换为单精度,并应用z-score归一化。

transstrain = transform(adsTrain,@(x,info))“IncludeInfo”,真正的);transTest = transform(adsTest,@(x,info)helperReadData(x,info),“IncludeInfo”,真正的);

深度卷积神经网络(DCNN)架构

这个例子使用了一个自定义训练循环和下面的深度卷积网络。

numF = 12;dropoutProb = 0.2;layers = [sequenceInputLayer(1,“名字”“输入”的最小长度, 8192,...“归一化”“没有”1) convolution1dLayer(5日,“名称”“pre-emphasis-filter”...“WeightsInitializer”@(深圳)kronDelta(深圳),“BiasLearnRateFactor”, 0) stftLayer (“窗口”、汉明(1280)“OverlapLength”, 900,...“OutputMode”“空间”“名字”“STFT”numF) convolution2dLayer(5日,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer (3 2 * numF“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer (3 2 * numF“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”) batchNormalizationLayer reluLayer dropoutLayer(dropoutProb) globalAveragePooling2dLayer fullyConnectedLayer(numel(categories(ads.Labels)) softmaxLayer];Dlnet = dlnetwork(层);

序列输入层后面是一个由5个系数的单个滤波器组成的1-D卷积层。这是一个有限脉冲响应滤波器。深度学习网络中的卷积层默认情况下对输入特征执行仿射操作。若要获得严格的线性(筛选)操作,请使用默认值“BiasInitializer”这是“零”并设置该层的偏差学习率因子为0。这意味着偏差被初始化为0,并且在训练过程中永不改变。网络使用自定义初始化的过滤器权重为一个缩放的克罗内克增量序列。这是一个全通过滤器,它对输入不进行过滤。allpass过滤器权重初始化器的代码如下所示。

函数delta = kronDelta(sz)此函数仅用于“学习预强调过滤器的使用”深度学习的例子。它可以改变或删除%未来发布。L = sz(1);= 0 (L,sz(2),sz(3),“单一”);delta(1) = 1/√(L);结束

stftLayer取滤波后的输入信号,并得到它们的幅值stft。幅度STFT是信号的二维表示,适用于二维卷积网络。

虽然在训练过程中STFT的权重没有改变,但该层支持反向传播,这使得“预强调过滤器”层中的过滤器系数可以被学习。金宝app

网络训练

为自定义训练循环设置训练选项。使用70个epoch,小批大小为128。将初始学习速率设置为0.001。

NumEpochs = 70;miniBatchSize = 128;learnRate = 0.001;

在自定义训练循环中,使用minibatchqueue对象。的processSpeechMB函数读入一个小批处理,并对标签应用一热编码方案。

mbqTrain = minibatchqueue(transstrain,2,...“MiniBatchSize”miniBatchSize,...“MiniBatchFormat”, {“认知行为治疗”“CB”},...“MiniBatchFcn”, @processSpeechMB);

训练网络并绘制每次迭代的损失图。使用Adam优化器更新网络可学习参数。为训练进度绘制损失,设置值为进步在下面的代码中改为“training-progress”。

进步=“最终损失”如果进步= =“训练进步”图lineLossTrain = animatedline;Ylim ([0 inf]) xlabel(“迭代”) ylabel (“损失”网格)结束初始化一些训练循环变量trailingAvg = [];trailingAvgSq = [];迭代= 0;lossByIteration = 0;遍历epoch并计时开始= tic;epoch = 1:NumEpochs reset(mbqTrain) shuffle(mbqTrain)在小批上循环hasdata(mbqTrain)迭代=迭代+ 1;获得下一个小批量和一个热编码的目标[dlX,Y] = next(mbqTrain);评估模型梯度和损失[gradients, loss, state] = dlfeval(@modelGradSTFT,dlnet,dlX,Y);如果进步= =“最终损失”lossByIteration(迭代)=损失;结束更新网络状态dlnet。状态=状态;使用Adam优化器更新网络参数。[dlnet,trailingAvg,trailingAvgSq] = adamupdate(...dlnet、渐变trailingAvg trailingAvgSq,迭代,learnRate);%显示培训进度D = duration(0,0,toc(start),“格式”“hh: mm: ss”);如果进步= =“训练进步”addpoints (lineLossTrain、迭代、失去)标题(”时代:“+ epoch +,消失:"+字符串(D))结束结束disp (“epoch后的训练损失”+ epoch +”:“+损失);结束
历元后训练损失1:1.6774历元后训练损失2:1.0849历元后训练损失3:0.7954历元后训练损失4:0.43229历元后训练损失5:0.28836历元后训练损失6:0.264历元后训练损失7:0.24139历元后训练损失8:0.15673历元后训练损失9:0.1592历元后训练损失10:0.11318历元后训练损失11:0.12009历元后训练损失12:0.094991历元后训练损失13:0.17283历元后训练损失14:0.040015历元后训练损失15:0.049605历元后训练损失16:0.083731历元后训练损失17:0.078779历元后训练损失18:0.054683历元后训练损失19:0.027298历元后训练损失20:0.044558历元后训练损失21:0.044667历元后训练损失22:0.016505历元后训练损失23:0.049081历元后训练损失24:0.027639历元后训练损失25:0.043931历元后训练损失26:0.027954历元后训练损失27:0.019847历元后训练损失28:0.053152历元后训练损失29:0.013408历元后训练损失30:0.033531历元后训练损失31:0.04912历元后训练损失32:0.019765历元后训练损失33:0.045105历元后训练损失34:0.027663历元后训练损失35:0.059035历元后训练损失36:0.034425历元后训练损失37:0.030115历元后训练损失38:0.054834历元后训练损失39:0.010394历元后训练损失40:0.012589历元后训练损失41:0.02252历元后训练损失42:0.0066057历元后训练损失43:0.010897历元后训练损失44:0.003925历元后训练损失45:0.0061427历元后训练损失46:0.0085712历元后训练损失47:0.0040145历元后训练损失48:0.0044145历元后训练损失49:0.0025928纪元后的训练损失50:0.0041339纪元后的训练损失51:0.0044418纪元后的训练损失52:0.0023163纪元后的训练损失53:0.0024928纪元后的训练损失54:0.0028587纪元后的训练损失55:0.0055593纪元后的训练损失56:0.0024783纪元后的训练损失57:0.003228纪元后的训练损失58:0.0059129纪元后的训练损失59:0.0012979纪元后的训练损失60:0.0042822纪元后的训练损失61:0.0039421纪元后的训练损失62:0.011248纪元后的训练损失63:0.0012685纪元后的训练损失64:0.0024448纪元后的训练损失65:0.0028598纪元后的训练损失66:0.0015261纪元后的训练损失67:0.0013287纪元后的训练损失68:0.0030115纪元后的训练损失69:0.0094241纪元后的训练损失70:0.0031064
如果进步= =“最终损失”阴谋(1:迭代,lossByIteration)网格标题(“迭代导致的训练损失”)包含(“迭代”) ylabel (“损失”结束

在保留的测试集上测试训练好的网络。使用一个minibatchqueue对象的迷你批处理大小为32。

miniBatchSize = 32;mbqTest = minibatchqueue(transTest,2,...“MiniBatchSize”miniBatchSize,...“MiniBatchFormat”, {“认知行为治疗”“CB”},...“MiniBatchFcn”, @processSpeechMB);

遍历测试集并预测每个小批的类标签。

numObservations = numel(adsTest.Files);classes = string(唯一的(adsTest.Labels));预测= [];在小批上循环hasdata (mbqTest)读取小批数据dlX = next(mbqTest);对小批量进行预测dlYPred =预测(dlnet,dlX);确定对应的类predBatch = onehotdecode(dlYPred,classes,1);预测=[预测预批次];结束

评估在保留测试集中的600个示例上的分类准确性。

accuracy = mean(prediction ' == categorical(adsTest.Labels))
准确度= 0.9883

测试性能约为99%。您可以注释掉1-D卷积层,并在没有预强调过滤器的情况下重新训练网络。没有预强调滤波器的测试性能也很好,约为96%,但使用预强调滤波器使一个小的改善。值得注意的是,虽然使用习得的预强调滤波器仅略微提高了测试精度,但这是通过仅向网络添加5个可学习参数来实现的。

为了检查学习的预强调滤波器,提取1-D卷积层的权值。画出频率响应。回想一下,数据的采样频率是8千赫。因为我们将滤波器初始化为一个缩放的Kronecker delta序列(全通滤波器),所以我们可以很容易地将初始化滤波器的频率响应与学习到的响应进行比较。

FIRFilter = dlnet.Layers(2).Weights;[H,W] = freqz(FIRFilter,1,[],8000);delta = kronDelta([5 11 1]);Hinit = freqz(delta,1,[],4000);情节(W, 20 * log10 (abs ([H Hinit])),“线宽”, 2)网格包含(“赫兹”) ylabel (“数据库”)传说(学会过滤的“初始过滤”“位置”“东南”)标题(“学习预强调滤镜”

该示例展示了如何在基于信号的短时傅里叶变换的二维卷积网络中学习预强调滤波器作为预处理步骤。的能力stftLayer为了支金宝app持反向传播,在深度网络中启用基于梯度的过滤器权重优化。虽然这只导致网络在测试集上的性能有了很小的改进,但它实现了这种改进,可学习参数的数量增加了微不足道。

附录:Helper函数

函数[out,info] = helperReadData(x,info)此函数仅用于“学习预强调过滤器的使用”深度学习的例子。它可以改变或删除%未来发布。N =数字(x);X =单(X);如果N > 8192 x = x(1:8192);elseifN < 8192 pad = 8192-N;Prepad =地板(pad/2);Postpad = cell (pad/2);X = [0 (prepad,1);x;0 (postpad 1)];结束X = (X -mean(X))./std(X);X = X (:)';out = {x,info.Label};结束函数[dlX,dlY] = processSpeechMB(Xcell,Ycell)此函数仅用于“学习预强调过滤器的使用”深度学习的例子。它可以改变或删除%未来发布。Xcell = cellfun(@(x)重塑(x,1,1,[]),Xcell,“大学”、假);dlX = cat(2,Xcell{:});ly = cat(2,Ycell{:});dlY = onehotencode(dlY,1);结束函数[gradient,loss,state] = modelGradSTFT(net,X,T)此函数仅用于“学习预强调过滤器的使用”深度学习的例子。它可以改变或删除%未来发布。[y,state] = net.forward(X);损失=交叉熵(y,T);= dlgradient(loss,net.Learnables);损失= double(gather(extractdata(Loss)));结束

另请参阅

应用程序

对象

功能

相关的话题