主要内容

音频特征的顺序特征选择

本例给出了应用于语音数字识别任务的特征选择的典型工作流程。

在顺序特征选择中,你在给定的特征集上训练网络,然后增量地添加或删除特征,直到达到最高的精度[1].在本例中,使用“自由语音数字数据集”将顺序正向选择应用于语音数字识别任务[2]

流语音数字识别

为了推动这个示例,首先加载一个预先训练好的网络audioFeatureExtractor对象用于训练网络,并对特征进行归一化因子。

负载(“network_Audio_SequentialFeatureSelection.mat”“bestNet”“安全的”“标准化者”);

创建一个audioDeviceReader从麦克风读取音频。创建三个dsp。AsyncBuffer对象:一个用于缓冲从麦克风读取的音频,一个用于缓冲输入音频的短期能量用于语音检测,一个用于缓冲预测。

fs = afe.SampleRate;deviceReader = audioDeviceReader(SampleRate=fs,SamplesPerFrame=256);audioBuffer = dsp.AsyncBuffer(fs*3);steBuffer = dsp.AsyncBuffer(1000);predictionBuffer = dsp.AsyncBuffer(5);

创建一个图来显示流音频,推断期间网络输出的概率和预测。

图;streamAxes = subplot(3,1,1);streamPlot = plot(零(fs,1));ylabel (“振幅”)包含(“时间(s)”)标题(“音频流”) streamAxes。XTick = [0,fs];streamAxes。XTickLabel = [0,1];streamAxes。YLim = [-1,1];analyzedAxes = subplot(3,1,2);analyzedPlot = plot(零(fs/2,1));标题(“分析”) ylabel (“振幅”)包含(“时间(s)”) set(gca,XTickLabel=[]) analyzedAxes。XTick = [0,fs/2];analyzedAxes。XTickLabel = [0,0.5];analyzedAxes。YLim = [-1,1];probabilityAxes = subplot(3,1,3);probabilityPlot = bar(0:9,0.1*ones(1,10));轴([1,10,0,1])ylabel (“概率”)包含(“类”

执行流数字识别(数字0到9)20秒。当循环运行时,说出其中一个数字并测试其准确性。

首先,定义一个短期能量阈值,在这个阈值下,假设信号不包含语音。

steThreshold = 0.015;idxVec = 1:fs;抽搐Toc < 20从您的设备读取一帧音频。audioIn = deviceReader();将音频写入缓冲区。写(audioBuffer audioIn);%当200毫秒的数据未使用时,继续此循环。audioBuffer。NumUnreadSamples > 0.2*fs从音频缓冲区读取1秒。在这一秒中,有800毫秒%是重读旧数据,200 ms是新数据。audioToAnalyze = read(audioBuffer,fs,0.8*fs);更新图形以绘制当前音频数据。streamPlot。YData = audioToAnalyze;ste = mean(abs(audioToAnalyze));写(steBuffer, ste);如果steBuffer。NumUnreadSamples > 5 abc = sort(peek(steBuffer));steThreshold = abc(round(0.4* nummel (abc)));结束如果ste > steThreshold使用detectspeech函数来确定一个语音区域%存在。idx = detectSpeech(audioToAnalyze,fs);如果存在一个语音区域,执行以下操作。如果~ isempty (idx)除语音外,把信号的所有部分归零%区域,并修剪到0.5秒。audioToAnalyze = trimOrPad(audioToAnalyze(idx(1,1):idx(1,2))),fs/2);正常化音频。audioToAnalyze = audioToAnalyze/max(abs(audioToAnalyze));更新分析的线段图analyzedPlot。YData = audioToAnalyze;提取特征和转置它们,使时间。%跨列。features = (extract(afe,audioToAnalyze))';使特征正常化。features = (features - normalizers.Mean) ./ normalizers.标准差;调用分类来确定概率和%获奖标签。Features (isnan(Features)) = 0;[label,probs] = category (bestNet,features);用概率和获胜来更新情节%的标签。probabilityPlot。YData = probs;写(predictionBuffer,聚合氯化铝);如果predictionBuffer。NumUnreadSamples == predictionBuffer。容量lastTen = peek(predictionBuffer);[~,决定]= max(平均(lastTen。*损害(大小(lastTen, 1)), 1));probabilityax . title . string = num2str(decision-1);结束结束其他的如果信号能量低于阈值,则假设无语音%检测。probabilityAxes.Title.String ="";probabilityPlot。YData = 0.1*ones(10,1);analyzedPlot。YData = 0 (fs/2,1);重置(predictionBuffer)结束drawnowlimitrate结束结束

