主要内容

用深度学习训练语音指令识别模型

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

要使用预先训练的语音命令识别系统,请参见基于深度学习的语音指令识别

要快速运行示例,请设置speedupExample真正的.要运行已发布的完整示例,请设置speedupExample

speedupExample =

为再现性设置随机种子。

rng默认的

加载数据

本示例使用谷歌语音命令数据集[1].下载并解压缩数据集。

downloadFolder = matlab.internal.examples.downloadSupportFile (“音频”,“google_speech.zip”);dataFolder = tempdir;unzip(downloadFolder,dataFolder) dataset = fullfile(dataFolder,“google_speech”);

增加的数据

该网络不仅应该能够识别不同的口语,还应该能够检测音频输入是否为静音或背景噪音。

支持函数,augmentDataset,使用谷歌语音命令数据集的背景文件夹中的长音频文件创建一秒段的背景噪声。该函数从每个背景噪声文件中创建相同数量的背景段,然后在train和验证文件夹之间分割这些段。

augmentDataset(数据集)
Progress = 17 (%) Progress = 33 (%) Progress = 50 (%) Progress = 67 (%) Progress = 83 (%) Progress = 100 (%)

创建培训数据存储

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

广告= audioDatastore (fullfile(数据集,“训练”),...IncludeSubfolders = true,...FileExtensions =“wav”,...LabelSource =“foldernames”);

指定希望模型识别为命令的单词。将所有不是命令或背景噪声的文件标记为未知的.将不是命令的词标记为未知的创建一组词,该组词近似于除命令之外的所有词的分布。网络使用这个组来学习命令和所有其他单词之间的区别。

为了减少已知词和未知词之间的类不平衡,加快处理速度,在训练集中只包含一小部分未知词。

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

命令=分类([“是的”,“不”,《飞屋环游记》,“向下”,“左”,“正确”,“上”,“关闭”,“停止”,“走”]);背景=分类(“背景”);isCommand = ismember (ads.Labels、命令);isBackground = ismember (ads.Labels、背景);isUnknown = ~ (isCommand | isBackground);includeFraction = 0.2;%要包含的未知数的百分比。idx =找到(isUnknown);idx = idx (randperm(元素个数(idx)轮((1-includeFraction) * sum (isUnknown))));isUnknown (idx) = false;ads.Labels (isUnknown) =分类(“未知”);adsTrain =子集(广告,isCommand | isUnknown | isBackground);adsTrain。标签= removecats (adsTrain.Labels);

创建验证数据存储

创建一个audioDatastore这指向验证数据集。遵循与创建培训数据存储相同的步骤。

广告= audioDatastore (fullfile(数据集,“确认”),...IncludeSubfolders = true,...FileExtensions =“wav”,...LabelSource =“foldernames”);isCommand = ismember (ads.Labels、命令);isBackground = ismember (ads.Labels、背景);isUnknown = ~ (isCommand | isBackground);includeFraction = 0.2;%要包含的未知数的百分比。idx =找到(isUnknown);idx = idx (randperm(元素个数(idx)轮((1-includeFraction) * sum (isUnknown))));isUnknown (idx) = false;ads.Labels (isUnknown) =分类(“未知”);adsValidation =子集(广告,isCommand | isUnknown | isBackground);adsValidation。标签= removecats (adsValidation.Labels);

可视化培训和验证标签的分布。

图(单位=“归一化”,Position=[0.2,0.2,0.5,0.5]) tiledlayout(2,1) nexttile直方图(adsTrain.Labels) title(“培训标签分配”) ylabel (“观察”网格)nexttile直方图(adsValidation.Labels)标题(“验证标签分配”) ylabel (“观察”网格)

如果需要,可以通过减少数据集来加快示例的速度。

如果speedupExample numUniqueLabels = numel(unique(adsTrain.Labels));% #好< UNRCH >将数据集减少20倍adsTrain = splitEachLabel(adsTrain,round(numel(adsTrain. files) / numUniqueLabels / 20));adsValidation = splitEachLabel(adsValidation,round(numel(adsValidation. files) / numUniqueLabels / 20));结束

为培训准备数据

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

为了加快处理速度,您可以跨多个工作者分配特征提取。如果可以访问并行计算工具箱™,则启动并行池。

如果canUseParallelPool && ~speedupExample useParallel = true;gcp;其他的useParallel = false;结束
使用“本地”配置文件启动并行池(parpool)…连接到并行池(工作人员数量:6)。

提取的特征

