主要内容

基于小波散射和深度学习的语音数字识别

这个例子展示了如何使用机器和深度学习技术对语音数字进行分类。在本例中,使用支持向量机(SVM)和长短期记忆(LSTM)网络的小波时间散射执行分类。万博1manbetx您还应用贝叶斯优化来确定合适的超参数,以提高LSTM网络的精度。此外,该示例说明了使用深度卷积神经网络(CNN)和mel频率谱图的方法。

数据

克隆或下载免费语音数字数据集(FSDD),可在https://github.com/Jakobovski/free-spoken-digit-dataset。FSDD是一个开放的数据集,这意味着它可以随着时间的推移而增长。本例使用的是2019年1月29日提交的版本,该版本由4位演讲者提供的2000份数字0到9的英语录音组成。在这个版本中,有两个说话者的母语是美式英语,一个说话者的母语是非英语,带有比利时法语口音,还有一个说话者的母语是非英语,带有德国口音。采样频率为8000hz。

使用audioDatastore管理数据访问,确保录音随机分为训练集和测试集。设置位置属性到您的计算机上的FSDD录音文件夹的位置,例如:

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

audioDatastore去那个地方。

ads = audioDatastore(location);

辅助函数helpergenLabels从FSDD文件创建标签的分类数组。的源代码helpergenLabels在附录中列出。列出类和每个类中的示例数量。

ads. labels = helpergenLabels(广告);总结(ads.Labels)
0 300 1 300 2 300 3 300 4 300 5 300 6 300 7 300 8 300 9 300

FSDD数据集由10个平衡的类组成,每个类有200个记录。FSDD中的录音时长不相等。FSDD并不是太大,所以阅读FSDD文件并构造信号长度的直方图。