示例的其余部分说明了流检测中使用的网络是如何训练的,以及输入到网络中的特征是如何选择的。

创建训练和验证数据集

下载免费语音数字数据集(FSDD)[2].FSDD由语音数字(0-9)的短音频文件组成。

downloadFolder = matlab.internal.examples.download金宝appSupportFile(“音频”“FSDD.zip”);dataFolder = tempdir;unzip(下载文件夹,数据文件夹)dataset = fullfile(数据文件夹,数据文件夹)“FSDD”);

创建一个audioDatastore指向录音。得到数据集的抽样率。

ads = audioDatastore(dataset, inclesubfolders =true);[~,adsInfo] = read(ads);fs = adsInfo.SampleRate;

文件名的第一个元素是文件中的数字。获取文件名的第一个元素,将它们转换为类别,然后设置标签的属性audioDatastore

[~,filename] = cellfun(@(x)fileparts(x),ads.Files,UniformOutput=false);ads.Labels = categorical(string(cellfun(@(x)x(1),文件名));

若要将数据存储划分为开发集和验证集,请使用splitEachLabel.分配80%的数据用于开发,剩余的20%用于验证。

[adsTrain,adsValidation] = splitEachLabel(ads,0.8);

设置音频特征提取器

创建一个audioFeatureExtractor对象以10毫秒的更新速率提取超过30毫秒的Windows音频特性。将您想在本例中测试的所有特性设置为真正的

赢=汉明(轮(0.03*fs),“周期”);overlapLength = round(0.02*fs);afe = audioFeatureExtractor(...窗口=赢,...OverlapLength = OverlapLength,...SampleRate = fs,......linearSpectrum = false,...melSpectrum = false,...barkSpectrum = false,...erbSpectrum = false,......mfcc = true,...mfccDelta = true,...mfccDeltaDelta = true,...gtcc = true,...gtccDelta = true,...gtccDeltaDelta = true,......spectralCentroid = true,...spectralCrest = true,...spectralDecrease = true,...spectralEntropy = true,...spectralFlatness = true,...spectralFlux = true,...spectralKurtosis = true,...spectralRolloffPoint = true,...spectralSkewness = true,...spectralSlope = true,...spectralSpread = true,......= false,...harmonicRatio = false,...zerocrossrate = false,...shortTimeEnergy = false);

定义层次和培训选项

定义深度学习层列表(深度学习工具箱)trainingOptions(深度学习工具箱)本例中使用。第一层,sequenceInputLayer(深度学习工具箱),只是一个占位符。根据在连续特征选择过程中测试的特征,第一层将被替换为sequenceInputLayer合适的尺寸。

numUnits =One hundred.;层= [...sequenceInputLayer (1) bilstmLayer (numUnits OutputMode =“最后一次”) fullyConnectedLayer(nummel (categories(adsTrain.Labels)) softmaxLayer classificationLayer];选项= trainingOptions(“亚当”...LearnRateSchedule =“分段”...洗牌=“every-epoch”...Verbose = false,...MaxEpochs = 20);

顺序特征选择

在顺序特征选择的基本形式中,您在给定的特征集上训练网络,然后增量地添加或删除特征,直到精度不再提高[1]

提出了选择

考虑一个在四个特征集上进行前向选择的简单案例。在第一个正向选择循环中,通过训练网络并比较它们的验证精度,对四个特征中的每一个进行独立测试。指出了导致最高验证精度的特征。在第二个正向选择循环中,第一个循环中的最佳特征与每个剩余特征相结合。现在每对特征都用于训练。如果第二个循环中的精度没有比第一个循环中的精度提高,则选择过程结束。否则,将选择新的最佳特征集。向前选择循环继续,直到精度不再提高为止。

逆向选择

在反向特征选择中,首先在一个由所有特征组成的特征集上进行训练,并测试在删除特征时准确性是否会提高。

运行顺序特征选择

辅助函数(sequentialFeatureSelectiontrainAndValidateNetwork,trimOrPad)实现向前或向后顺序的特征选择。指定训练数据存储、验证数据存储、音频特征提取器、网络层、网络选项和方向。作为一般规则,如果你预期一个小的特征集,选择向前,如果你预期一个大的特征集,选择向后。

方向=“前进”;[日志,bestFeatures,bestNet,normalizers] = sequentialfeaturesselection (adsTrain,adsValidation,afe,layers,options,direction);

日志输出HelperFeatureExtractor是一个包含所有测试特性配置和相应验证精度的表。

日志
日志=62×2表特征精度_____________________________________________________________________ ________ "mfccDelta, spectralKurtosis, spectralRolloffPoint" 98.25 "mfccDelta, spectralRolloffPoint" 97.75 "mfccDelta, spectralreduce, spectralKurtosis, spectralRolloffPoint" 97.75 "mfccDelta, mfccDeltaDelta" 97 "mfccDelta, gtccDeltaDelta, spectralRolloffPoint" 97 "mfcc, mfccDelta, spectralKurtosis, spectralRolloffPoint" 97 "mfcc, mfccDelta, spectralKurtosis, spectralRolloffPoint" 97 "mfcc,mfccDelta“96.75”mfccDelta, gtccDeltaDelta, spectralKurtosis, spectralRolloffPoint“96.75”mfccDelta, spectralRolloffPoint, spectralSlope“96.5”mfccDelta“96.25”mfccDelta, spectralSpread“96.25”mfccDelta, spectraldescent, spectralRolloffPoint“96.25”mfccDelta, spectralFlatness, spectralKurtosis, spectralRolloffPoint“96.25”mfccDelta, gtccDeltaDelta“96”

bestFeatures输出sequentialFeatureSelection包含已设置为的最优特性的结构真正的

bestFeatures
bestFeatures =带字段的结构:mfcc: 0 mfccDelta: 1 mfccDeltaDelta: 0 gtcc: 0 gtccDelta: 0 gtccDeltaDelta: 0 spectralCentroid: 0 spectralCrest: 0 spectralreduce: 0 spectralEntropy: 0 spectralFlatness: 0 spectralFlux: 0 spectral峰度:1 spectralRolloffPoint: 1 spectralSkewness: 0 spectralSlope: 0 spectralSpread: 0

您可以设置您的audioFeatureExtractor使用结构体。

安全设置(afe bestFeatures)
afe = audioFeatureExtractor with properties: properties Window: [240×1 double] OverlapLength: 160 SampleRate: 8000 FFTLength: [] SpectralDescriptorInput: 'linearSpectrum' FeatureVectorLength:15启用特征mfccDelta, spectralKurtosis, spectralRolloffPoint禁用特征linearSpectrum, melSpectrum, barkSpectrum, erbSpectrum, mfcc, mfccDeltaDelta gtcc, gtccDelta, gtccDeltaDelta, spectralCentroid, spectralCrest, spectralreduce spectralEntropy, spectralFlatness, spectralFlux, spectralSkewness, spectralSlope, spectralSpread pitch, harmonicRatio, zerocrossrate, shortTimeEnergy提取一个特征,将相应的属性设置为true。例如,obj。MFCC = true,将MFCC添加到启用的特性列表中。

sequentialFeatureSelection同时输出与所选特征相对应的最佳性能网络和归一化因子。保存网络,配置完毕audioFeatureExtractor,和归一化因子,取消注释这一行:

%保存(“network_Audio_SequentialFeatureSelection.mat”、“bestNet”,“安全的”,“标准化者”)

结论

这个例子说明了循环神经网络(LSTM或BiLSTM)连续特征选择的工作流。它可以很容易地适应CNN和RNN-CNN的工作流程。

金宝app支持功能

训练和验证网络

函数[trueLabels,predictedLabels,net,normalizers] = trainAndValidateNetwork(adsTrain,adsValidation,afe,layers,options)训练并验证网络。%的输入:指向训练集的audioDatastore对象指向验证集的audioDatastore对象% afe - audioFeatureExtractor对象。% layers - LSTM或BiLSTM网络的层options - trainingOptions对象%输出:% trueLabels -验证集的真实标签% predictedLabels -验证集的预测标签net训练过的网络% normalizers -被测特性的归一化因子The MathWorks, Inc.版权所有将数据转换为高数组。tallTrain = tall(adsTrain);tallValidation = tall(adsValidation);从训练集中提取特征。重新定位特征% time沿行与sequenceInputLayer兼容。fs = afe.SampleRate;tallTrain = cellfun(@(x)trimOrPad(x,fs/2),tallTrain,UniformOutput=false);tallTrain = cellfun(@(x)x/max(abs(x),[],“所有”)、tallTrain UniformOutput = false);tallFeaturesTrain = cellfun(@(x)extract(afe,x),tallTrain,UniformOutput=false);tallFeaturesTrain = cellfun(@(x)x',tallFeaturesTrain,UniformOutput=false);% #好< NASGU >[~,featuresTrain] = evalc(“收集(tallFeaturesTrain)”);%使用evalc抑制命令行输出。tallValidation = cellfun(@(x)trimOrPad(x,fs/2),tallValidation,UniformOutput=false);tallValidation = cellfun(@(x)x/max(abs(x),[],“所有”)、tallValidation UniformOutput = false);tallFeaturesValidation = cellfun(@(x)extract(afe,x),tallValidation,UniformOutput=false);tallFeaturesValidation = cellfun(@(x)x',tallFeaturesValidation,UniformOutput=false);% #好< NASGU >[~,featuresValidation] = evalc(“收集(tallFeaturesValidation)”);%使用evalc抑制命令行输出。使用训练集来确定每一个的平均值和标准差%的特性。规范化训练集和验证集。allFeatures = cat(2,featuresTrain{:});M = mean(allFeatures,2,“omitnan”);S = std(allFeatures,0,2,“omitnan”);featuresTrain = cellfun(@(x)(x- m)./S,featuresTrain,UniformOutput=false);ii = 1:numel(featuresTrain) idx = find(isnan(featuresTrain{ii}));如果~isempty(idx) featuresTrain{ii}(idx) = 0;结束结束featuresValidation = cellfun(@(x)(x- m)./S,featuresValidation,UniformOutput=false);ii = 1:numel(featuresValidation) idx = find(isnan(featuresValidation{ii}));如果~isempty(idx) featuresValidation{ii}(idx) = 0;结束结束复制训练和验证集的标签,使它们在%与序列一一对应。labelsTrain = adsTrain.Labels;更新输入层测试功能的数量。layers(1) = sequenceInputLayer(size(featuresTrain{1},1));培训网络。net = trainNetwork(featuresTrain,labelsTrain,layers,options);评估网络。调用classification获取每个标签的预测标签%的序列。predictedLabels =分类(net,featuresValidation);trueLabels = adsValidation.Labels;将归一化因子保存为结构。标准化者。均值= M;标准化者。标准差= S;结束

顺序特征选择

函数[日志,bestFeatures,bestNet,bestNormalizers] = sequentialfeaturesselection (adsTrain,adsValidate,afeThis,layers,options,direction)%的输入:指向训练集的audioDatastore对象指向验证集的audioDatastore对象% afe - audioFeatureExtractor对象。将所有要测试的特性设置为true% layers - LSTM或BiLSTM网络的层options - trainingOptions对象% direction - SFS方向,指定为'forward'或'backward'%输出:日志簿-包含测试的特性配置和相应验证精度的表% bestFeatures -包含最佳特性配置的结构% bestNet -具有最高验证精度的训练网络% bestNormalizers -用于最佳特性的特征归一化因子The MathWorks, Inc.版权所有afe = copy(afeThis);featuresToTest = fieldnames(info(afe));N = numel(featuresToTest);bestValidationAccuracy = 0;设置初始特性配置:全部开启,用于向后选择%或全部关闭向前选择。featureConfig = info(afe);i = 1:N如果strcmpi(方向,“落后”) featureConfig.(featuresToTest{i}) = true;其他的featureConfig.(featuresToTest{i}) = false;结束结束初始化日志以跟踪功能配置和准确性。。logbook = table(featureConfig,0,VariableNames=[“功能配置”“准确性”]);执行顺序特性评估。wrapperIdx = 1;bestAccuracy = 0;wrapperIdx <= N创建包含要测试的所有特性配置的单元格数组%在当前循环中。featureConfigsToTest = cell(numel(featuresToTest),1);ii = 1:数字(featuresToTest)如果strcmpi(方向,“落后”) featureConfig.(featuresToTest{ii}) = false;其他的featureConfig.(featuresToTest{ii}) = true;结束featureConfigsToTest{ii} = featureConfig;如果strcmpi(方向,“落后”) featureConfig.(featuresToTest{ii}) = true;其他的featureConfig.(featuresToTest{ii}) = false;结束结束遍历每个特性集。ii = 1:数字(featureConfigsToTest)确定要测试的当前特性配置。。更新%功能安全。currentConfig = featureConfigsToTest{ii};currentConfig集(afe)%训练并获得电流的k倍交叉验证精度%特性配置。[trueLabels,predictedLabels,net,normalizers] = trainAndValidateNetwork(adsTrain,adsValidate,afe,layers,options);valAccuracy = mean(trueLabels==predictedLabels)*100;如果valAccuracy > bestValidationAccuracy = valAccuracy;bestNet =网络;bestNormalizers = normalizers;结束%更新日志result = table(currentConfig,valAccuracy,VariableNames=[“功能配置”“准确性”]);日志日志=[日志日志;结果];% #好< AGROW >结束以最佳精度确定和打印设置。如果精度%没有改善,结束运行。[a,b] = max(日志{:,“准确性”});如果a <= bestAccuracy wrapperIdx = inf;其他的wrapperIdx = wrapperIdx + 1;结束bestAccuracy = a;根据最近的获胜者更新要测试的功能。。赢家=日志{b,“功能配置”};Fn = fieldnames(winner);Tf = structfun(@(x)(x),赢家);如果strcmpi(方向,“落后”) featuresToRemove = fn(~tf);其他的featuresToRemove = fn(tf);结束ii = 1: nummel (featurestomove) loc = strcmp(featuresToTest, featurerestoremove {ii});featuresToTest(loc) = [];如果strcmpi(方向,“落后”) featureConfig.(featurerestoremove {ii}) = false;其他的featureConfig.(featureoremove {ii}) = true;结束结束结束对日志进行排序,使其更具可读性。。日志(1,:)= [];删除占位符第一行。航海日志= sortrows(航海日志,“准确性”“下”);bestFeatures =日志{1,“功能配置”};M =日志{:,“功能配置”};Fn = fieldnames(m);myString =字符串(数字(m),1);wrapperIdx = 1:numel(m) tf = structfun(@(x)(x),logbook{wrapperIdx,“功能配置”});myString(wrapperIdx) = strjoin(fn(tf),”、“);结束logbook = table(myString,logbook{:,“准确性”}, VariableNames = (“特征”“准确性”]);结束

镶边或衬垫

函数y = trimOrPad(x,n)% y = trimOrPad(x,n)修整或填充输入x到n个样本。如果x是%修剪,前面和后面修剪得一样。如果x是填充的,它就是%前面和后面都用零填充。用于奇数长度的修剪或%填充物,多余的样品从后面修剪或填充物。The MathWorks, Inc.版权所有A = size(x,1);如果a < n frontPad = floor((n-a)/2);backPad = n - a - frontPad;y = [0 (frontPad,1);x; 0 (backPad,1)];elseifa > n frontTrim =地板((a-n)/2)+1;backTrim = a - n - frontTrim;y = x(frontTrim:end-backTrim);其他的Y = x;结束结束

参考文献

[1]贾因,A.和D.宗克尔。特征选择:评估、应用和小样本性能模式分析与机器智能汇刊。第19卷,1997年第2期,第153-158页。

[2] Jakobovski。“Jakobovski / Free-Spoken-Digit-Dataset。”GitHub, 2019年5月30日。https://github.com/Jakobovski/free-spoken-digit-dataset。