定义从音频输入中提取听觉谱图的参数。segmentDuration是每个语音片段的持续时间,以秒为单位。frameDuration是用于频谱计算的每一帧的持续时间。hopDuration是每个频谱之间的时间步长。numBands是听觉谱图中滤波器的数量。

fs = 16 e3;%数据集的已知采样率。segmentDuration = 1;frameDuration = 0.025;hopDuration = 0.010;FFTLength = 512;numBands = 50;segmentSamples =圆(segmentDuration * fs);frameSamples =圆(frameDuration * fs);hopSamples =圆(hopDuration * fs);overlapSamples = frameSamples - hopSamples;

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

afe = audioFeatureExtractor (...SampleRate = fs,...FFTLength = FFTLength,...窗口=损害(frameSamples,“周期”),...OverlapLength = overlapSamples,...barkSpectrum = true);setExtractorParameters (afe“barkSpectrum”NumBands = NumBands WindowNormalization = false);

定义一系列变换audioDatastore要将音频填充到一致的长度,提取特征,然后应用对数。

transform1 =变换(adsTrain @ (x)[0(地板((segmentSamples-size (x, 1)) / 2), 1); x; 0(装天花板((segmentSamples-size (x, 1)) / 2), 1)));transform2 =变换(transform1, @ (x)提取(afe x));transform3 =变换(transform2 @ (x) {log10 (x + 1 e-6)});

使用readall函数从数据存储中读取所有数据。当读取每个文件时,在返回数据之前,它将通过转换进行传递。

XTrain = readall (transform3 UseParallel = UseParallel);

输出是numFiles1单元阵列。细胞阵列的每个元素都对应于从文件中提取的听觉谱图。

numFiles =元素个数(XTrain)
numFiles = 28463
[numHops, numBands numChannels] =大小(XTrain {1})
numHops = 98
numBands = 50
numChannels = 1

将细胞阵列转换为具有沿四维听觉谱图的四维阵列。

XTrain =猫(4,XTrain {:});[numHops, numBands numChannels numFiles] =大小(XTrain)
numHops = 98
numBands = 50
numChannels = 1
numFiles = 28463

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

transform1 =变换(adsValidation @ (x)[0(地板((segmentSamples-size (x, 1)) / 2), 1); x; 0(装天花板((segmentSamples-size (x, 1)) / 2), 1)));transform2 =变换(transform1, @ (x)提取(afe x));transform3 =变换(transform2 @ (x) {log10 (x + 1 e-6)});XValidation = readall (transform3 UseParallel = UseParallel);XValidation =猫(4,XValidation {:});

为了方便起见,分离训练和验证目标标签。

TTrain = adsTrain.Labels;TValidation = adsValidation.Labels;

可视化数据

绘制一些训练样本的波形和听觉谱图。播放相应的音频片段。

specMin = min (XTrain [],“所有”);specMax = max (XTrain [],“所有”);idx = randperm(元素个数(adsTrain.Files), 3);图(单位=“归一化”位置= (0.2,0.2,0.6,0.6));tiledlayout(2、3)ii = 1:3 [x,fs] = audioread(adsTrain.Files{idx(ii)});nexttile (ii)情节(x)轴title(string(adsTrain.Labels(idx(ii)))) nexttile(ii+3)) spect = XTrain(:,:,1,idx(ii)))';pcolor(spect) clim([specMin specMax])着色声音(x, fs)暂停(2)结束

定义网络体系结构

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

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

为了使每个类的总损失权重相等,可以使用与每个类的训练示例数量成反比的类权重。使用Adam优化器训练网络时,训练算法独立于类权值的整体归一化。

类=类别(TTrain);classWeights = 1. / countcats (TTrain);classWeights = classWeights ' /意味着(classWeights);numClasses =元素个数(类);timePoolSize =装天花板(numHops / 8);dropoutProb = 0.2;numF = 12;layers = [imageInputLayer([numHops,afe.FeatureVectorLength]) convolution2dLayer(3,numF,Padding= .“相同”maxPooling2dLayer(3,Stride=2,Padding= .“相同”) convolution2dLayer (3 2 * numF填充=“相同”maxPooling2dLayer(3,Stride=2,Padding= .“相同”) convolution2dLayer(3、4 * numF填充=“相同”maxPooling2dLayer(3,Stride=2,Padding= .“相同”) convolution2dLayer(3、4 * numF填充=“相同”) batchNormalizationLayer reluLayer convolution2dLayer(3,4*numF,Padding= .“相同”) batchNormalizationLayer reluLayer maxPooling2dLayer([timePoolSize,1]) dropoutLayer(dropoutProb) fullyConnectedLayer(numClasses) softmaxLayer classificationLayer(Classes= Classes,ClassWeights= ClassWeights)];

