基于深度学习的语音指令识别

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

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

通过预先训练的网络识别命令

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

加载预先训练的网络。

负载('commandnet.mat'

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

  • “是的”

  • “不”

  • “向下”

  • “左”

  • “正确”

  • “开”

  • “关”

  • “停止”

  • “走”

在有人说“停止”的地方加载一个简短的语音信号。

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

听取命令。

声音(x, fs)

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

使用功能解密卫生术来计算听觉谱图。在稍后的示例中,您将了解特征提取的细节。

听觉探测= PerverextractAutiveFeatures(X,FS);

根据命令的声谱图对其进行分类。

命令=分类(trainedNet auditorySpect)
命令=分类停止

培训网络以对不属于此设置的单词进行分类为“未知”。

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

加载语音信号并收听它。

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

计算听觉谱图。

听觉探测= PerverextractAutiveFeatures(X,FS);

分类信号。

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

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

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

X = 0.01 * randn(16e3,1);

计算听觉谱图。

听觉探测= PerverextractAutiveFeatures(X,FS);

对背景噪声进行分类。

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

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

在麦克风的流音频上测试预先训练的命令检测网络。例如,试着说出其中一条命令,是的或者停止.然后,试着说出其中一个不认识的单词,比如马文希拉床上房子,或者从0到9的任何数字。

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

classificationRate = 20;adr = audioDeviceReader ('samplerate'fs,“SamplesPerFrame”,地板(FS / Classificationrate));

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

audioBuffer = dsp.AsyncBuffer (fs);. class标签= trainedNet.Layers(结束);YBuffer (1: classificationRate / 2) =分类(“背景”);probbuffer = zeros([numel(标签),分类符号/ 2]);countthreshold = ceil(分类符号* 0.2);probthreshold = 0.7;

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

h =图(“单位”“归一化”“位置”,[0.2 0.1 0.6 0.8]);期限= 20;抽搐;ishandle(h)&& toc %从音频设备中提取音频样本并将样本添加到%缓冲区。x = ADR();写(audiobuffer,x);y =读取(Audiobuffer,FS,FS-ADR.SampleSperFrame);spec = perverextractautionsfeatures(y,fs);%分类当前频谱图,将标签保存到标签缓冲区,%并将预测的概率保存到概率缓冲区。[YPredicted,聚合氯化铝]=分类(trainedNet,规范,“ExecutionEnvironment”'cpu');YBuffer = [YBuffer(2:结束),YPredicted);probBuffer = [probBuffer(:, 2:结束)、聚合氯化铝(:));%绘制当前波形和频谱图。子图(2,1,1)绘图(Y)轴Ylim ([-1,1]) subplot(2,1,2) pcolor(spec') caxis([-4 2.6445])底纹现在通过执行一个非常简单的命令来进行实际的命令检测%阈值操作。声明一个检测并显示它%数字标题,如果所有以下持有:1)最常见的标签%不是背景。2)最新框架的至少计数%标签一致。3)预测标签的最大概率为at% probThreshold最少。否则,不要声明检测。[YMODE,COUNT] =模式(YBUFFER);maxprob = max(probbuffer(标签== ymode,:));子图(2,1,1)如果YMode = =“背景”||count ”“)其他的标题(字符串(YMode),“字形大小”,20)结束drawnow结束

加载语音命令数据集

下载并提取数据集[1]。

url =“https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz”;downloadFolder = tempdir;datasetFolder = fullfile (downloadFolder,“google_speech”);如果〜存在(DataSetFolder,“dir”) disp ('下载语音命令数据集(1.5 GB)......')Untar(URL,DataSetFolder)结束

创建一个audioDatastore这指向数据集。

广告= audioDatastore (datasetFolder,......'insertumbfolders',真实,......“FileExtensions”'.wav'......'labelsource''foldernames'
广告= audioDataStore具有属性:文件:{'... \ local \ temp \ google_speech \ _background_noise_ \ dope_the_dishes.wav';'... \ appdata \ local \ temp \ google_speech \ _background_noise_ \ dude_miaowing.wav';'... \ appdata \ local \ temp \ google_speech \ _background_noiss_ \ struction_bike.wav'...和64724更多}文件夹:{'c:\ users \ bhemmat \ appdata \ local \ temp \ google_speech'}标签:[_background_noise_;_Background_Noise_;_Background_Noise_ ...和64724更多分类] leartefilesystemroots:{} OutputDataType:'double'支持outportFormats:[“WAV”万博1manbetx“FLAC”“OGG”“MP4”“M4A”] DefaultOutputFormat:“WAV”

选择要识别的单词

指定要为模型识别为命令的单词。标记未命令的所有单词未知的.标记不是命令的单词未知的创建一组单词,它近似于除命令之外的所有单词的分布。网络使用这个组来学习命令和所有其他单词之间的区别。

为了减少已知和未知单词之间的类不平衡,加快处理速度,在训练集中只包含一部分未知单词。不要在训练集中包含带有背景噪声的较长的文件。背景噪声将在稍后的单独步骤中添加。

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

命令=分类([“是的”“不”“向下”“左”“正确”“开”“关”“停止”“走”]);isCommand = ismember (ads.Labels、命令);isUnknown = ~ ismember(广告。标签,[命令,“_background_noise_”]);includeFraction = 0.2;mask = rand(numel(ads.Labels),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);ADSSUBSET =子集(广告,ISCommand | Isunknown);countAckeLabel(Adssubset)
ans = 11×2 table Label Count _______ _____向下2359 go 2372 left 2353 no 2375 off 2357 on 2367 right 2367 stop 2380 unknown 8186 up 2375 yes 2377

将数据分割为训练、验证和测试集

数据集文件夹包含文本文件,其中列出了要用作验证和测试集的音频文件。这些预定义的验证和测试集不包含同一个人对同一词的表达,所以使用这些预定义集比从整个数据集中随机选择一个子集更好。

因为本示例训练的是单个网络,所以它只使用验证集而不是测试集来评估训练的模型。如果您训练了许多网络,并选择验证精度最高的网络作为最终网络,那么您可以使用测试集来评估最终网络。

读取验证文件列表。

c = ImportData(FullFile(DataSetFolder,“validation_list.txt”));filesValidation =字符串(c);

阅读测试文件列表。

c = ImportData(FullFile(DataSetFolder,“testing_list.txt”));filesTest =字符串(c);

确定数据存储中的哪些文件应转到验证集,哪些文件应转到测试集。

files = adssubset.files;sf = split(文件,filesep);ISValidation = ISMember(SF(:,终端1)+“/”+科幻(:,结束),filesValidation);isTest = ismember(sf(:,end-1)) +“/”+科幻(:,结束),filesTest);adsValidation =子集(adsSubset isValidation);adsTrain =子集(adsSubset,~isValidation & ~isTest);

要用整个数据集训练网络,并达到尽可能高的精度,集合逃守血统到目前为止.要快速运行此示例,请设置逃守血统到目前为止真实

depentataset = false;如果reduceDataset numUniqueLabels = nummel (unique(adsTrain.Labels));%将数据集减少20倍adsTrain = splitEachLabel(adsTrain,round(numel(adsTrain. files) / numUniqueLabels / 20));adsValidation = splitEachLabel(adsValidation,round(numel(adsValidation. files) / numUniqueLabels / 20));结束

计算听觉谱图

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

定义特征提取的参数。segmentDuration是每个语音剪辑的持续时间(以秒为单位)。框架是频谱计算的每个帧的持续时间。hopDuration是每个频谱之间的时间步长。numBands为听觉声谱图中过滤器的数量。

创建一个audiofeatureextractor.对象进行特征提取。

fs = 16 e3;%数据集的已知抽样率。semmentduration = 1;Framedrion = 0.025;Hopduration = 0.010;segmensamples = round(semmentduration * fs);FramesAmples =圆形(框架* FS);HOPSAMPLES =圆形(HOPDURATION * FS);重叠amples = framesamples  -  hoppamples;FFTLength = 512;numbands = 50;AFE = audiofeatureextractor(......'samplerate'fs,......“FFTLength”,fftlength,......“窗口”损害(frameSamples“周期”),......'overlaplencth'overlapSamples,......“barkSpectrum”,真的);setExtractorParams(AFE,“barkSpectrum”'numbands'numbands);

从数据集读取文件。训练卷积神经网络需要输入大小一致。数据集中的一些文件长度小于1秒。在音频信号的前面和后面应用零填充,使其具有长度SEGMANSEMPLES.

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

audiofeatureextractor.通过窗口功率正常化听觉频谱图,以便测量与窗口的窗口类型和长度无关。在此示例中,您通过应用对数来处理听觉频谱图。拍摄少数的日志可能会导致循环错误。为避免循环错误,您将反转窗口归一化。

确定要应用的非规范化因子。

unNorm = 2 / (sum (afe.Window) ^ 2);

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

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

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

对于每个分区,从数据存储中读取,填充信号零,然后提取特征。

parforii = 1:numPar subds = partition(adsTrain,numPar,ii);XTrain = 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)];XTrain(:,::,idx)=提取物(afe,xpadded);结束XTrainc {II} = XTrain;结束

