主要内容

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

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

数据

克隆或下载免费语音数字数据集(FSDD),可在https://github.com/Jakobovski/free-spoken-digit-dataset获得。FSDD是一个开放的数据集,这意味着它可以随着时间的推移而增长。本例使用的是2019年1月29日提交的版本,该版本由2000个从4个说话者处获得的数字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);总结(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 (numel(ads.Files),1);Nr = 1;Hasdata (ads) = read(ads);LenSig(nr) = nummel (digit);Nr = Nr +1;结束重置(ads)直方图(LenSig)网格包含(“信号长度(样本)”) ylabel (“频率”

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

小波时间散射

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

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

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

rng默认的;Ads =洗牌(Ads);[adsTrain,adsTest] = splitachlabel (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) = read(scatds_Train);Xtrain = cat(2,Xtrain, smart);结束

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

Xtest = [];scatds_Test = transform(adsTest,@(x)helperReadSPData(x));hasdata(scatds_Test) = 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“标准化”,真正的);classificationSVM = fitcecoc(TrainFeatures,adsTrain。标签,“学习者”模板,“编码”“onevsone”“类名”分类({' 0 ';' 1 ';' 2 ';“3”;“4”;“5”;“6”;“7”;“8”;“9”}));

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

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

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

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

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

图(“单位”“归一化”“位置”,[0.2 0.2 0.5 0.5]);ccscat = confusionchart(adest . 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 = nummel (unique(YTrain));图层= [sequenceInputLayer inputSize lstmLayer (numHiddenUnits,“OutputMode”“最后一次”) fulllyconnectedlayer (numClasses) softmaxLayer classificationLayer];

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

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

训练网络。

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

贝叶斯优化

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

YTrain = adsTrain.Labels;YTest = adest . 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);optimizeconcondition = false;如果优化条件BayesObject = bayesopt(ObjFcn,optVars,“MaxObjectiveEvaluations”15岁的“IsObjectiveDeterministic”假的,“UseParallel”,真正的);其他的url =“http://ssd.mathworks.com/金宝appsupportfiles/audio/SpokenDigitRecognition.zip”;downloadNetFolder = tempdir;netFolder = fullfile(下载netFolder,“SpokenDigitRecognition”);如果~存在(netFolder“dir”) disp (“正在下载预训练网络(1个文件- 12mb)…”解压缩(url, downloadNetFolder)结束负载(fullfile (netFolder“0.02.mat”));结束
下载预训练网络(1个文件- 12 MB)…

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

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

numHiddenUnits = 768;numClasses = nummel (unique(YTrain));图层= [sequenceInputLayer inputSize lstmLayer (numHiddenUnits,“OutputMode”“最后一次”) fulllyconnectedlayer (numClasses) softmaxLayer classificationLayer];maxEpochs = 300;miniBatchSize = 50;options = trainingOptions(“亚当”“InitialLearnRate”2.198827960269379 e-04“MaxEpochs”maxEpochs,“MiniBatchSize”miniBatchSize,“SequenceLength”“最短”“洗牌”“every-epoch”“详细”假的,“阴谋”“训练进步”);net = trainNetwork(TrainFeatures,YTrain,layers,options);predLabels = classification (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对记录长度进行标准化,对振幅进行归一化,得到梅尔频谱图。使用mel频率谱图的对数作为DCNN的输入。为了避免取0的对数,在每个元素上加上一个小的。

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

定义DCNN架构

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

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

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

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

训练网络。

trainedNet = trainNetwork(XTrain,YTrain,layers,options);

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

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

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

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

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

总结

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

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

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

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

附录:辅助函数

函数标签= helpergenLabels(ads)此函数仅用于小波工具箱示例。可能是%在将来的版本中已更改或已删除。tmp = cell(numel(ads.Files),1);表达=“[0 - 9]+ _”;nf = 1: null (ads.Files); idx = regexp(ads.Files{nf},expression);tmp{nf} = ads.Files{nf}(idx);结束标签=分类(tmp);结束
函数x = helperReadSPData(x)此函数仅供使用小波工具箱的示例。它可能会改变%将在以后的版本中删除。N = nummel (x);如果N > 8192 x = x(1:8192);elseifN < 8192 pad = 8192-N;Prepad = floor(pad/2);Postpad = ceil(pad/2);X = [0 (pread,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 (unique(Y_train));图层= [sequenceInputLayer inputSize bilstmLayer (optVars。NumHiddenUnits,“OutputMode”“最后一次”%使用隐藏层数从优化变量的值fulllyconnectedlayer (numClasses) softmaxLayer分类层];%训练时不显示的图options = trainingOptions(“亚当”“InitialLearnRate”, optVars。InitialLearnRate,使用优化变量的初始学习率值“MaxEpochs”, 300,“MiniBatchSize”30岁的“SequenceLength”“最短”“洗牌”“永远”“详细”、假);%%训练网络net = trainNetwork(X_train, Y_train, layers, options);%%训练准确度X_val_P = net. classified (X_val);accuracy_training = sum(X_val_P == Y_val)./numel(Y_val);valError = 1 - accuracy_training;%%将网络和选项的结果与错误值一起保存在结果文件夹中的MAT文件中fileName = fullfile(“结果”, num2str(valError) +“.mat”);保存(文件名,“净”“valError”“选项”) cons = [];结束%结束内部函数结束% end用于外部函数
函数X = helperspeechSpectrograms(ads,segmentDuration, framedduration,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);= normalizeAndResize(x);fs = info.SampleRate;frameLength = round(frameLength *fs);hopLength = round(hopDuration*fs);spec = melSpectrogram(x,fs,“窗口”汉明(frameLength“周期”),“OverlapLength”,frameLength - hopLength;“FFTLength”, 2048,“NumBands”numBands,“FrequencyRange”[4000]);如果谱图的宽度小于numHops,则将谱图放入% X的中间。W = size(spec,2);left = floor((numHops-w)/2)+1;Ind = left:左+w-1;X(:,ind,1,i) = spec;如果Mod (i,500) == 0 disp(“加工”+ I +"文件退出"+ numFiles)结束结束disp (“…”);结束%--------------------------------------------------------------------------函数x = normalizeAndResize(x)%此函数仅用于基于小波散射和深度学习的语音数字识别%的例子。它可能会在将来的版本中更改或删除。N = nummel (x);如果N > 8192 x = x(1:8192);elseifN < 8192 pad = 8192-N;Prepad = floor(pad/2);Postpad = ceil(pad/2);X = [0 (pread,1);x;0 (postpad 1)];结束X = X /max(abs(X));结束

版权所有:The MathWorks, Inc。

另请参阅

相关的例子

更多关于