指定培训选项

要定义训练参数,请使用trainingOptions(深度学习工具箱).使用小型批处理大小为128的Adam优化器。

miniBatchSize = 128;validationFrequency =地板(元素个数(TTrain) / miniBatchSize);选择= trainingOptions (“亚当”,...InitialLearnRate = 3的军医,...MaxEpochs = 15,...MiniBatchSize = MiniBatchSize,...洗牌=“every-epoch”,...情节=“训练进步”,...Verbose = false,...ValidationData = {XValidation, TValidation},...ValidationFrequency = ValidationFrequency);

列车网络的

要训练网络,使用trainNetwork(深度学习工具箱).如果您没有GPU,那么训练网络可能需要时间。

trainedNet = trainNetwork (XTrain、TTrain层,选择);

评估培训网络

要计算网络在训练集和验证集上的最终准确性,请使用分类(深度学习工具箱).网络对这个数据集非常准确。然而,训练、验证和测试数据都具有类似的分布,不一定反映真实环境。这个限制特别适用于未知的类别,它只包含少量单词的发音。

YValidation =分类(trainedNet XValidation);validationError = mean(YValidation ~= TValidation);YTrain =分类(trainedNet XTrain);trainError = mean(YTrain ~= TTrain);disp ([“训练误差:+ trainError * 100 +“%”"验证错误:"+ validationError * 100 +“%”])
“训练误差:2.7263%”“验证误差:6.3968%”

若要绘制验证集的混淆矩阵,请使用confusionchart(深度学习工具箱).通过使用列和行摘要显示每个类的精度和召回率。

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

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

ii = 1:100 x = randn([numHops,numBands]);predictionTimer =抽搐;(y,聚合氯化铝)= (trainedNet x, ExecutionEnvironment =进行分类“cpu”);(二)= toc (predictionTimer);结束disp ([“网络大小:”+谁(“trainedNet”).字节/ 1024 +“知识库”...CPU上的单图像预测时间:+的意思是(时间(11:结束))* 1000 +“女士”])
"网络大小:292.2842 kB" " CPU单图像预测时间:3.7237 ms"

支持功能

用背景噪声增强数据集

函数augmentDataset(datasetloc) adsBkg = audioDatastore(fullfile(datasetloc),“背景”));fs = 16 e3;%数据集的已知采样率segmentDuration = 1;segmentSamples =圆(segmentDuration * fs);volumeRange = log10([1的军医,1]);numBkgSegments = 4000;numBkgFiles =元素个数(adsBkg.Files);numSegmentsPerFile =地板(numBkgSegments / numBkgFiles);fpTrain = fullfile (datasetloc,“训练”,“背景”);fpValidation = fullfile (datasetloc,“确认”,“背景”);如果~ datasetExists (fpTrain)%创建目录mkdir (fpTrain) mkdir (fpValidation)backgroundFileIndex = 1: numl (adsBkg. files) [bkgFile,fileInfo] = read(adsBkg);[~, fn] = fileparts (fileInfo.FileName);确定每个段的起始指数segmentStart =兰迪(大小(bkgFile, 1) -segmentSamples, numSegmentsPerFile, 1);确定每个剪辑的增益^((volumeRange(2)-volumeRange(1))*rand(numSegmentsPerFile,1) + volumeRange(1));segmentIdx = 1: numSegmentsPerFile隔离随机选择的数据段。bkgSegment = bkgFile (segmentStart (segmentIdx): segmentStart (segmentIdx) + segmentSamples-1);按指定增益缩放段。bkgSegment = bkgSegment *获得(segmentIdx);在-1和1之间剪辑音频。bkgSegment = max (min (bkgSegment, 1), 1);%创建文件名。Afn = fn +“_segment”+ segmentIdx +“wav”随机分配背景片段给火车或%验证集。如果兰德> 0.85指定15%用于验证dirToWriteTo = fpValidation;其他的将85%分配给训练集。dirToWriteTo = fpTrain;结束将音频写入文件位置。ffn = fullfile (dirToWriteTo afn);audiowrite (ffn bkgSegment fs)结束%打印进展流('进度= %d (%%)\n'而圆(100 *进展(adsBkg)))结束结束结束

参考文献

[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

Baidu
map