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

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

要从零开始训练一个网络,您必须先下载数据集。如果您不想下载数据集或训练网络,那么您可以加载这个示例提供的预训练网络,并执行示例的下面两个部分:识别命令与预训练网络检测命令使用串流音频从麦克风

识别命令与预训练网络

再进训练过程中的细节,你会使用预训练的语音识别网络来识别语音命令。

装入预先训练网络。

负载(“commandNet.mat”)

该网络经过训练,可以识别以下语音命令:

  • “是”

  • “没有”

  • “涨”

  • “下”

  • “左”

  • “对”

  • “上”

  • “关”

  • “停”

  • “走”

加载其中一个人说“停”短的语音信号。

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

听命令。

声音(X,FS)

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

使用功能extractAuditoryFeature计算听觉谱图。您将在稍后的例子经过特征提取的细节。

auditorySpect = helperExtractAuditoryFeatures(X,FS);

分类基于其听觉频谱的命令。

命令=分类(trainedNet,auditorySpect)
命令=绝对停止

该网络进行训练不属于该组为“未知”分类的话。

现在,您将分类没有包含在命令识别列表中选择一个字(“打”)。

加载语音信号和收听。

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。

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

classificationRate = 20;ADR = audioDeviceReader(“SampleRate”,FS,'SamplesPerFrame',地板(FS / classificationRate));

初始化音频缓冲。提取网络的分类标签。初始化半秒的标签和音频流的分类概率的缓冲区。使用这些缓冲区分类结果在一段较长的时间,并通过检测到命令时,在该生成“协议”进行比较。指定决策逻辑阈值。

audioBuffer = dsp.AsyncBuffer(FS);标签= trainedNet.Layers(结束).Classes;YBuffer(1:classificationRate / 2)=分类(“背景”);probBuffer =零([numel(标签),classificationRate / 2]);countThreshold =小区(classificationRate * 0.2);probThreshold = 0.7;

创建人物和检测命令,只要创建的人物存在。无限期运行循环,集时限天道酬勤。要停止现场检测,只需关闭的身影。

h =图('单位',“归一化”,'位置'[0.2 0.1 0.6 0.8]);的timeLimit = 20;抽动;ishandle(h) && toc < timeLimit从音频设备中提取音频样本并将样本添加到%的缓冲。x = adr ();写(audioBuffer x);fs, y =阅读(audioBuffer fs-adr.SamplesPerFrame);规范= helperExtractAuditoryFeatures (y, fs);%对当前光谱图进行分类,将标签保存到标签缓冲区,%,并将预测的概率保存到概率缓冲区。[YPredicted,probs] =分类(trainedNet,规格,“ExecutionEnvironment”,“cpu”);YBuffer = [YBuffer(2:结束),YPredicted];probBuffer = [probBuffer(:,2:结束),probs(:)];%绘制的电流波形和频谱。次要情节(2,1,1)情节(y)轴ylim([-1,1]) subplot(2,1,2) pcolor(spec') caxis([-4 2.6445])底纹平面现在通过执行一个非常简单的命令来执行实际的命令检测%的阈值操作。声明检测并将其显示在%图标题,如果所有下列条件成立:1)最常见的标签%不是背景。2)至少计算最新帧的计数阈值%标签一致。3)预测标签的最大概率为%至少probThreshold。否则,不申报的检测。[YMode,计数] =模式(YBuffer);maxProb = MAX(probBuffer(标签== YMode,:));副区(2,1,1)如果YMode ==“背景”|| count < count threshold || maxProb < probThreshold title(“”)其他标题(字符串(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,“目录”)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:万博1manbetx[ “WAV” “后手” “奥格” “MP4” “M4A”] DefaultOutputFormat: “WAV”

选择要识别的单词

指定您希望模型将其识别为命令的单词。将非命令的所有单词标记为未知。未命令,标签字未知创建一组单词,这些单词近似于除命令之外的所有单词的分布。网络使用这个组来学习命令和所有其他单词之间的区别。

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

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

命令=分类([“是”,“没有”,“涨”,“下”,“左”,“对”,“上”,“关”,“停”,“走”]);isCommand = ismember (ads.Labels、命令);isUnknown = ~ ismember (ads.Labels[命令,“_背景噪音_”]);includeFraction = 0.2;掩模=兰特(numel(ads.Labels),1)“未知”);adsSubset =子集(广告,isCommand | isUnknown);countEachLabel(adsSubset)
ANS = 11×2表标签数量_______ _____下降2359转到2372在2367右2367停止2380未知8186留下2353没有2375关高达2357 2375个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)+“/”+科幻(:,结束),filesValidation);isTest = ismember(sf(:,end-1) +“/”+科幻(:,结束),filesTest);adsValidation =子集(adsSubset isValidation);adsTrain =子集(ads子集,~isValidation & ~isTest);

