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

这个例子展示了如何训练一个深度学习模型来检测音频中语音命令的存在。该示例使用语音命令数据集[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 = 0.01 * randn(16e3,1);

计算听觉谱图。

auditorySpect = helperExtractAuditoryFeatures (x, fs);

对背景噪声进行分类。

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

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

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

指定赫兹的识别率,并创建一个可以读取你的麦克风音频的音频设备读取器。

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

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

audioBuffer = dsp.AsyncBuffer (fs);. class标签= trainedNet.Layers(结束);YBuffer (1: classificationRate / 2) =分类(“背景”);probBuffer = 0([元素个数(标签),classificationRate / 2));countThreshold =装天花板(classificationRate * 0.2);probThreshold = 0.7;

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

h =图(“单位”'标准化'“位置”,[0.2 0.1 0.6 0.8]);期限= 20;抽搐;ishandle(H)&& TOC <的timeLimit%从音频设备提取音频样本并将样品添加到%的缓冲区。X = ADR();写(audioBuffer,X);Y =读(audioBuffer,FS,FS-adr.SamplesPerFrame);规格= helperExtractAuditoryFeatures(Y,FS);%分类目前的频谱,保存标签到标签缓冲,%并保存预测概率的概率缓冲器。[YPredicted,聚合氯化铝]=分类(trainedNet,规范,'executionenvironment''CPU');YBuffer = [YBuffer(2:结束),YPredicted);probBuffer = [probBuffer(:, 2:结束)、聚合氯化铝(:));%绘制电流波形和谱图。副区(2,1,1)曲线图(y)轴Ylim([ -  1,1])子图(2,1,2)PColor(SPEC')Caxis([ -  4 2.6445])阴影%现在通过执行一个非常简单的实际命令检测来进行实际命令检测%阈值操作。声明的检测,并在其显示%数字标题,如果所有以下持有:1)最常见的标签%不是背景。2)至少最新的帧的countThreshold%标签同意。3)预测标签的最大概率是在% probThreshold最少。否则,不要声明检测。[YMode,计数]=模式(YBuffer);maxProb = max(probBuffer(labels == YMode,:)); / /输出次要情节(2,1,1)如果YMode = =“背景”||计数”“)其他的标题(string (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)……”)解压(URL,datasetFolder)结束

创建一个audiodatastore.这指向了数据集。

广告= audioDatastore (datasetFolder,......“IncludeSubfolders”,真实,......“FileExtensions”“wav”......“LabelSource”'foldernames'
ads = audioDatastore与属性:文件:{'…\本地\Temp\google_speech\_background_noise_\doing_the_dishes.wav';’……\ AppData \当地\ Temp \ google_speech \ _background_noise_ \ dude_miaowing.wav”;’……\ AppData \当地\ Temp \ google_speech \ _background_noise_ \ exercise_bike.wav”……{'C:\Users\bhemmat\AppData\Local\Temp\google_speech'}标签:[_background_noise_;_background_noise_;_background_noise_……alteratefilesystemroots: {} OutputDataType: 'double' SupportedOutputFormats: ["wav金宝app" "flac" "ogg" "mp4" "m4a"] DefaultOutputFormat: "wav"

选择单词来认识

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

为了减少已知和未知的单词和加速处理之间的类不平衡,仅包括训练集中的一小部分未知单词。不要在训练集中包含具有背景噪声的较长文件。背景技术噪音将在单独的步骤中添加。

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

命令=分类([“是的”“不”《飞屋环游记》“向下”“左”“正确”“上”“关闭”“停止”“走”]);IsCommand = ISMember(Ads.Labels,命令);isunknown =〜ismember(ads.labels,[命令,“_background_noise_”]);includeFraction = 0.2;mask = rand(numel(ads.Labels),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);adsSubset =子集(广告,isCommand | isUnknown);countEachLabel (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 = string(c);

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

文件= adsSubset.Files;科幻小说=分裂(文件、filesep);isValidation = ismember(sf(:,end-1)) +“/”+ SF(:,结束),filesvalidation);ISTEST = ISMEMEMEMEMEMEMEMER(SF(:,终止 -  1)+“/”+ SF(:,结束),FILESTEST);ADSValidation =子集(ADSSUBSET,ISValidation);adstrain =子集(ADSUBSET,〜ISValidation&〜ISTEST);

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

reduceDataset = 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));结束

计算听觉谱图

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

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

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

fs = 16 e3;%数据集的已知抽样率。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 (......'samplerate'fs,......“FFTLength”FFTLength,......“窗口”损害(frameSamples'定期'),......'OverlapLength'overlapSamples,......“barkSpectrum”,真正的);setExtractorParams (afe“barkSpectrum”“NumBands”, numBands);

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

X =读(adsTrain);NUMSAMPLES =尺寸(X,1);numToPadFront =地板((segmentSamples  -  NUMSAMPLES)/ 2);numToPadBack =小区((segmentSamples  -  NUMSAMPLES)/ 2);xPadded = [零(numToPadFront,1,“喜欢”中,x); X;零(numToPadBack,1,“喜欢”中,x)];

为了提取音频功能,通话提取物.输出是跨行带有时间的Bark谱。

设有=提取物(AFE,xPadded);[numHops,numFeatures] =大小(特征)
numHops = 98 numFeatures = 50

audioFeatureExtractor由窗口功率归一化的听觉频谱,使得测量是独立窗口和窗口的长度的类型。在这个例子中,您可以通过应用对数后处理听觉谱图。以日志小的数字可能会导致舍入误差。为了避免舍入误差,你将扭转窗口正常化。

确定应用的非正规化的因素。

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

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

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

如果~ isempty(版本(“平行”))&&〜reduceDataset池= GCP;数参= numpartitions(adsTrain,池);其他的numpar = 1;结束

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

议案ii = 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 {二} = XTrain;结束

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

XTrain =猫(4,XTrainC {:});[numHops,numBands,numChannels,numSpec] =尺寸(XTrain)
numHops = 98 numBands = 50 numChannels = 1 numSpec = 25041

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

XTrain = XTrain / Unnorm;epsil = 1e-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 =猫(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])阴影sound(x,fs)暂停(2)结束

添加背景噪声数据

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

使用的音频文件_background_noise_文件夹中创建的背景噪声中的一个,第二夹子的样品。创建的背景剪辑从每个背景噪音文件的数量不变。您也可以创建自己的背景噪音的记录,并将它们添加到_background_noise_文件夹。在计算谱图之前,该函数使用从给定范围内的对数均匀分布中采样的因子对每个音频剪辑进行缩放volumeRange

adsBkg =子集(广告,广告。标签= =“_background_noise_”);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(:,:,:,印第安纳州)=提取(afe x);如果国防部(印第安纳州,1000)= = 0 disp (“加工”+字符串(IND)+“背景剪辑退出”+字符串(numBkgClips))结束IND = IND + 1;结束结束Xbkg = Xbkg / unNorm;Xbkg = log10(Xbkg + epsil);
由4000个加工的2000个背景剪辑的加工1000个背景剪辑中的4000个加工3000个背景剪辑中的4000个加工4000个背景夹子中的4000个

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

numTrainBkg =地板(0.85 * numBkgClips);numValidationBkg =地板(0.15 * numBkgClips);XTrain(:,:,: + 1:终端+ numTrainBkg) = Xbkg (:,:,:, 1: numTrainBkg);YTrain(+ 1:结束+ numTrainBkg) =“背景”;XValidation(:,:,: + 1:终端+ numValidationBkg) = Xbkg (:,:,:, numTrainBkg + 1:结束);YValidation(+ 1:结束+ 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 (YTrain);classWeights = classWeights ' /意味着(classWeights);numClasses =元素个数(类别(YTrain));timePoolSize =装天花板(numHops / 8);dropoutProb = 0.2;numF = 12;[imageInputLayer([numHops numBands]))卷积2dlayer (3,numF,“填充”“相同”maxPooling2dLayer(3,'走吧',2,“填充”“相同”)卷积2dlayer(3,2 * numf,“填充”“相同”maxPooling2dLayer(3,'走吧',2,“填充”“相同”) convolution2dLayer(3、4 * numF,“填充”“相同”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列车的小批量大小为25个时代和后20个时代的10倍降低学习速度。

miniBatchSize = 128;validationFrequency =地板(元素个数(YTrain) / miniBatchSize);选择= trainingOptions (“亚当”......“InitialLearnRate”3的军医,......“MaxEpochs”25,......'MiniBatchSize'miniBatchSize,......“洗牌”“every-epoch”......'plots'“训练进度”......“详细”假的,......“ValidationData”{XValidation, YValidation},......“ValidationFrequency”validationFrequency,......“LearnRateSchedule”“分段”......“LearnRateDropFactor”,0.1,......'LearnRateDropPeriod'20);

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

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

评估培训网络

计算在训练集(无数据扩张)和验证集合网络的最终精度。该网络是在这个数据集非常准确。然而,培训,验证和测试数据都具有相似的分布不一定反映真实世界的环境。此限制特别适用于未知的类别,它只包含少量单词的话语。

如果SDENTATASET LOAD('commandNet.mat''trainedNet');结束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]);CM = ConfusionChart(YValidation,YVALPRED);cm.title =“验证数据的混淆矩阵”;厘米。ColumnSummary ='列 - 归一化';厘米。RowSummary =“row-normalized”;SortClasses(cm,[命令,“未知”“背景”])

与约束硬件资源的应用,如移动应用程序时,考虑可用内存和计算资源的限制。计算以千字节的网络的总大小,并使用CPU时测试其预测速度。预测时间为单个输入图像进行分类的时间。如果您输入多张图片到网络上,这些可以同时划分,导致每幅图像更短的预测时间。当分类音频流,但是,单张图像的预测时间是最相关的。

信息=卫生组织('trainedNet');disp (“网络规模”+ info.bytes / 1024 +“知识库”i = 1:100 x = randn([numHops,numBands]);tic [YPredicted,probs] = classification(训练网,x,“刽子果环境”'CPU');时间(i)= toc;结束disp (“关于CPU单图像预测时间:”+的意思是(时间(11:结束))* 1000 +“女士”
网络大小:286.7314 kB CPU上的单张图像预测时间:3.1647 ms

参考文献

[1]看守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.

参考文献

[1]看守P.“语音命令:用于单词语音识别一个公共数据集”,2017年可从http://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.

另请参阅

||

相关的话题