LenSig = 0(数字(ads.Files),1);Nr = 1;Hasdata(广告)数字=读(广告);LenSig(nr) =数字(数字);Nr = Nr +1;结束重置(广告)直方图(LenSig)网格包含(“信号长度(样本)”) ylabel (“频率”

直方图显示记录长度的分布正偏。为了分类,本例使用8192个样本的公共信号长度,这是一个保守值,确保截断较长的录音不会切断语音内容。如果信号长度大于8192个样本(1.024秒),则记录被截断为8192个样本。如果信号的长度小于8192个样本,则对信号进行对称的预加和后加,使其长度为8192个样本。

小波时间散射

使用waveletScattering使用0.22秒不变尺度创建小波时间散射框架。在本例中,通过对所有时间样本的散射变换求平均值来创建特征向量。要在每个时间窗口中有足够数量的散射系数进行平均,请设置OversamplingFactor到2,使每条路径的散射系数数量相对于临界下采样值增加4倍。

sf =小波散射(“SignalLength”, 8192,“InvarianceScale”, 0.22,...“SamplingFrequency”, 8000,“OversamplingFactor”2);

将FSDD分为训练集和测试集。将80%的数据分配给训练集,并保留20%的数据给测试集。训练数据用于训练基于散射变换的分类器。试验数据用于验证模型。

rng默认的;广告= shuffle(广告);[adsTrain,adsTest] = splitEachLabel(ads,0.8);countEachLabel (adsTrain)
ans =10×2表标签计数_____ _____ 0 240 1 240 2 240 3 240 4 240 5 240 6 240 7 240 8 240 9 240
countEachLabel (adsTest)
ans =10×2表标签计数_____ _____ 0 60 1 60 2 60 3 60 4 60 5 60 6 60 7 60 8 60 9 60

辅助函数helperReadSPData将数据截断或填充为8192的长度,并按其最大值对每个记录进行规范化。的源代码helperReadSPData在附录中列出。创建一个8192 × 1600的矩阵,其中每一列都是一个语音数字记录。

Xtrain = [];scatds_Train = transform(adsTrain,@(x)helperReadSPData(x));hasdata(scatds_Train) smat = read(scatds_Train);Xtrain = cat(2,Xtrain,smat);结束

对测试集重复此过程。得到的矩阵是8192 × 400。

Xtest = [];scatds_Test = transform(adsTest,@(x)helperReadSPData(x));hasdata(scatds_Test) smat = read(scatds_Test);Xtest = cat(2,Xtest,smat);结束

将小波散射变换应用于训练集和测试集。

Strain = sf.featureMatrix(Xtrain);Stest = sf.featureMatrix(Xtest);

获得训练集和测试集的平均散射特征。排除零阶散射系数。

TrainFeatures = Strain(2:end,:,:);TrainFeatures = squeeze(mean(TrainFeatures,2))';TestFeatures = Stest(2:end,:,:);TestFeatures = squeeze(mean(TestFeatures,2))';

支持向量机分类器

现在,数据已经被简化为每个记录的特征向量,下一步是使用这些特征对记录进行分类。创建一个二次多项式核的SVM学习器模板。将SVM与训练数据进行拟合。

template = templateSVM(...“KernelFunction”多项式的...“PolynomialOrder”2,...“KernelScale”“汽车”...“BoxConstraint”, 1...“标准化”,真正的);分类svm = fitcecoc(...TrainFeatures,...adsTrain。标签,...“学习者”模板,...“编码”“onevsone”...“类名”分类({' 0 '' 1 '' 2 '“3”“4”“5”“6”“7”“8”“9”}));

利用k-fold交叉验证,根据训练数据预测模型的泛化精度。将训练集分成五组。

partitionedModel = crossval(classificationSVM,“KFold”5);[validationforecasts, validationScores] = kfoldPredict(partitionedModel);validationAccuracy = (1 - kfoldLoss(partitionedModel,“LossFun”“ClassifError”)) * 100
validationAccuracy = 97.4167

估计泛化精度约为97%。使用训练好的支持向量机预测测试集中的语音数字类。

predLabels = predict(classificationSVM,TestFeatures);testAccuracy = sum(predLabels==adsTest.Labels)/numel(predLabels)*100
testAccuracy = 97.1667

用混淆图总结模型在测试集上的表现。通过使用列和行摘要显示每个类的精度和召回率。混淆图底部的表格显示了每个类的精度值。混淆图右侧的表格显示召回值。

图(“单位”“归一化”“位置”,[0.2 0.2 0.5 0.5]);ccscat = confusionchart(adsTest.Labels,predLabels);ccscat。Title =“小波散射分类”;ccscat。ColumnSummary =“column-normalized”;ccscat。RowSummary =“row-normalized”

散射变换结合SVM分类器对测试集中的语音数字进行分类,准确率为98%(错误率为2%)。

长短期记忆(LSTM)网络

LSTM网络是一种循环神经网络(RNN)。rnn是专门处理顺序或时间数据(如语音数据)的神经网络。由于小波散射系数是序列,它们可以作为LSTM的输入。通过使用散射特征而不是原始数据,可以减少网络需要学习的可变性。

修改训练和测试散射特征以用于LSTM网络。排除零阶散射系数,将特征转换为单元阵列。

TrainFeatures = Strain(2:end,:,:);TrainFeatures = squeeze(num2cell(TrainFeatures,[1 2]));TestFeatures = Stest(2:end,:,:);TestFeatures = squeeze(num2cell(TestFeatures, [1 2]));

构造一个具有512个隐藏层的简单LSTM网络。

[inputSize, ~] = size(TrainFeatures{1});YTrain = adsTrain.Labels;numHiddenUnits = 512;numClasses = numel(唯一的(YTrain));层= [...sequenceInputLayer inputSize lstmLayer (numHiddenUnits,“OutputMode”“最后一次”) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer];

设置超参数。使用Adam优化和50个小批量大小。将最大epoch数设置为300。使用1e-4的学习速率。如果不想使用图跟踪进度,可以关闭训练进度图。如果有GPU,培训默认使用GPU。否则,它使用CPU。有关更多信息,请参见trainingOptions(深度学习工具箱)

maxEpochs = 300;miniBatchSize = 50;选项= trainingOptions(“亚当”...“InitialLearnRate”, 0.0001,...“MaxEpochs”maxEpochs,...“MiniBatchSize”miniBatchSize,...“SequenceLength”“最短”...“洗牌”“every-epoch”...“详细”假的,...“阴谋”“训练进步”);

培训网络。

net = trainNetwork(TrainFeatures,YTrain,layers,options);
predLabels =分类(net,TestFeatures);testAccuracy = sum(predLabels==adsTest.Labels)/numel(predLabels)*100
testAccuracy = 96.3333

贝叶斯优化

确定合适的超参数设置通常是训练深度网络最困难的部分之一。为了缓解这个问题,可以使用贝叶斯优化。在本例中,您将使用贝叶斯技术优化隐藏层的数量和初始学习率。创建一个新目录来存储mat文件,其中包含关于超参数设置和网络的信息以及相应的错误率。

YTrain = adsTrain.Labels;YTest = adsTest.Labels;如果~ (”结果/”“dir”mkdir)结果结束

初始化要优化的变量及其取值范围。因为隐藏层数必须为整数,所以设置“类型”“整数”

optVars = [optimizableVariable(“InitialLearnRate”(1 e-5, 1 e 1),“转换”“日志”) optimizableVariable (“NumHiddenUnits”(1000),“类型”“整数”));

贝叶斯优化是计算密集型的,可能需要几个小时才能完成。为了本例的目的,设置optimizeCondition下载和使用预先优化的超参数设置。如果你设置optimizeCondition真正的,目标函数helperBayesOptLSTM使用贝叶斯优化最小化。附录中列出的目标函数是给定特定超参数设置的网络错误率。加载设置的目标函数最小值为0.02(错误率为2%)。

ObjFcn = helperBayesOptLSTM(TrainFeatures,YTrain,TestFeatures,YTest);optimizeCondition = false;如果optimizeCondition BayesObject = bayesopt(ObjFcn,optVars,...“MaxObjectiveEvaluations”15岁的...“IsObjectiveDeterministic”假的,...“UseParallel”,真正的);其他的url =“http://ssd.mathworks.com/万博1manbetxsupportfiles/audio/SpokenDigitRecognition.zip”;downloadNetFolder = tempdir;netFolder = fullfile(下载netFolder,“SpokenDigitRecognition”);如果~存在(netFolder“dir”) disp (下载预训练的网络(1个文件- 12 MB)…解压缩(url, downloadNetFolder)结束负载(fullfile (netFolder“0.02.mat”));结束
下载预训练网络(1个文件- 12 MB)…

如果进行贝叶斯优化,将生成如下图所示的图形,跟踪目标函数值与对应的超参数值和迭代次数。您可以增加贝叶斯优化迭代的次数,以确保达到目标函数的全局最小值。

使用隐藏单元数和初始学习率的优化值重新训练网络。

numHiddenUnits = 768;numClasses = numel(唯一的(YTrain));层= [...sequenceInputLayer inputSize lstmLayer (numHiddenUnits,“OutputMode”“最后一次”) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer];maxEpochs = 300;miniBatchSize = 50;选项= trainingOptions(“亚当”...“InitialLearnRate”2.198827960269379 e-04...“MaxEpochs”maxEpochs,...“MiniBatchSize”miniBatchSize,...“SequenceLength”“最短”...“洗牌”“every-epoch”...“详细”假的,...“阴谋”“训练进步”);net = trainNetwork(TrainFeatures,YTrain,layers,options);predLabels =分类(net,TestFeatures);testAccuracy = sum(predLabels==adsTest.Labels)/numel(predLabels)*100
testAccuracy = 97.5000

如图所示,使用贝叶斯优化产生的LSTM具有更高的精度。

使用mel频率谱图的深度卷积网络

作为语音数字识别任务的另一种方法,使用基于mel频率谱图的深度卷积神经网络(DCNN)对FSDD数据集进行分类。使用与散射变换中相同的信号截断/填充过程。类似地,通过将每个信号样本除以最大绝对值来归一化每个记录。为了一致性,使用与散射变换相同的训练集和测试集。

设置mel-frequency谱图参数。使用与散射变换中相同的窗口或帧持续时间,0.22秒。将窗口之间的跳转设置为10毫秒。使用40个频段。

segmentDuration = 8192*(1/8000);frameDuration = 0.22;hopDuration = 0.01;numBands = 40;

重置训练和测试数据存储。

重置(adsTrain);重置(adsTest);

辅助函数helperspeechSpectrograms,定义在本例的末尾,使用melSpectrogram对记录长度进行标准化,对振幅进行归一化,得到梅尔频谱图。使用梅尔频率谱图的对数作为DCNN的输入。为了避免取0的对数,在每个元素上加上一个小的。

Epsil = 1e-6;XTrain = helpspeech spectrograms (adsTrain,segmentDuration,frameDuration,hopDuration,numBands);
计算语音谱图…2400中处理500个文件2400中处理1000个文件2400中处理1500个文件2400中处理2000个文件…完成
XTrain = log10(XTrain + epsil);XTest = helpspeechspectrograms (adsTest,segmentDuration,frameDuration,hopDuration,numBands);
计算语音谱图…处理了600个文件中的500个…完成了
XTest = log10(XTest + epsil);YTrain = adsTrain.Labels;YTest = adsTest.Labels;

定义DCNN架构

构造一个小的DCNN作为图层数组。使用卷积和批处理归一化层,并使用最大池化层对特征映射进行下采样。为了降低网络记忆训练数据特定特征的可能性,在最后一个全连接层的输入中加入少量的dropout。

sz = size(XTrain);specSize = sz(1:2);imageSize = [specSize 1];numClasses = nummel(类别(YTrain));dropoutProb = 0.2;numF = 12;图层= [imageInputLayer(imageSize) convolution2dLayer(5,numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer (3 2 * numF“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”maxPooling2dLayer(3,“步”2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”(3,4*numF,“填充”“相同”) batchNormalizationLayer reluLayer maxPooling2dLayer(2) dropoutLayer(dropoutProb) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer(“类”类别(YTrain));];

设置用于训练网络的超参数。使用50个小批大小和1e-4的学习率。指定Adam优化。因为本例中的数据量相对较小,所以将执行环境设置为“cpu”再现性。您还可以通过将执行环境设置为任意一个来在可用的GPU上训练网络“图形”“汽车”.有关更多信息,请参见trainingOptions(深度学习工具箱)

miniBatchSize = 50;选项= trainingOptions(“亚当”...“InitialLearnRate”1的军医,...“MaxEpochs”30岁的...“MiniBatchSize”miniBatchSize,...“洗牌”“every-epoch”...“阴谋”“训练进步”...“详细”假的,...“ExecutionEnvironment”“cpu”);

培训网络。

trainedNet = trainNetwork(XTrain,YTrain,图层,选项);

使用训练好的网络预测测试集的数字标签。

[ypredict,probs] =分类(trainedNet,XTest,“ExecutionEnvironment”“CPU”);cnnAccuracy = sum(yexpected ==YTest)/ nummel (YTest)*100
cnnAccuracy = 98.1667

用混淆图总结训练网络在测试集上的性能。通过使用列和行摘要显示每个类的精度和召回率。混淆图底部的表格显示了精度值。混淆图右侧的表格显示召回值。

图(“单位”“归一化”“位置”,[0.2 0.2 0.5 0.5]);ccDCNN =混淆图(YTest, yexpected);ccDCNN。Title =“DCNN的困惑表”;ccDCNN。ColumnSummary =“column-normalized”;ccDCNN。RowSummary =“row-normalized”

DCNN使用梅尔频谱图作为输入,对测试集中的语音数字进行分类,准确率约为98%。

总结

这个例子展示了如何使用不同的机器和深度学习方法对FSDD中的语音数字进行分类。实例说明了小波散射与支持向量机和LSTM的结合。采用贝叶斯方法对LSTM超参数进行优化。最后,示例展示了如何使用带有mel频率谱图的CNN。

该示例的目标是演示如何使用MathWorks®工具以基本不同但互补的方式处理问题。所有工作流都使用audioDatastore管理来自磁盘的数据流并确保适当的随机化。

本例中使用的所有方法在测试集上的表现都一样好。这个例子并不是要在各种方法之间进行直接比较。例如,还可以在CNN中使用贝叶斯优化进行超参数选择。在深度学习中,像这个版本的FSDD这样的小型训练集的另一个有用的策略是使用数据增强。操作如何影响类并不总是已知的,因此数据扩充并不总是可行的。然而,对于语音,已建立的数据增强策略可通过audioDataAugmenter

在小波时间散射的情况下,也有一些修改可以尝试。例如,您可以改变变换的不变尺度,改变每个滤波器组的小波滤波器数量,并尝试不同的分类器。

附录:Helper函数

函数标签= helpergenLabels(广告)此函数仅在小波工具箱示例中使用。可能是这样%将在将来的版本中更改或删除。tmp = cell(数字(ads.Files),1);表达=“[0 - 9]+ _”nf = 1: number (ads.Files) idx = regexp(ads.Files{nf},表达式);tmp{nf} = ads.Files{nf}(idx);结束标签=分类(tmp);结束
函数x = helperReadSPData(x)此函数仅用于使用小波工具箱的示例。它可能会改变%将在未来的版本中删除。N =数字(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 /max(abs(X));结束
函数x = helperBayesOptLSTM(X_train, Y_train, X_val, Y_val)此函数仅用于基于小波散射和深度学习的语音数字识别%的例子。它可能会在未来的版本中被更改或删除。x = @valErrorFun;函数[valError,cons, fileName] = valErrorFun(optVars)%% LSTM体系结构[inputSize,~] = size(X_train{1});numClasses = nummel(惟一的(Y_train));层= [...sequenceInputLayer inputSize bilstmLayer (optVars。NumHiddenUnits,“OutputMode”“最后一次”使用优化变量中的隐藏层数fullyConnectedLayer(numClasses) softmaxLayer classificationLayer];%训练时不显示图选项= trainingOptions(“亚当”...“InitialLearnRate”, optVars。InitialLearnRate,...%利用优化变量的初始学习率值“MaxEpochs”, 300,...“MiniBatchSize”30岁的...“SequenceLength”“最短”...“洗牌”“永远”...“详细”、假);%%网络训练net = trainNetwork(X_train, Y_train, layers, options);训练准确率X_val_P = net. classification (X_val);精度训练= sum(X_val_P == Y_val)./数值(Y_val);valError = 1 -准确性训练;将网络和选项的结果与错误值一起保存在results文件夹中的MAT文件中文件名= fullfile(“结果”, num2str(valError) +“.mat”);保存(文件名,“净”“valError”“选项”) cons = [];结束% end为内部函数结束% end用于外部函数
函数X = helpspeechspectrograms (ads,segmentDuration,frameDuration,hopDuration,numBands)此函数仅用于基于小波散射和深度学习的语音数字识别%的例子。它可能会在未来的版本中被更改或删除。% helperspeechSpectrograms(广告、segmentDuration frameDuration、hopDuration numBands)%为数据存储广告中的文件计算语音频谱图。% segmentDuration是演讲片段的总时长(以秒为单位),% frameDuration每个频谱图帧的持续时间,hopDuration表示%每个频谱图帧之间的时移,和numBands的个数%频带。disp (“计算语音谱图……”);numHops = ceil((segmentDuration - frameDuration)/hopDuration);numFiles = length(ads.Files);X = 0 ([numBands,numHops,1,numFiles],“单一”);i = 1:numFiles [x,info] = read(ads);x = normalizeAndResize(x);fs = info.SampleRate;frameLength = round(frameDuration*fs);hopLength = round(hopDuration*fs);spec = melSpectrogram(x,fs,...“窗口”汉明(frameLength“周期”),...“OverlapLength”,frameLength...“FFTLength”, 2048,...“NumBands”numBands,...“FrequencyRange”[4000]);如果频谱图的宽度小于numHops,则将频谱图放入% X的中间。W = size(spec,2);left = floor((numHops-w)/2)+1;Ind = left:left+w-1;X(:,ind,1,i) = spec;如果Mod (i,500) == 0“加工”+ I +文件输出+ numFiles)结束结束disp (“…”);结束%--------------------------------------------------------------------------函数x = normalizeandsize (x)此函数仅用于基于小波散射和深度学习的语音数字识别%的例子。它可能会在未来的版本中被更改或删除。N =数字(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 /max(abs(X));结束

版权所有2018,The MathWorks, Inc.

另请参阅

相关的例子

更多关于