将输出转换为沿第四维度的听觉光谱图的四维阵列。

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

通过窗口电源缩放功能,然后拍摄日志。要获得具有更平滑的分布的数据,请使用小偏移采用频谱图的对数。

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

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

如果~ isempty(版本(“平行”))pool = gcp;numpar = numpartitions(adsvalidation,pool);其他的numPar = 1;结束parforii = 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 {ii} = xvalidation;结束xvalidation = cat(4,xvalidationc {:});xvalidation = xvalidation / unnorm;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])阴影声音(x, fs)暂停(2)结束

添加背景噪声数据

该网络不仅要能够识别不同的语音,还必须能够检测输入是否包含沉默或背景噪声。

使用音频文件_Background_Noise._文件夹创建背景噪声的一秒钟剪辑的样本。从每个背景噪声文件创建相同数量的背景剪辑。您还可以创建自己的背景噪音录制并将其添加到_Background_Noise._文件夹。在计算频谱图之前,该函数重新分配每个音频剪辑,其中因子从所提供的范围中的日志均匀分布中采样volumerange.

ADSBKG =子集(广告,ADS.LABELS ==“_background_noise_”);numBkgClips = 4000;如果SDENTATASET NUMBKGCLIPS = NUM​​BKGCLIPS / 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);印第安纳州= 1;count = 1:numbkgfiles bkg = bkgall {count};idxstart = randi(numel(bkg)-fs,numclipsperfile(count),1);idxend = idxstart + fs-1;增益= 10. ^((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(:,:,:,印第安纳州)=提取(afe x);如果国防部(印第安纳州,1000)= = 0 disp (“加工”(印第安纳州)+ +字符串“背景剪辑退出”+字符串(numBkgClips))结束IND = IND + 1;结束结束xbkg = xbkg / unnorm;xbkg = log10(xbkg + epsil);
4000个背景剪辑中处理了1000个,4000个背景剪辑中处理了2000个,4000个背景剪辑中处理了3000个,4000个背景剪辑中处理了4000个

在训练集、验证集和测试集之间分割背景噪声谱图。因为_Background_Noise._文件夹仅包含大约五个半分钟的背景噪声,不同数据集中的背景样本高度相关。为了增加背景噪声的变化,您可以创建自己的背景文件并将其添加到文件夹中。为了增加网络的稳健性,您还可以尝试将背景噪声与语音文件混合到语音文件中。

numTrainBkg =地板(0.85 * numBkgClips);numValidationBkg =地板(0.15 * numBkgClips);XTrain(:,:,: + 1:终端+ numTrainBkg) = Xbkg (:,:,:, 1: numTrainBkg);YTrain(+ 1:结束+ 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)标题(“验证标签分配”

定义神经网络结构

创建一个简单的网络架构,作为一组层。使用卷积和批处理归一化层,并使用最大池化层在“空间上”(即在时间和频率上)对特征映射进行向下采样。添加一个最终的最大池化层,随着时间的推移将输入特征映射全局池化。这在输入谱图中强制了(近似)时间平移不变性,允许网络执行相同的分类,而不依赖于语音在时间上的确切位置。全局池还显著减少了最终完全连接层中的参数数量。为了减少网络记忆训练数据的特定特征的可能性,在最后一个完全连接层的输入中添加少量的dropout。

这个网络很小,因为它只有五个卷积层和几个过滤器。numf.控制卷积层中的过滤器数量。为了提高网络的准确性,尝试通过添加相同的卷积块、批处理归一化块和ReLU层来增加网络深度。你也可以通过增加来增加卷积滤波器的数量numf.

使用加权交叉熵分类损失。weightedClassificationLayer (classWeights)创建自定义分类层,用于计算跨熵丢失,并通过观察加权classWeights.按照类出现的顺序指定类权重类别(YTrain).为了使每个类在损失中具有相等的总权重,使用与每个类中的训练示例数量成反比的类权重。使用Adam优化器训练网络时,训练算法独立于类权值的整体归一化。

Classweights = 1./countcats(itrain);classweights = classweights'/均值(类别级);numclasses = numel(类别(YTrain));timepoolsize = ceil(numhops / 8);dropoutprob = 0.2;numf = 12;图层= [imageInputLayer([numhops numbands])卷积2dlayer(3,numf,“填充”'同样'maxPooling2dLayer(3,“步”,2,“填充”'同样') convolution2dLayer (3 2 * numF“填充”'同样'maxPooling2dLayer(3,“步”,2,“填充”'同样')卷积2dlayer(3,4 * numf,“填充”'同样'maxPooling2dLayer(3,“步”,2,“填充”'同样')卷积2dlayer(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;验证频率=地板(Numel(YTrain)/小型匹配);选项=培训选项('亚当'......“InitialLearnRate”3的军医,......'maxepochs',25,......'minibatchsize'miniBatchSize,......“洗牌”'每个时代'......“阴谋”'培训 - 进步'......“详细”,假,......'vightationdata'{XValidation, YValidation},......'验证职业'validationFrequency,......“LearnRateSchedule”'分段'......“LearnRateDropFactor”, 0.1,......'学习ropperiod', 20);

培训网络。如果你没有GPU,那么训练网络可能会花费一些时间。

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

评估培训的网络

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

如果reduceDataset负载('commandnet.mat''trousahynet');结束YValPred =分类(trainedNet XValidation);validationError = mean(YValPred ~= YValidation);YTrainPred =分类(trainedNet XTrain);= mean(YTrainPred ~= YTrain);disp (“训练误差:+ trainError * 100 +“%”) disp ("验证错误:"+ validationError * 100 +“%”
训练错误:1.526%验证错误:5.1539%

绘制混淆矩阵。通过使用列和行摘要显示每个类的精度和召回率。对混淆矩阵的类进行排序。最大的混淆是在未知的单词和命令之间,向上关闭下来,和

图(“单位”“归一化”“位置”,[0.2 0.2 0.5 0.5]);厘米= confusionchart (YValidation YValPred);厘米。Title =“验证数据的混淆矩阵”;cm.columnsummary =“column-normalized”;厘米。RowSummary =“row-normalized”;sortClasses(厘米,[命令,“未知”“背景”])

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

信息= whos('trousahynet');disp (“网络尺寸:”+ INFO.BYTES / 1024 +“知识库”i = 1:100 x = randn([numHops,numBands]);tic [YPredicted,probs] = classification(训练网,x,“ExecutionEnvironment”'cpu');时间(i) = toc;结束disp (“CPU上的单图像预测时间:”+均值(时间(11:结束))* 1000 +“MS”
网络大小:286.7314 kB CPU上的单张图像预测时间:3.1647 ms

参考资料

[1] Warden P.“语音命令:用于单词语音识别的公共数据集”,2017.可从中获取https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz..版权所有Google 2017.语音命令DataSet在Creative Commons归因4.0许可下许可,可在此处提供:https://creativecommons.org/licenses/by/4.0/legalcode

参考资料

[1] Warden P.“语音命令:用于单词语音识别的公共数据集”,2017.可从中获取http://download.tensorflow.org/data/speech_commands_v0.01.tar.gz..版权所有Google 2017.语音命令DataSet在Creative Commons归因4.0许可下许可,可在此处提供:https://creativecommons.org/licenses/by/4.0/legalcode

另请参阅

||

相关主题