主要内容

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

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

要从头开始训练网络,必须先下载数据集。如果不想下载数据集或训练网络,则可以加载本示例提供的预训练网络,并执行示例的下两部分:通过预先训练的网络识别命令使用来自麦克风的流式音频检测命令

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

在详细介绍培训过程之前,您将使用经过预培训的语音识别网络来识别语音命令。

加载预先训练好的网络。

装载(“commandNet.mat”)

对网络进行培训,以识别以下语音命令:

  • “是的”

  • “不”

  • 《飞屋环游记》

  • “向下”

  • “左”

  • “正确”

  • “上”

  • “关闭”

  • “停止”

  • “走”

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

[x,fs]=音频读取(“停止命令。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=针孔(16e3);

计算听觉频谱图。

auditorySpect = helperExtractAuditoryFeatures (x, fs);

对背景噪声进行分类。

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

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

在麦克风的流式音频上测试预先训练好的命令检测网络。例如,尝试说出其中一个命令,是的,没有停止.然后,试着说出一个未知单词,如马文,希拉,,房子,,,或0到9之间的任意数字。

以Hz为单位指定分类率,并创建可以从麦克风读取音频的音频设备读取器。

分类率=20;adr=音频设备阅读器(“SampleRate”,财政司司长,“样品性能框架”,楼(fs/分级率);

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

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

只要创建的图形存在,就创建图形并检测命令期限Inf.要停止实时检测,只需关闭图形。

h=数字(“单位”,“正常化”,“位置”,[0.20.1 0.6 0.8]);时限=20;ticishandle(h)和&toc<时限%从音频设备提取音频样本并将样本添加到%缓冲区。x=adr();write(audioBuffer,x);y=read(audioBuffer,fs,fs adr.SamplesPerFrame);spec=helperExtractAuditoryFeatures(y,fs);%对当前光谱图进行分类,将标签保存到标签缓冲区,%并将预测的概率保存到概率缓冲区。[YPredicted,聚合氯化铝]=分类(trainedNet,规范,“执行环境”,“cpu”);YBuffer=[YBuffer(2:end),yppredicted];probBuffer=[probBuffer(:,2:end),probs(:)];%绘制电流波形和谱图。子地块(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)如果伊莫德==“背景”||计数”“)其他的标题(string (YMode),“字形大小”, 20)结束刷新屏幕结束

加载语音命令数据集

此示例使用Google Speech Commands数据集[1]。下载该数据集并卸载下载的文件。将PathToDatabase设置为数据的位置。

url ='https://ssd.mathworks.com/万博1manbetxsupportfiles/audio/google_speech.zip';downloadFolder=tempdir;dataFolder=fullfile(downloadFolder,“google_speech”);如果~exist(数据文件夹,“dir”)disp(“下载数据集(1.4 GB)……”解压缩(url, downloadFolder)结束

创建培训数据存储

创建一个音频数据存储(音频工具箱)这指向训练数据集。

广告= audioDatastore (fullfile (dataFolder,“火车”),...“IncludeSubfolders”是的,...“文件扩展名”,“.wav”,...“LabelSource”,“foldernames”)
ads = audioDatastore与属性:文件:{'…\AppData\Local\Temp\google_speech\train\bed\00176480_nohash_0.wav';’……\ AppData \当地\ Temp \床google_speech \培训\ \ 004 ae714_nohash_0.wav;’……\ AppData \当地\ Temp \床google_speech \培训\ \ 004 ae714_nohash_1.wav……{'C:\Users\jibrahim\AppData\Local\Temp\google_speech\train'}标签:[bed;床上;床上……alteratefilesystemroots: {} OutputDataType: 'double' SupportedOutputFormats: ["wav万博1manbetx" "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=子集(ads,isCommand | isUnknown);计数标签(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 (fullfile (dataFolder,“验证”),...“IncludeSubfolders”是的,...“文件扩展名”,“.wav”,...“LabelSource”,“foldernames”) isCommand = ismember(ads.Labels,commands);isUnknown = ~ isCommand;includeFraction = 0.2;mask = rand(numel(ads.Labels),1) < includeFraction;isUnknown = isUnknown & mask;ads.Labels (isUnknown) =分类(“未知”);adsValidation =子集(广告,isCommand | isUnknown);countEachLabel (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真正的

reducedastatset=false;如果reduceDataset numiniqueLabels=numel(唯一(adsTrain.Labels));%将数据集缩减到原来的20倍adsTrain=splitEachLabel(adsTrain,round(numel(adsTrain.Files)/numUniqueLabels/20));adsvalization=splitEachLabel(adsvalization,round(numel(adsvalization.Files)/numUniqueLabels/20));结束

计算听觉频谱图

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

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

创建一个音频特征提取器(音频工具箱)对象以执行特征提取。

fs = 16 e3;%数据集的已知抽样率。segmentDuration=1;frameDuration=0.025;hopDuration=0.010;segmentSamples=round(segmentDuration*fs);frameSamples=round(frameDuration*fs);hopSamples=round(hopDuration*fs);OverlapseSamples=frameSamples-hopSamples;FFTLLength=512;Numberands=50;afe=audioFeatureExtractor(...“SampleRate”,财政司司长,...“FFTLength”FFTLength,...“窗口”,hann(框架样本,“周期性”),...“重叠长度”overlapSamples,...“巴克光谱”,真正的);setExtractorParams (afe“巴克光谱”,“麻木人”numBands,“窗口规范化”、假);

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

x=读取(adsTrain);numSamples=大小(x,1);numToPadFront=地板((分段采样-numSamples)/2);numToPadBack=天花板((分段采样-numSamples)/2);xPadded=[零(numToPadFront,1,“喜欢”,x);x;零(numToPadBack,1,“喜欢”,x)];

要提取音频功能,请调用摘录.输出为横行随时间变化的树皮谱。

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

在本例中,通过应用对数对听觉声谱图进行后处理。取小数字的对数会导致四舍五入错误。

为了加快处理速度,可以使用将特征提取分布到多个辅助对象帕弗

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

如果~z~我是空的(“平行”))&&&~reducedasetpool=gcp;numPar=numpartitions(adsTrain,pool);其他的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=[zeros(floor((segmentSamples size(x,1))/2),1);x;zeros(ceil((segmentSamples size(x,1))/2),1];XTrain(:,:,:,idx)=extract(afe,xPadded);结束XTrainC{ii}=XTrain;结束

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

XTrain=cat(4,XTrainC{:});[numHops,numBands,numChannels,numSpec]=size(XTrain)
numHops=98 numBands=50 numChannels=1 numSpec=25021

通过窗口功率缩放特征,然后获取日志。要获得分布更平滑的数据,请使用小偏移量获取光谱图的对数。

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

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

如果~z~我是空的(“平行”) pool = gcp;numPar = numpartitions (adsValidation、池);其他的numPar=1;结束帕弗ii=1:numPar subds=partition(adsvalization,numPar,ii);XValidation=zero(numHops,numBands,1,numel(subds.Files));对于idx=1:numel(subds.Files)x=read(subds);xPadded=[zeros(floor((segmentSamples size(x,1))/2),1);x;zeros(ceil((segmentSamples size(x,1))/2),1];XValidation(:,:,:,idx)=extract(afe,xPadded);结束XValidationC{ii}=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(numel(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)轴标题(字符串(adsTrain.Labels(idx(i)))子批次(2,3,i+3)spect=(XTrain(:,:,1,idx(i)));pcolor(spect)caxis([specMin specMax])着色声音(x,fs)暂停(2)结束

添加背景噪声数据

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

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

adsBkg = audioDatastore (fullfile (dataFolder“背景”) numBkgClips = 4000;如果reducedastatset numBkgClips=numBkgClips/20;结束容积率=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);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)+“背景剪辑退出”+字符串(多个片段))结束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个

在训练集、验证集和测试集之间分割背景噪声的频谱图_背景噪声_文件夹仅包含大约五分钟半的背景噪声,不同数据集中的背景样本高度相关。若要增加背景噪声的变化,可以创建自己的背景文件并将其添加到文件夹中。若要提高网络对噪声的鲁棒性,还可以尝试混合backgr将噪音输入语音文件。

numTrainBkg=地板(0.85*numBkgClips);numValidationBkg=地板(0.15*numBkgClips);XTrain(:,:,:,end+1:end+numTrainBkg)=Xbkg(:,:,:,1:numTrainBkg);YTrain(结束+1:end+numTrainBkg)=“背景”; XValidation(:,:,:,end+1:end+numValidationBkg)=Xbkg(:,:,:,numTrainBkg+1:end);YValidation(end+1:end+NUMVLIDATIONBKG)=“背景”;

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

身材(“单位”,“正常化”,“位置”,[0.2 0.2 0.5 0.5])子批次(2,1,1)直方图(YTrain)标题(“培训标签分发”)子图(2,1,2)直方图(YValidation)标题(“验证标签分配”)

定义神经网络结构

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

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

使用加权交叉熵分类损失。权重ClassificationLayer(类权重)创建一个自定义分类层,该层使用加权的观测值计算交叉熵损失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 reluLayer MaxPoolig2dLayer(3,“大步走”2,“填充”,“相同”)卷积2层(3,2*numF,“填充”,“相同”)batchNormalizationLayer reluLayer MaxPoolig2dLayer(3,“大步走”2,“填充”,“相同”)卷积2层(3,4*numF,“填充”,“相同”)batchNormalizationLayer reluLayer MaxPoolig2dLayer(3,“大步走”2,“填充”,“相同”)卷积2层(3,4*numF,“填充”,“相同”)batchNormalizationLayer reluLayer卷积2Dlayer(3,4*numF,“填充”,“相同”)batchNormalizationLayer reluLayer MaxPoolg2dLayer([timePoolSize,1])DropOutployer(dropoutProb)fullyConnectedLayer(numClasses)softmaxLayer weightedClassificationLayer(classWeights)];

列车网络

指定训练选项。使用最小批量为128的Adam优化器。训练25个阶段,20个阶段后将学习率降低10倍。

miniBatchSize=128;验证频率=楼层(numel(YTrain)/最小批量大小);选项=培训选项(“亚当”,...“初始学习率”,3e-4,...“MaxEpochs”,25,...“MiniBatchSize”miniBatchSize,...“洗牌”,“every-epoch”,...“情节”,“培训进度”,...“详细”假的,...“ValidationData”,{XValidation,YValidation},...“ValidationFrequency”validationFrequency,...“LearnRateSchedule”,“分段”,...“LearnRateDropFactor”,0.1,...“LearnRateDropPeriod”,20);

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

trainedNet=列车网络(XTrain、YTrain、图层、选项);

评估培训网络

在训练集(无数据扩充)和验证集上计算网络的最终精度。网络在此数据集上非常精确。但是,训练、验证和测试数据都具有类似的分布,不一定反映真实环境。此限制尤其适用于未知的类别,其中只包含少量单词的语句。

如果减载(“commandNet.mat”,“训练网”);结束YValPred=分类(trainedNet,XValidation);validationError=平均值(YValPred~=YValidation);YTrainPred=分类(trainedNet,XTrain);trainError=平均值(YTrainPred~=YTrain);disp(“训练误差:+ trainError * 100 +"%")disp(“验证错误:”+验证错误*100+"%")
培训误差:1.907%验证误差:5.5376%

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

身材(“单位”,“正常化”,“位置”,[0.20.20.50.5]);厘米=混淆图(YValidation,YValPred);厘米标题=“验证数据的混淆矩阵”; cm.摘要=“列规格化”;cm.概述=“row-normalized”; SortClass(cm,[命令,“未知”,“背景”])

当对具有诸如移动应用的受限硬件资源的应用程序工作时,考虑可用内存和计算资源的限制。使用千兆字节计算网络的总大小,并在使用CPU时测试其预测速度。预测时间是对单个输入图像进行分类的时间。如果输入,如果将多个图像传输到网络,则可以同时对这些图像进行分类,从而缩短每个图像的预测时间。但是,在对流媒体音频进行分类时,单个图像的预测时间是最相关的。

信息=谁(“训练网”); disp(“网络大小:”+info.bytes/1024+“kB”)对于i = 1:100 x = randn([numHops,numBands]);tic [YPredicted,probs] = classification(训练网,x,“执行环境”,“cpu”);时间(i)=总有机碳;结束disp (“CPU上的单映像预测时间:”+平均值(时间(11:end))*1000+“ms”)
网络大小:286.7402 kB CPU上的单映像预测时间:2.5119毫秒

工具书类

[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

工具书类

[1] Warden 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

另见

||

相关的话题