主要内容

使用深度学习的言语命令识别

这个例子展示了如何训练一个深度学习模型来检测音频中语音命令的存在。该示例使用语音命令数据集[1]训练卷积神经网络来识别给定的命令集。

要从划痕培训网络,必须首先下载数据集。如果您不想下载数据集或培训网络,那么您可以加载包含此示例的预磨平网络,并执行示例的下两个部分:用预先训练的网络识别命令使用来自麦克风的流音频检测命令

用预先训练的网络识别命令

在进入详细的训练过程之前,您将使用预先训练过的语音识别网络来识别语音命令。

加载预先训练的网络。

负载('commandnet.mat'

培训网络以识别以下语音命令:

  • “是的”

  • “不”

  • 《飞屋环游记》

  • “下”

  • “剩下”

  • “对”

  • “在”

  • “关闭”

  • “停止”

  • “去”

装载一个人说“停止”的短语信号。

[x, fs] = audioread (“stop_command.flac”);

听取命令。

声音(x, fs)

预先训练的网络以基于听觉的谱图作为输入。首先将语音波形转换为基于听觉的声谱图。

使用的函数extractAuditoryFeature计算听觉频谱图。您将在示例之后浏览功能提取的细节。

auditorySpect = helperExtractAuditoryFeatures (x, fs);

根据其听觉频谱图对命令进行分类。

命令=分类(trainedNet auditorySpect)
命令=无条件停止

经过训练,该网络将不属于这个集合的单词分类为“未知”。

现在您将对命令列表中没有包含的单词(“play”)进行分类以识别。

加载语音信号并收听它。

x = audioread ('play_command.flac');声音(x, fs)

计算听觉谱图。

auditorySpect = helperExtractAuditoryFeatures (x, fs);

信号的分类。

命令=分类(trainedNet auditorySpect)
命令=分类未知

训练网络将背景噪声分类为“背景”。

创建一个由随机噪声组成的一秒信号。

X = PinkNoise(16E3);

计算听觉谱图。

auditorySpect = helperExtractAuditoryFeatures (x, fs);

分类背景噪音。

命令=分类(trainedNet auditorySpect)
命令=分类背景

使用来自麦克风的流音频检测命令

在麦克风的流音频上测试预先训练的命令检测网络。例如,试着说出其中一条命令,是的没有, 要么停止.然后,尝试说这样一个未知的单词,如玛文希拉房子,或者从0到9的任何数字。

指定Hz中的分类速率,并创建一个可以从麦克风读取音频的音频设备读取器。

classificationRate = 20;adr = audioDeviceReader ('采样率'fs,“SamplesPerFrame”、地板(fs / classificationRate));

初始化音频的缓冲区。提取网络的分类标签。为流音频的标签和分类概率初始化半秒的缓冲区。使用这些缓冲区在更长的时间内比较分类结果,并且在检测到命令时构建“协议”。指定决策逻辑的阈值。

audiobuffer = dsp.asyncuffer(FS);标签= TRAINARNET.LAYERS(END).CLASS;YBUFFER(1:ClassificationRate / 2)=分类(“背景”);probBuffer = 0([元素个数(标签),classificationRate / 2));countThreshold =装天花板(classificationRate * 0.2);probThreshold = 0.7;

只要创建的图形存在,就创建一个图形并检测命令。要无限期地运行循环,请设置期限INF..要停止活检测,只需关闭图形。

h =图('单位''标准化'“位置”,[0.2 0.1 0.6 0.8]);期限= 20;抽搐句柄(h) && toc < timeLimit%从音频设备提取音频样本并将样品添加到%缓冲区。x = ADR();写(audiobuffer,x);y =读取(Audiobuffer,FS,FS-ADR.SampleSperFrame);spec = perverextractautionsfeatures(y,fs);%分类当前频谱图,将标签保存到标签缓冲区,%并将预测的概率保存到概率缓冲区。[ypreedicted,probs] =分类(trountainnet,spec,'executionenvironment''中央处理器');YBUFFER = [YBUFFER(2:END),Y预期];probbuffer = [probbuffer(:,2:结束),probs(:)];%绘制电流波形和谱图。子图(2,1,1)绘图(Y)轴紧的Ylim([ -  1,1])子图(2,1,2)PColor(SPEC')Caxis([ -  4 2.6445])阴影平坦的%现在通过执行一个非常简单的实际命令检测来进行实际命令检测%阈值操作。声明一个检测并显示它%数字标题如果所有以下保留:1)最常见的标签%不是背景。2)最新框架的至少计数%标签同意。3)预测标签的最大概率是在%最少探针。否则,请勿声明检测。[YMode,计数]=模式(YBuffer);maxProb = max(probBuffer(labels == YMode,:)); / /输出次要情节(2,1,1)如果YMode = =“背景”||count “)其他的标题(string (YMode),'字体大小', 20)结束drawnow结束

加载语音命令数据集

此示例使用Google语音命令数据集[1]。下载DataSet和Untar下载文件。将pathtodatabase设置为数据的位置。

URL =.“https://ssd.mathworks.com/万博1manbetxsupportfiles/audio/google_speech.zip”;downloadfolder = tempdir;datafolder = fullfile(downloadlefolder,'google_speech');如果~存在(dataFolder'dir') disp (“下载数据集(1.4 GB)……”)解压缩(URL,DownloadFolder)结束

创建培训数据存储

创建一个audiodatastore.指向训练数据集。

广告= audiodataStore(fullfile(datafolder,“火车”),......“IncludeSubfolders”,真的,......'fileextensions'“wav”......“LabelSource”'foldernames'
广告= audioDataStore具有属性:文件:{'... \ appdata \ local \ temp \ google_speech \ train \ bed \ 00176480_nohash_0.wav';'... \ appdata \ local \ temp \ google_speech \ train \ bed \ 004ae714_nohash_0.wav';'... \ appdata \ local \ temp \ google_speech \ train \ bed \ 004ae714_nohash_1.wav'...和51085更多}文件夹:{'c:\ users \ jibrahim \ appdata \ local \ temp \ google_speech \ train \ train \ train \ train \ train \ train'}标签:[床;床上;床......和51085更多分类] leartefilesystemroots:{} outputdatatype:'double'supportedOutputFormats:万博1manbetx[“WAV”“FLAC”“OGG”“MP4”“M4A”] DefaultOutputFormat:“WAV”

选择要识别的单词

指定要为模型识别为命令的单词。标记未命令的所有单词未知.将不是命令的单词标记为未知创建一组单词,该单词近似于命令以外的所有单词的分布。该网络使用此组来了解命令和所有其他单词之间的差异。

为了减少已知和未知的单词和加速处理之间的类不平衡,仅包括训练集中的一小部分未知单词。

使用子集创建仅包含命令和未知单词的子集的数据存储。计算属于每个类别的示例的数量。

命令=分类([“是的”“不”《飞屋环游记》“下”“剩下”“对”“在”“关闭”“停止”“去”]);isCommand = ismember (ads.Labels、命令);isUnknown = ~ isCommand;includeFraction = 0.2;mask = rand(numel(ads.Labels),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);adsTrain =子集(广告,isCommand | isUnknown);countEachLabel (adsTrain)
ans = 11×2 table Label Count _______ _____ down 1842 go 1861 left 1839 no 1853 off 1839 on 1864 right 1852 stop 1885 unknown 6483 up 1843 yes 1860

创建验证数据存储

创建一个audiodatastore.指向验证数据集。遵循与创建训练数据存储相同的步骤。

广告= audiodataStore(fullfile(datafolder,“验证”),......“IncludeSubfolders”,真的,......'fileextensions'“wav”......“LabelSource”'foldernames')IsCommand = ISMember(Ads.Labels,命令);isUnknown = ~ isCommand;includeFraction = 0.2;mask = rand(numel(ads.Labels),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);ADSValidation =子集(广告,ISCommand | isunknown);CountAckeLabel(ADSValidation)
ads = audioDatastore的属性:Files:{'…\AppData\Local\Temp\google_speech\validation\bed\026290a7_nohash_0.wav';’……\ AppData \当地\ Temp \ google_speech \床验证\ \ 060 cd039_nohash_0.wav;’……\ AppData \当地\ Temp \ google_speech \床验证\ \ 060 cd039_nohash_1.wav……{'C:\Users\jibrahim\AppData\Local\Temp\google_speech\validation'}标签:[bed;床上;床上……和6795年更直言]AlternateFileSystemRoots: {} OutputDataType:“双”SupportedOutputFormats:[万博1manbetx“wav”“flac”“ogg”“mp4”“m4a格式”]DefaultOutputFormat:“wav”ans = 11×2表标签数  _______ _____ 264 260 247 270 256 257 256停止246未知850 260对261

要用整个数据集训练网络,并达到尽可能高的精度,集合reduceDataset.快速运行此示例,设置reduceDataset真正的

depentataset = false;如果Depentataset numuniqueLabels = numel(唯一(adstrain.labels));%将数据集缩减到原来的20倍adstrain = splitheachlabel(adstrain,round(numel(adstrain.files)/ numuniqueLabels / 20));ADSValidation = SpliteachLabel(ADSValidation,ROUND(NUMER(ADSValidation.Files)/ NumUnIqueLabels / 20));结束

计算听觉谱图

为准备卷积神经网络的有效培训数据,将语音波形转换为基于听觉的频谱图。

定义特征提取的参数。分段为每个演讲片段的持续时间(单位为秒)。frameDuration为进行频谱计算的每帧的持续时间。哈姆瑟是每个频谱之间的时间步长。numBands是听觉频谱图中的过滤器数量。

创建一个audioFeatureExtractor对象执行特征提取。

fs = 16e3;数据集的%已知采样率。segmentDuration = 1;frameDuration = 0.025;hopDuration = 0.010;segmentSamples =圆(segmentDuration * fs);frameSamples =圆(frameDuration * fs);hopSamples =圆(hopDuration * fs);overlapSamples = framessamples - hopSamples;FFTLength = 512;numBands = 50;afe = audioFeatureExtractor (......'采样率'fs,......“FFTLength”FFTLength,......'窗户'损害(frameSamples'定期'),......'overlaplencth',重叠,......“barkSpectrum”,真正的);setExtractorParams (afe“barkSpectrum”“NumBands”,numband,'风向正常化'、假);

从数据集中读取文件。训练卷积神经网络需要输入尺寸是一致的大小。数据集中的某些文件少于1秒。将零填充应用于音频信号的正面和背面,使其长度为长度segmentSamples

x =读(adstrain);numsamples = size(x,1);numtopadfront =楼层((SegmentsAmples  -  Numsamples)/ 2);numtopadback = ceil((segmentsamples  -  numsamples)/ 2);xpadded = [zeros(numtopadfront,1,'像',x); x; zeros(numtopadback,1,'像',X)];

要提取音频功能,请致电提炼.输出是跨行带有时间的Bark谱。

特征=提取物(AFE,XPadded);[numhops,numfeatures] =大小(特征)
numHops = 98 numFeatures = 50

在此示例中,您通过应用对数来处理听觉频谱图。拍摄少数的日志可能会导致循环错误。

要加快处理速度,可以使用议案

首先,确定数据集的分区数。如果您没有并行计算工具箱™,请使用单个分区。

如果~ isempty(版本(“平行”))&&〜oderataset pool = gcp;numpar = numpartitions(adstrain,pool);其他的numpar = 1;结束

对于每个分区,从数据存储读取,零打击信号,然后提取该功能。

议案II = 1:numpar subds = partition(adstrain,numpar,ii);xtrain =零(numhops,numband,1,numel(subds.files));为了idx = 1:numel(subds. files) x = read(subds);xPadded =[0(地板(segmentSamples-size (x, 1)) / 2), 1); x; 0(装天花板((segmentSamples-size (x, 1)) / 2), 1)];XTrain (:,:,:, idx) =提取(afe xPadded);结束XTrainc {II} = XTrain;结束

使用沿着第四维度的听觉频谱图转换为4维数组。

XTrain = Cat(4,Xtrainc {:});[numhops,numband,numchannels,numspec] =大小(xtrain)
numhops = 98 numbands = 50 numchannels = 1 numspec = 25021

根据窗户功率缩放特征,然后取日志。为了获得分布更平滑的数据,使用小偏移量对谱图取对数。

epsil = 1 e-6;XTrain = log10(XTrain + epsil);

对验证集执行上面描述的特征提取步骤。

如果~ isempty(版本(“平行”) pool = gcp;numPar = numpartitions (adsValidation、池);其他的numpar = 1;结束议案ii = 1:numPar subds = partition(adsValidation,numPar,ii);XValidation = 0 (numHops numBands 1,元素个数(subds.Files));为了idx = 1:numel(subds. files) x = read(subds);xPadded =[0(地板(segmentSamples-size (x, 1)) / 2), 1); x; 0(装天花板((segmentSamples-size (x, 1)) / 2), 1)];xValidation(:,::,idx)=提取物(afe,xpadded);结束XValidationC {2} = XValidation;结束xvalidation = cat(4,xvalidationc {:});xvalidation = log10(xvalidation + epsil);

隔离列车和验证标签。删除空型。

ytrain = removecats(adstrain.labels);yvalidation = removecats(adsvalidation.labels);

可视化数据

绘制一些训练样本的波形和听觉谱图。播放相应的音频片段。

specmin = min(xtrain,[],“所有”);specMax = max (XTrain [],“所有”);idx = randperm(元素个数(adsTrain.Files), 3);图('单位''标准化'“位置”,[0.2 0.2 0.6 0.6]);为了i = 1:3 [x,fs] = audioread(adsTrain.Files{idx(i)});次要情节(2、3、i)情节(x)轴紧的标题(string (adsTrain.Labels (idx (i))))次要情节(2 3 i + 3) spect = (XTrain (:,: 1, idx(我)');cxis ([specMin specMax])阴影平坦的sound(x,fs)暂停(2)结束

添加背景噪声数据

网络必须不仅能够识别不同的口语单词,还可以检测输入是否包含沉默或背景噪声。

使用音频文件_背景_文件夹创建背景噪声的一秒钟剪辑的样本。从每个背景噪声文件创建相同数量的背景剪辑。您还可以创建自己的背景噪音录制并将其添加到_背景_文件夹。在计算谱图之前,该函数使用从给定范围内的对数均匀分布中采样的因子对每个音频剪辑进行缩放volumeRange

adsbkg = audiodataStore(fullfile(datafolder,'背景') numBkgClips = 4000;如果reduceDataset numBkgClips = numBkgClips/20;结束volumeRange = log10([1的军医,1]);numBkgFiles =元素个数(adsBkg.Files);numClipsPerFile = histcounts (1: numBkgClips, linspace (1 numBkgClips numBkgFiles + 1);Xbkg = 0(大小(XTrain, 1),大小(XTrain, 2), 1, numBkgClips,'单身的');bkgall = readall(adsbkg);IND = 1;为了计数= 1:numBkgFiles bkg = bkgAll{count};idxStart =兰迪(元素个数(bkg) - f, numClipsPerFile(计数),1);idxEnd = idxStart + fs-1;^((volumeRange(2)-volumeRange(1)))*rand(numClipsPerFile(count),1) + volumeRange(1));为了j = 1:numclipsperfile(count)x = bkg(idxstart(j):idxend(j))* gain(j);x = max(min(x,1), -  1);xbkg(::,:,ind)=提取物(afe,x);如果mod(ind,1000)== 0 disp(“处理 ”+字符串(IND)+“背景剪辑”+字符串(numbkgclips))结束IND = IND + 1;结束结束xbkg = log10(xbkg + epsil);
adsBkg = audioDatastore与属性:文件:{'…\AppData\Local\Temp\google_speech\background\doing_the_dish .wav';“…\ AppData \当地背景\ Temp \ google_speech \ \ dude_miaowing.wav;“…\ AppData \当地背景\ Temp \ google_speech \ \ exercise_bike.wav……{'C:\Users\jibrahim\AppData\Local\Temp\google_speech\background'} AlternateFileSystemRoots: {} OutputDataType: 'double'标签:{}SupportedOutputFormats: ["wav" 万博1manbetx"flac" "ogg" "mp4" "m4a"] DefaultOutputFormat:“wav”从4000个背景剪辑中处理了1000个,从4000个背景剪辑中处理了2000个,从4000个背景剪辑中处理了3000个,从4000个背景剪辑中处理了4000个

在训练,验证和测试集之间分离背景噪声的谱图。因为这_background_noise_文件夹只包含约5分半钟的背景噪声,不同数据集中的背景样本具有高度相关性。为了增加背景噪音的变化,您可以创建自己的背景文件,并将它们添加到文件夹中。为了提高网络对噪声的鲁棒性,您还可以尝试在语音文件中混合背景噪声。

numtrainbkg =楼层(0.85 * numbkgclips);numvalidationbkg =楼层(0.15 * numbkgclips);XTrain(:,::,结束+ 1:end + numtrainbkg)= xbkg(:,:,:,1:numtrainbkg);YTRAIN(结束+ 1:end + NUMTRAINBKG)=“背景”;xValidation(::::,结束+ 1:end + NumValidationBkg)= XBKG(:,::,numtrainbkg + 1:结束);YValidation(终点+ 1:end + NumValidationBKG)=“背景”

绘制培训和验证集中不同类标签的分布。

图('单位''标准化'“位置”,[0.2 0.2 0.5 0.5])子图(2,1,1)直方图(YTrain)标题(“培训标签分配”)子图(2,1,2)直方图(YValidation)标题(“验证标签分发”

定义神经网络架构

创建一个简单的网络架构作为一系列图层。使用卷积和批量归一化层,并将特征映射“空间上”(即,在时间和频率上)使用MAX池层。添加最终最大池层,可以随时间全局汇集输入功能映射。这在输入频谱图中强制(近似)时间转换不变性,允许网络在时间上独立于语音的确切位置执行相同的分类。全球池也显着降低了最终完全连接层中的参数数量。为了减少网络记忆训练数据的特定功能的可能性,将少量丢失添加到最后一个完全连接的图层。

网络很小,因为它只有五个卷积层,滤波器很少。numF控制卷积层中的过滤器数量。为了提高网络的准确性,尝试通过添加相同的卷积块,批量归一化和relu层来增加网络深度。您还可以尝试通过增加提高卷积滤波器的数量numF

使用加权交叉熵分类损失。weightedClassificationLayer (classWeights)创建一个自定义分类层,计算交叉熵损失与观测加权类别级别.按照类出现的顺序指定类权重类别(YTrain).为了使每个类同等于丢失的总重量,使用与每个类中的训练示例的数量成反比的类重量。使用ADAM优化器培训网络时,培训算法与类重量的总体正常化无关。

classWeights = 1. / countcats (YTrain);classWeights = classWeights ' /意味着(classWeights);numClasses =元素个数(类别(YTrain));timePoolSize =装天花板(numHops / 8);dropoutProb = 0.2;numF = 12;[imageInputLayer([numHops numBands]))卷积2dlayer (3,numF,'填充'“相同”)BatchnormalizationLayer Ruilulayer MaxPooling2dlayer(3,'走吧'2,'填充'“相同”)卷积2dlayer(3,2 * numf,'填充'“相同”)BatchnormalizationLayer Ruilulayer MaxPooling2dlayer(3,'走吧'2,'填充'“相同”) convolution2dLayer(3、4 * numF,'填充'“相同”)BatchnormalizationLayer Ruilulayer MaxPooling2dlayer(3,'走吧'2,'填充'“相同”) convolution2dLayer(3、4 * numF,'填充'“相同”) batchNormalizationLayer reluLayer卷积2dlayer (3,4*numF,'填充'“相同”) batchNormalizationLayer reluLayer maxPooling2dLayer([timePoolSize,1]) dropoutLayer(dropoutProb) fulllyconnectedlayer (numClasses) softmaxLayer weightedClassificationLayer(classWeights)];

火车网络

指定培训选项。使用带有迷你批量大小为128的ADAM优化器。25时代的火车,并在20个时期之后将学习率降低10倍。

miniBatchSize = 128;validationFrequency =地板(元素个数(YTrain) / miniBatchSize);选择= trainingOptions ('亚当'......“InitialLearnRate”3的军医,......“MaxEpochs”,25,......'minibatchsize',小匹马,......'洗牌'“every-epoch”......'plots''培训 - 进步'......'verbose'假的,......“ValidationData”,{xvalidation,yvalidation},......“ValidationFrequency”,验证职权,......'shownrateschedule''分段'......“LearnRateDropFactor”,0.1,......“LearnRateDropPeriod”20);

训练网络。如果您没有GPU,则培训网络可能需要时间。

TrousaInnet = Trainnetwork(XTrain,Ytrain,图层,选项);

评估培训网络

计算培训集(没有数据增强)和验证集的最终准确性。网络在此数据集上非常准确。但是,培训,验证和测试数据都具有类似的分布,不一定反映现实世界环境。这种限制特别适用于未知类别,它只包含少量单词的话语。

如果SDENTATASET LOAD('commandnet.mat''trousahynet');结束YValPred =分类(trainedNet XValidation);validationError = mean(YValPred ~= YValidation);YTrainPred =分类(trainedNet XTrain);= mean(YTrainPred ~= YTrain);disp (“训练错误:”+ TrainError * 100 +“%”) disp (“验证错误:”+ validationError * 100 +“%”
培训误差:1.907%验证误差:5.5376%

绘制混乱矩阵。使用列和行摘要显示每个类的精度并回忆。对混淆矩阵的类进行排序。最大的混乱是在未知的单词和命令之间,向上没有,没有

图('单位''标准化'“位置”,[0.2 0.2 0.5 0.5]);CM = ConfusionChart(YValidation,YVALPRED);cm.title ='验证数据的混淆矩阵';厘米。ColumnSummary ='列 - 归一化';厘米。RowSummary ='行标准化';SortClasses(cm,[命令,“未知”“背景”])

在使用受约束硬件资源(如移动应用程序)的应用程序时,请考虑可用内存和计算资源的限制。使用CPU时计算网络的总大小,并在使用CPU时测试其预测速度。预测时间是对单个输入图像进行分类的时间。如果输入到网络的多个图像,则可以同时对这些图像进行分类,从而导致每个图像的更短预测次数。然而,当分类流音频时,单图像预测时间是最相关的。

信息= whos('trousahynet');disp (“网络尺寸:”+ INFO.BYTES / 1024 +“知识库”为了i = 1:100 x = randn([numhops,numbands]);TIC [YERPREDITED,PROPS] =分类(TRAIRATIONNET,X,“刽子果环境”'中央处理器');时间(i)= toc;结束disp (“CPU上的单图像预测时间:”+的意思是(时间(11:结束))* 1000 +“女士”
网络大小:286.7402 kB CPU上的单张图像预测时间:2.5119 ms

参考文献

[1] Warden P.“语音命令:用于单词语音识别的公共数据集”,2017.可从中获取https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz..版权2017年谷歌。Speech Commands Dataset是在Creative Commons Attribution 4.0许可下使用的,可以在这里获得:https://creativeCommons.org/licenses/by/4.0/Legalcode.