语音命令识别使用Deep学习

这个例子显示了如何培养检测音频语音命令的存在深刻的学习模式。该示例使用语音命令数据集[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)
命令=分类背景

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

测试您的预先训练的命令检测网络流音频从您的麦克风。试着说出其中一个命令,例如,是的没有, 要么。然后,试着说的未登录词的,如马文希拉,或从0到9的任何数字。

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

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

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

audioBuffer = dsp.AsyncBuffer (fs);. class标签= trainedNet.Layers(结束);YBuffer (1: classificationRate / 2) =分类(“背景”);probBuffer =零([numel(标签),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,规范,“执行环境”'中央处理器');YBuffer = [YBuffer(2:结束),YPredicted);probBuffer = [probBuffer(:, 2:结束)、聚合氯化铝(:));%绘制的电流波形和频谱。副区(2,1,1)曲线图(y)轴ylim([ -  1,1])副区(2,1,2)令pColor(规范')CAXIS([ -  4 2.6445])阴影%立即通过执行一个非常简单的做实际的命令检测%阈值操作。声明的检测,并在其显示数字标题如果下面全部保持:1)最常见的标签%不是背景。2)至少最新的帧的countThreshold%标签一致。3)预测的标签的最大概率是在% probThreshold最少。否则,不要声明检测。[YMode,计数] =模式(YBuffer);maxProb = MAX(probBuffer(标签== YMode,:));副区(2,1,1)如果YMode = =“背景”||计数" ")其他的标题(字符串(YMode)“字形大小”,20)结束drawnow结束

加载语音命令数据集

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

url =“https://storage.googleapis.com/download.tensorflow.org/data/speech_commands_v0.01.tar.gz”;downloadFolder = TEMPDIR;datasetFolder =完整文件(downloadFolder,“google_speech”);如果〜存在(datasetFolder,“dir”)disp (“下载语音命令数据集(1.5 GB)......”)解压(URL,datasetFolder)结束

创建audioDatastore它指向的数据集。

广告= audioDatastore (datasetFolder,...'IncludeSubfolders',真正,...“FileExtensions”'.WAV'...'LABELSOURCE''foldernames'
广告= audioDatastore与性能:文件:{ '... \本地的\ Temp \ google_speech \ _background_noise_ \ doing_the_dishes.wav';'... \应用程序数据\本地的\ Temp \ google_speech \ _background_noise_ \ dude_miaowing.wav';'... \应用程序数据\本地的\ Temp \ google_speech \ _background_noise_ \ exercise_bike.wav' ......和64724多}文件夹:{ 'C:\用户\ bhemmat \应用程序数据\本地的\ Temp \ google_speech'}标签:[_background_noise_;_背景噪音_;_background_noise_ ...和64724多个分类] AlternateFileSystemRoots:{} OutputDataType: '双' SupportedOutputFormats:金宝app[ “WAV” “后手” “奥格” “MP4” “M4A”] DefaultOutputFormat: “WAV”

选择单词来认识

指定您希望您的模型来识别为命令的话。标签不在命令,所有单词未知的。未命令,标签字未知的创建一组单词的近似比命令之外的所有词的分布。该网络使用这组学习的命令和所有其他的区别。

为了减少已知和未知单词和加快处理速度之间的阶级失衡,仅包括在训练集合中的未知单词的分数。不包括与训练集中的背景噪声的时间越长的文件。背景噪声将在后面的单独的步骤来添加。

子集创建仅包含命令和未登录词的子集的数据存储。算属于每个类别实例的数目。

命令=分类([“是的”“不”“涨”“向下”“剩下”“正确”“上”“关”“停”“走”]);isCommand = ismember(ads.Labels,命令);isUnknown =〜ismember(ads.Labels,[命令,“_background_noise_”]);includeFraction = 0.2;mask = rand(numel(ads. label),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);adsSubset =子集(广告,isCommand | isUnknown);countEachLabel (adsSubset)
ans = 11×2 table Label Count on 2359 go 2372 left 2353 no 2375 off 2357 on 2367 right 2367 stop 2380 unknown 8186 up 2375 yes 2377

将数据分解为培训、验证和测试集

数据集文件夹包含文本文件,其中列出要用作验证和测试集的音频文件。这些预定义的验证和测试集不包含同一个人发出的相同单词,因此使用这些预定义集比选择整个数据集的随机子集要好。

因为这个例子训练一个网络,它仅使用验证组,而不是测试集,以评估训练的模型。如果你训练多网络,并选择具有最高的准确度验证您的最终网络的网络,那么你可以使用测试仪来评估最终的网络。

阅读的验证文件的列表。

C = IMPORTDATA(完整文件(datasetFolder,'validation_list.txt'));filesValidation =字符串(c);

读取测试文件列表。

C = IMPORTDATA(完整文件(datasetFolder,“testing_list.txt”));filesTest =串(C);

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

文件= adsSubset.Files;SF =分裂(文件,filesep);isValidation = ismember(SF(:,端-1)+“/”+ SF(:,端),filesValidation);isTest = ismember(SF(:,端-1)+“/”+ SF(:,端),filesTest);adsValidation =子集(adsSubset,isValidation);adsTrain =子集(adsSubset,〜isValidation&〜isTest);

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

reduceDataset = FALSE;如果reduceDataset numUniqueLabels = numel(唯一的(adsTrain.Labels));%的20倍减少的数据集adsTrain = splitEachLabel(adsTrain,圆(numel(adsTrain.Files)/ numUniqueLabels / 20));adsValidation = splitEachLabel(adsValidation,圆(numel(adsValidation.Files)/ numUniqueLabels / 20));结束

计算听觉频谱图

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

定义特征提取的参数。segmentDuration是每个语音剪辑的持续时间(以秒计)。frameDuration是每帧频谱计算的持续时间。hopDuration是每个光谱之间的时间步长。numBands是的过滤器在听觉频谱数量。

创建audioFeatureExtractor对象来执行特征抽取。

fs = 16 e3;数据集的已知采样率。segmentDuration = 1;frameDuration = 0.025;hopDuration = 0.010;segmentSamples = ROUND(segmentDuration * FS);frameSamples = ROUND(frameDuration * FS);hopSamples = ROUND(hopDuration * FS);overlapSamples = frameSamples  -  hopSamples;FFTLength = 512;numBands = 50;AFE = audioFeatureExtractor(...'采样率'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)];

为了提取音频功能,通话提取。输出是一个时间跨度的树皮光谱。

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

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

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

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

为了加快处理速度,可以使用以下命令将特征提取分布到多个worker上PARFOR

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

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

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

PARFORi = 1:numPar subds =分区(adsTrain,numPar,ii);XTrain = 0 (numHops numBands 1,元素个数(subds.Files));IDX = 1:numel(subds.Files)X =读(subds);xPadded = [零(地板((segmentSamples尺寸(X,1))/ 2),1); X;零(小区((segmentSamples尺寸(X,1))/ 2),1)];XTrain(:,:,:,IDX)=提取物(AFE,xPadded);结束XTrainC {二} = XTrain;结束

转换输出到一个4维阵列与听觉光谱图沿第四维。

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(版本(“平行”))池= GCP;数参= numpartitions(adsValidation,池);其他的数参= 1;结束PARFORi = 1:numPar subds =分区(adsValidation,numPar,ii);XValidation = 0 (numHops numBands 1,元素个数(subds.Files));IDX = 1:numel(subds.Files)X =读(subds);xPadded = [零(地板((segmentSamples尺寸(X,1))/ 2),1); X;零(小区((segmentSamples尺寸(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 =分钟(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(ⅰ)});副区(2,3,i)的积(X)轴标题(string (adsTrain.Labels (idx (i))))次要情节(2 3 i + 3) spect = (XTrain (:,: 1, idx(我)');pcolor(spect) caxis([specMin specMax])着色声音(X,FS)暂停(2)结束

添加背景噪声数据

网络不仅要能识别不同的语音,还要能检测输入是否有噪声或背景噪声。

使用的音频文件_背景噪音_文件夹中创建的背景噪声中的一个,第二夹子的样品。创建的背景剪辑从每个背景噪音文件的数量不变。您也可以创建自己的背景噪音的记录,并将它们添加到_背景噪音_文件夹。计算所述频谱之前,将功能重新调整与由下式给出的范围内的数均匀分布采样的因子每个音频剪辑volumeRange

adsBkg =子集(广告,ads.Labels ==“_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 =兰迪(numel(BKG)-fs,numClipsPerFile(计数),1);idxEnd = idxStart + FS-1;增益= 10 ^((volumeRange(2)-volumeRange(1))*兰特(numClipsPerFile(计数),1)+ volumeRange(1))。j = 1:numClipsPerFile(count) x = bkg(idxStart(j):idxEnd(j))*增益(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);
处理1000个背景剪辑出的4000处理2000背景剪辑出的4000处理3000个背景剪辑出的4000处理4000个背景剪辑出来的4000

将背景噪声的谱图拆分为训练集、验证集和测试集。因为_背景噪音_文件夹仅包含约五分半钟的背景噪声的,在不同的数据集的背景样品是高度相关的。为了提高在背景噪音的变化,你可以创建自己的背景文件,并将它们添加到该文件夹​​。为了增加网络噪声的鲁棒性,你也可以尝试的背景噪声混入语音文件。

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。

这个网络很小,因为它只有5个卷积层,几乎没有过滤器。numF控制卷积层中过滤器的数量。为了提高网络的准确性,可以尝试通过添加相同的卷积、批处理标准化和ReLU层来增加网络深度。您还可以尝试通过增加卷积过滤器的数量来增加它numF

使用加权交叉熵分类的损失。weightedClassificationLayer (classWeights)创建一个自定义分类层,该层使用加权的观测值计算交叉熵损失classWeights。指定类权重的顺序与类出现的顺序相同类别(YTrain)。为了使每个班损失的总重量相等,可以使用与每个班的训练实例数量成反比的班级权重。当使用Adam优化器来训练网络时,训练算法独立于类权重的整体规范化。

classWeights = 1./countcats(YTrain);classWeights = classWeights' /平均值(classWeights);numClasses = numel(类别(YTrain));timePoolSize =小区(numHops / 8);dropoutProb = 0.2;numF = 12;层= [imageInputLayer([numHops numBands])convolution2dLayer(3,numF,“填充”'相同'maxPooling2dLayer(3,“跨越论”2,“填充”'相同')convolution2dLayer(3,2 * numF,“填充”'相同'maxPooling2dLayer(3,“跨越论”2,“填充”'相同')convolution2dLayer(3,4- * numF,“填充”'相同'maxPooling2dLayer(3,“跨越论”2,“填充”'相同')convolution2dLayer(3,4- * numF,“填充”'相同') batchNormalizationLayer reluLayer convolution2dLayer(3,4*numF,“填充”'相同'maxPooling2dLayer([timePoolSize,1]) dropoutLayer(dropoutProb)全连接层(numClasses) softmaxLayer weightedClassificationLayer(classWeights)];

列车网络

指定培训选项。使用亚当优化与128列车的小批量大小为25个时代和后20个时代的10倍降低学习速度。

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

培训网络。如果你没有一个GPU,那么训练网络可能需要时间。

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

评估培训网络

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

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

画出混淆矩阵。显示的精度和通过使用列和行摘要召回为每个类。排序的混淆矩阵的类。最大的困惑是未知的词和命令之间,向上没有没有

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

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

信息=卫生组织('trainedNet');disp (“网络规模”+ info.bytes / 1024 +“知识库”i = 1:100 x = randn([numHops, numband]);t [YPredicted,probs] =分类(trainedNet,x,“执行环境”'中央处理器');时间(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年谷歌的语音命令数据集采用知识共享署名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年谷歌的语音命令数据集采用知识共享署名4.0许可协议授权,可在这里:https://creativecommons.org/licenses/by/4.0/legalcode

也可以看看

||

相关话题