要培养与整个数据集的网络,实现尽可能高的精度,集reduceDataset。要快速运行这个例子,一套reduceDataset真正

reduceDataset = false;如果reduceDataset numUniqueLabels = numel(unique(adstrain . tags));%的20倍减少的数据集adsTrain = splitEachLabel(adsTrain,round(numel(adstr . files) / numUniqueLabels / 20));adsValidation = splitEachLabel(adsValidation,round(numel(adsValidation. files) / numUniqueLabels / 20));结束

计算听觉频谱图

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

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

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

FS = 16e3;%所述数据集的已知采样率。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(“SampleRate”,FS,'FFTLength',FFTLength,'窗口',汉恩(frameSamples,“周期”“OverlapLength”,overlapSamples,'barkSpectrum',真正);setExtractorParams(AFE,'barkSpectrum','NumBands',numBands);

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

x =阅读(adsTrain);numSamples =大小(x, 1);numToPadFront = floor((segmentSamples - numSamples)/2);numToPadBack = ceil((segmentSamples - numSamples)/2);xPadded = 0 (numToPadFront 1'喜欢',x); x; 0 (numToPadBack 1'喜欢',x));

要提取音频特征,请调用提取。输出是巴克谱与整个行的时间。

特点=提取(afe xPadded);[numHops, numFeatures] =大小(特性)
numHops = 98个numFeatures = 50

audioFeatureExtractor利用窗口功率对听觉谱图进行归一化,使测量结果与窗口类型和窗口长度无关。在本例中,您通过应用一个对数对听觉谱图进行后处理。记录小的数字可能会导致舍入错误。为了避免舍入错误,您将反转窗口规范化。

确定要应用的反正化因子。

unNorm = 2 /(总和(afe.Window)^ 2);

为了加快处理速度,可以使用分布在多个工人的特征提取parfor

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

如果〜的isEmpty(VER('平行')) && ~reduceDataset pool = gcp;numPar = numpartitions (adsTrain、池);其他numPar = 1;结束

对于每个分区,从数据存储区,零垫的信号读出,然后解压缩的功能。

parforII = 1:数参subds =分区(adsTrain,数参,ⅱ);XTrain =零(numHops,numBands,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 {2} = XTrain;结束

的输出转换成与沿第四维听觉谱图4维数组。

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

通过缩放窗口功率的特征,然后采取日志。为了获得具有更平滑的分布数据,采取使用一个小的偏移频谱的对数。

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

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

如果〜的isEmpty(VER('平行'))池= GCP;数参= numpartitions(adsValidation,池);其他numPar = 1;结束parforII = 1:数参subds =分区(adsValidation,数参,ⅱ);XValidation =零(numHops,numBands,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)];XValidation (:,:,:, idx) =提取(afe xPadded);结束XValidationC {二} = 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(numel(adsTrain.Files),3);数字('单位',“归一化”,'位置'[0.2 0.2 0.6 0.6]);对于I = 1:3 [X,FS] = audioread(adsTrain.Files {IDX(ⅰ)});副区(2,3,i)的积(X)轴标题(字符串(adsTrain.Labels(IDX(I))))副区(2,3,i + 3中)SPECT =(XTrain(:,:,1,IDX(I))');令pColor(SPECT)CAXIS([specMin specMax])阴影平面声音(x, fs)暂停(2)结束

添加背景噪声数据

该网络必须不仅能够识别不同的话语,而且如果输入包含静寂或背景噪声检测。

中的音频文件_background_noise文件夹创建背景噪声的一秒剪辑样本。从每个背景噪声文件创建相同数量的背景剪辑。还可以创建自己的背景噪声录音并将其添加到_background_noise_文件夹。计算所述频谱之前,将功能重新调整与由下式给出的范围内的数均匀分布采样的因子每个音频剪辑volumeRange

adsBkg =子集(广告,ads.Labels ==“_背景噪音_”);numBkgClips = 4000;如果reduceDataset numBkgClips = numBkgClips/20;结束volumeRange = LOG10([1E -4,1-]);numBkgFiles = numel(adsBkg.Files);numClipsPerFile = histcounts(1:numBkgClips,linspace(1,numBkgClips,numBkgFiles + 1));Xbkg =零(大小(XTrain,1),大小(XTrain,2),1,numBkgClips,'单');bkgAll = readall (adsBkg);印第安纳州= 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(计数)X = BKG(idxStart(J):idxEnd(J))*增益(J);X =最大值(分钟(X,1), -  1);Xbkg(:,:,:,IND)=提取物(AFE,X);如果MOD(IND,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:端+ numValidationBkg)= Xbkg(:,:,:,numTrainBkg + 1:结束);YValidation(端+ 1:端+ numValidationBkg)=“背景”;

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

数字('单位',“归一化”,'位置',[0.2 0.2 0.5 0.5])子图(2,1,1)直方图(YTrain)“培训标签分发”)副区(2,1,2)的直方图(YValidation)标题(“验证标签分发”)

定义神经网络体系结构

创建一个简单的网络架构层的阵列。使用卷积和批标准化层,以及下采样特征映射“空间”(即,在时间和频率),使用最大池层。添加一个最终的最大池层池全球输入特征映射随着时间的推移。这加强了(大约)时间平移在输入频谱图不变性,允许网络在时间执行分类独立语音的精确位置是相同的。全局池也显著降低在最终完全连接层参数的数目。为了减少网络记忆特定的可能性训练数据的特征,信号失落的少量到输入添加到最后一个完全连接层。

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

采用加权交叉熵分类损失。weightedClassificationLayer(classWeights)创建计算与由加权观测交叉熵损失的自定义分类层classWeights。指定以相同的顺序类权重类出现在类别(YTrain)。给每个类等于总重量的损失,使用类的权重是成反比的每一类训练示例的数目。当使用优化亚当训练网络,训练算法是独立于类的权重的整体归一化。

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

列车网络的

指定培训选项。使用最小批处理大小为128的Adam优化器。训练25个epoch,并且在20个epoch后将学习率降低10倍。

miniBatchSize = 128;validationFrequency =地板(numel(YTrain)/ miniBatchSize);选项= trainingOptions(“亚当”,'InitialLearnRate',3E-4,'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);validationError =平均值(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);厘米。Title =“混淆矩阵用于验证数据”;cm.ColumnSummary =“column-normalized”;cm.RowSummary =“行标准化”;sortClasses(厘米,[命令,“未知”,“背景”])

当处理具有受限硬件资源(如移动应用程序)的应用程序时,请考虑可用内存和计算资源的限制。计算网络的总大小(以千字节为单位),并在使用CPU时测试其预测速度。预测时间是对单个输入图像进行分类的时间。如果向网络输入多幅图像,可以同时对这些图像进行分类,从而缩短每张图像的预测时间。然而,在对流式音频进行分类时,单图像预测时间是最相关的。

信息=谁(“trainedNet”);DISP(“网络大小:”+信息。字节/ 1024 +“KB”)对于I = 1:100×= randn([numHops,numBands]);抽动[YPredicted,probs] =分类(trainedNet,X,“ExecutionEnvironment”,“cpu”);时间(i) = toc;结束DISP(“CPU上的单图像预测时间:”+平均(时间(11:结束))* 1000 +“ 多发性硬化症”)
网络规模:在CPU 286.7314 KB单图像预测时间:3.1647毫秒

参考

[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

另请参阅

||

相关话题