主要内容

语音命令识别代码生成在树莓派

这个例子展示了如何将特征提取和卷积神经网络(CNN)部署到树莓派™上进行语音命令识别。要生成特征提取和网络代码,您可以使用MATLAB Coder™,MATLAB®支持包树莓派硬件和ARM®计算库。金宝app在本例中,生成的代码是树莓派上的可执行代码,它由MATLAB脚本调用,该脚本显示预测的语音命令以及信号和听觉谱图。MATLAB脚本和树莓派上的可执行文件之间的交互是使用用户数据报协议(UDP)处理的。有关音频预处理和网络训练的详细信息,请参见使用深度学习的语音命令识别

先决条件

  • 深度学习库的MATLAB编码器接口

  • 支持NEON扩展的ARM处理器金宝app

  • ARM计算库版本20.02.1(在目标ARM硬件上)

  • 编译器和库的环境变量

有关支持金宝app的库版本以及有关设置环境变量的信息,请参见与MATLAB编码器深度学习的先决条件(MATLAB编码器)

MATLAB中的流演示

中开发的特征提取管道和分类使用相同的参数使用深度学习的语音命令识别

定义与网络训练相同的采样率(16 kHz)。定义分类率和每帧输入的音频样本数量。输入到网络的特征是一个巴克谱图,对应于1秒的音频数据。Bark谱图计算了25 ms窗口和10 ms跳。计算每个谱图中单个谱的数目。

Fs = 16000;classificationRate = 20;samplesPerCapture = fs/ classiationrate;segmentDuration = 1;segmentSamples = round(segmentDuration*fs);frameDuration = 0.025;framessamples = round(frameDuration*fs);hopDuration = 0.010;hopSamples = round(hopDuration*fs);numSpectrumPerSpectrogram = floor((segmentsamples - framessamples)/hopSamples) + 1;

创建一个audioFeatureExtractor目的提取无窗归一化的50波段树皮谱图。计算每个谱图中元素的数量。

afe = audioFeatureExtractor(“SampleRate”fs,“FFTLength”, 512,“窗口”损害(frameSamples“周期”),“OverlapLength”, framessamples - hopSamples,“barkSpectrum”,真正的);numBands = 50;setExtractorParameters (afe“barkSpectrum”“NumBands”numBands,“WindowNormalization”、假);numElementsPerSpectrogram = numSpectrumPerSpectrogram*numBands;

加载预训练的CNN和标签。

负载(“commandNet.mat”) labels = trainedNet.Layers(end).Classes;NumLabels = nummel (labels);BackGroundIdx = find(label == .“背景”);

定义缓冲区和决策阈值以处理后网络预测。

probBuffer = single(0 ([NumLabels, classiationrate /2]));YBuffer = single(NumLabels * ones(1, classiationrate /2));countThreshold = ceil(classificationRate*0.2);probThreshold = single(0.7);

创建一个audioDeviceReader对象从设备读取音频。创建一个dsp。AsyncBuffer对象将音频缓冲成块。

adr = audioDeviceReader(“SampleRate”fs,“SamplesPerFrame”samplesPerCapture,“OutputDataType”“单一”);audioBuffer = dsp.AsyncBuffer(fs);

创建一个dsp。MatrixViewer对象和atimescope对象来显示结果。

matrixViewer = dsp。MatrixViewer (“ColorBarLabel”“每波段功率(分贝/波段)”“包含”“帧”“YLabel”“汪汪”乐队“位置”,[400 100 600 250],“ColorLimits”2.6445 [4],“AxisOrigin”“左下角”“名称”基于深度学习的语音命令识别);时间范围=时间范围“SampleRate”fs,“YLimits”[1],“位置”,[400 380 600 250],“名称”基于深度学习的语音命令识别“TimeSpanSource”“财产”“时间间隔”,1,“BufferLength”fs,“YLabel”“振幅”“ShowGrid”,真正的);

显示时间范围和矩阵查看器。只要时间范围和矩阵查看器都打开,或者直到达到时间限制,就检测命令。要在达到时间限制之前停止实时检测,请关闭时间范围窗口或矩阵查看器窗口。

show(timeScope) show(matrixViewer) timeLimit = 10;抽搐isVisible(timeScope) && isVisible(matrixViewer) && toc < timeLimit%捕获音频X = adr();写(audioBuffer x);y = read(audioBuffer,fs,fs- samplespercapture);%计算听觉特征feature = extract(afe,y);auditoryFeatures = log10(features + 1e-6);%执行预测probs = predict(trainedNet, auditoryFeatures);[~, ypredict] = max(probs);%执行统计后处理YBuffer = [YBuffer(2:end), ypredicting];probBuffer = [probBuffer(:,2:end),probs(:)];[YModeIdx, count] = mode(YBuffer);maxProb = max(probBuffer(YModeIdx,:));如果YModeIdx == single(BackGroundIdx) || single(count) < countThreshold || maxProb < probThreshold speechCommandIdx = BackGroundIdx;其他的speech commandix = YModeIdx;结束%更新图表matrixViewer (auditoryFeatures ');timeScope (x);如果(speechCommandIdx == BackGroundIdx)时间范围。Title =' ';其他的timeScope。Title =char(labels(speechCommandIdx));结束drawnowlimitrate结束

隐藏作用域。

隐藏(matrixViewer)隐藏(timeScope)

准备MATLAB代码用于部署

要创建一个函数来执行与代码生成兼容的特征提取,请调用generateMATLABFunctionaudioFeatureExtractor对象。的generateMATLABFunction对象函数创建一个独立的函数,该函数执行等效的特征提取,并与代码生成兼容。

generateMATLABFunction (afe“extractSpeechFeatures”

HelperSpeechCommandRecognitionRasPi金宝app支持函数封装了前面演示的特征提取和网络预测过程。使特征提取与代码生成兼容,特征提取由生成的代码处理extractSpeechFeatures函数。使网络兼容代码生成,支持功能采用金宝appcoder.loadDeepLearningNetwork(MATLAB编码器)加载网络的功能。支持函数金宝app使用adsp。UDPReceiver系统对象从树莓派发送听觉谱图和预测语音命令对应的索引到MATLAB。支持功能金宝app使用dsp。UDPReceiver系统对象来接收您的麦克风在MATLAB中捕获的音频。

在树莓派上生成可执行文件

取代hostIPAddress还有你的机器地址。您的树莓派发送听觉谱图和预测的语音命令到这个IP地址。

hostIPAddress = coder。常数(“172.18.230.30”);

创建代码生成配置对象以生成可执行程序。将目标语言指定为c++。

CFG = coder.config(exe”);cfg。TargetLang =“c++”;

用Raspberry Pi上的ARM计算库创建一个用于深度学习代码生成的配置对象。指定树莓派的架构,并将深度学习配置对象附加到代码生成配置对象。

DLCFG =编码器。DeepLearningConfig (“arm-compute”);dlcfg。ArmArchitecture =v7的;dlcfg。ArmComputeVersion =“20.02.1”;cfg。DeepLearningConfig = dlcfg;

使用树莓派支持包功能,金宝appraspi,创建与树莓派的连接。在下面的代码中,替换:

  • raspiname你的树莓派的名字

  • PI和您的用户名

  • 密码输入你的密码

R = raspi(“raspiname”“π”“密码”);

创建一个coder.hardware(MATLAB编码器)对象,并将其附加到代码生成配置对象。

Hw =编码器。硬件(“树莓π”);cfg。硬件= hw;

指定树莓派上的构建文件夹。

buildDir =“~ / remoteBuildDir”;cfg.Hardware.BuildDir = buildDir;

使用自动生成的c++主文件来生成独立的可执行文件。

cfg。GenerateExampleMain =“GenerateCodeAndCompile”;

调用codegen(MATLAB编码器)在树莓派上生成c++代码和可执行文件。默认情况下,树莓派应用程序名称与MATLAB函数名称相同。

codegen配置cfgHelperSpeechCommandRecognitionRasPiarg游戏{hostIPAddress}报告- v
部署代码。这可能需要几分钟。编译函数HelperSpeechCommandRecognitionRasPi…------------------------------------------------------------------------ 生成的精灵的位置:/home/pi/remoteBuildDir / MATLAB_ws / R2022a / W /交货/ ExampleManager / sporwal.Bdoc22a。###使用工具链:GNU GCC嵌入式Linux ### 'W:\Ex\ExampleManager\ sporwall . bdoc22 .j1844576\deeplearning_share -ex00376115\codegen\exe\HelperSpeechCommandRecognitionRasPi\HelperSpeechCommandRecognitionRasPi_rtw. jxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx00376115构建'HelperSpeechCommandRecognitionRasPi': make -j$(($(nproc)+1)) -Otarget -f HelperSpeechCommandRecognitionRasPi_rtw. mk'是最新的###可所有的  ------------------------------------------------------------------------ ### 生成编译报告……警告:函数'HelperSpeechCommandRecognitionRasPi'不会因无限循环而终止。Warning in ==> HelperSpeechCommandRecognitionRasPi Line: 86 Column: 1 Code generation successful (with warnings): View report

在树莓派上初始化应用程序

创建一个命令来打开HelperSpeechCommandRasPi应用程序在树莓派.使用系统发送命令到你的树莓派。

applicationName =“HelperSpeechCommandRecognitionRasPi”;applicationDirPaths = raspi.utils.getRemoteBuildDirectory(“applicationName”applicationName);targetDirPath = applicationDirPaths{1}.directory;exeName = strcat(applicationName,“.elf”);命令= [“cd”targetDirPath”;。/”exeName' &> 1 &'];系统(r,命令);

创建一个dsp。UDPReceiver系统对象发送在MATLAB中捕获的音频到您的树莓派。更新targetIPAddress你的树莓派。树莓派从同一端口接收捕获的音频dsp。UDPReceiver系统对象。

targetIPAddress =“172.18.231.92”;UDPSend = dsp。UDPSender (“RemoteIPPort”, 26000,“RemoteIPAddress”, targetIPAddress);

创建一个dsp。UDPReceiversystem对象来接收来自树莓派的听觉特征和预测的语音命令索引。从树莓派接收到的每个UDP数据包都包含以列为主顺序的听觉特征,然后是预测的语音命令索引。的最大消息长度dsp。UDPReceiver对象是65507字节。计算缓冲区大小以容纳UDP数据包的最大数量。

sizeOfFloatInBytes = 4;maxUDPMessageLength = floor(65507/sizeOfFloatInBytes);samplesPerPacket = 1 + numElementsPerSpectrogram;numPackets = floor(maxUDPMessageLength/samplesPerPacket);bufferSize = numPackets*samplesPerPacket*sizeOfFloatInBytes;udreceive = dsp。UDPReceiver (“LocalIPPort”, 21000,“MessageDataType”“单身”“MaximumMessageLength”samplesPerPacket,“下面的”bufferSize);

通过向树莓派上运行的可执行文件发送一帧零来减少初始化开销。

UDPSend (0 (samplesPerCapture 1“单身”));

使用部署代码执行语音命令识别

只要时间范围和矩阵查看器都打开,或者直到达到时间限制,就检测命令。要在达到时间限制之前停止实时检测,请关闭时间范围或矩阵查看器窗口。

show(timeScope) show(matrixViewer) timeLimit = 20;抽搐isVisible(timeScope) && isVisible(matrixViewer) && toc < timeLimit捕获音频并将其发送到RasPiX = adr();UDPSend (x);%从RasPi接收数据包udpRec = udreceive ();如果~ isempty (udpRec)提取预测索引,收到的UDP数据包的最后一个样本speechCommandIdx = udpRec(end);%提取听觉谱图spec =重塑(udpRec(1:numElementsPerSpectrogram), [numBands, numSpectrumPerSpectrogram]);显示时域信号和听觉谱图timeScope (x) matrixViewer(规范)如果speechCommandIdx == BackGroundIdx timeScope。Title =' ';其他的timeScope。Title =char(labels(speechCommandIdx));结束drawnowlimitrate结束结束隐藏(matrixViewer)隐藏(timeScope)

要停止树莓派上的可执行文件,使用stopExecutable.释放UDP对象。

stopExecutable(codertarget.raspi.raspberrypi,exeName) release(UDPSend) release(udreceive)

配置文件使用PIL工作流

您可以使用嵌入式编码器®的处理器在循环(PIL)工作流来测量树莓派上的执行时间。的ProfileSpeechCommandRecognitionRaspi金宝app支持函数相当于HelperSpeechCommandRecognitionRaspi函数,除了前者返回语音命令索引和听觉谱图,而后者使用UDP发送相同的参数。UDP调用所花费的时间小于1 ms,与总体执行时间相比,这是相对较小的。

创建一个PIL配置对象。

CFG = coder.config(“自由”“是”,真正的);cfg。VerificationMode =“公益诉讼”;

设置ARM计算库和体系结构。

DLCFG =编码器。DeepLearningConfig (“arm-compute”);cfg。DeepLearningConfig = dlcfg;cfg.DeepLearningConfig.ArmArchitecture =v7的;cfg.DeepLearningConfig.ArmComputeVersion =“19.05”;

建立与目标硬件的连接。

如果(~ (“r”“var”)) r = raspi(“raspiname”“π”“密码”);结束Hw =编码器。硬件(“树莓π”);cfg。硬件= hw;

设置构建目录和目标语言。

buildDir =“~ / remoteBuildDir”;cfg.Hardware.BuildDir = buildDir;cfg。TargetLang =“c++”;

启用分析,然后生成PIL代码。一个名为ProfileSpeechCommandRecognition_pil在当前文件夹中生成。

cfg。CodeExecutionProfiling = true;codegen配置cfgProfileSpeechCommandRecognitionRaspiarg游戏{rand(samplesPerCapture, 1, 'single')}报告- v
部署代码。这可能需要几分钟。编译函数ProfileSpeechCommandRecognitionRaspi…###连接配置功能'ProfileSpeechCommandRecognitionRaspi': '树莓派' ###使用工具链:GNU GCC嵌入式Linux ###创建'W:\Ex\ExampleManager\sporwal.Bdoc22a.j1844576\ deeplearning_share-ex00376115 \codegen\lib\ProfileSpeechCommandRecognitionRaspi\coderassumptions\lib\ProfileSpeechCommandRecognitionRaspi_ca. '可”……###构建'ProfileSpeechCommandRecognitionRaspi_ca': make -j$(($(nproc)+1)) -Otarget -f ProfileSpeechCommandRecognitionRaspi_ca。###使用工具链:GNU GCC嵌入式Linux ###创建“W:\Ex\ExampleManager\ sporwall . bdoc22 .j1844576\ deeplearning_share-ex00376115 \codegen\lib\ProfileSpeechCommandRecognitionRaspi\pil\ProfileSpeechCommandRecognitionRaspi_rtw。可”……###构建'ProfileSpeechCommandRecognitionRaspi': make -j$(($(nproc)+1)) -Otarget -f ProfileSpeechCommandRecognitionRaspi_rtw。生成精灵的位置:/home/pi/ remotebuilddir /MATLAB_ws/R2022a/W/Ex/ExampleManager/ sporwall . bdoc22a . mkallj1844576/ deeplearning_share-ex00376115 /codegen/lib/ProfileSpeechCommandRecognitionRaspi/pil ------------------------------------------------------------------------ ###使用工具链:GNU GCC嵌入式Linux ### W:\Ex\ExampleManager\sporwal.Bdoc22a.j1844576\ deeplearning_share-ex00376115 \codegen\lib\ProfileSpeechCommandRecognitionRaspi\ProfileSpeechCommandRecognitionRaspi_rtw。构建'ProfileSpeechCommandRecognitionRaspi': make -j$(($(nproc)+1)) -Otarget -f ProfileSpeechCommandRecognitionRaspi_rtw. mk'是最新的###可所有的  ------------------------------------------------------------------------ ### 生成编译报告……代码生成成功:查看报告

评估树莓派的执行时间

多次调用生成的PIL函数以获得平均执行时间。

testDur = 50e-3;numCalls = 100;k = 1:numCalls x = pinknoise(fs*testDur,“单一”);[speechcommandix, auditoryFeatures] = ProfileSpeechCommandRecognitionRaspi_pil(x);结束
###启动应用程序:'codegen\lib\ProfileSpeechCommandRecognitionRaspi\pil\ProfileSpeechCommandRecognitionRaspi。终止执行:clear ProfileSpeechCommandRecognitionRaspi_pil ###启动应用程序profilespeechcommandrecognitionraspi_elf…执行分析数据可供查看。打开模拟数据检查器。终止后可用的执行分析报告。

终止PIL执行。

清晰的ProfileSpeechCommandRecognitionRaspi_pil
主机应用程序产生以下标准输出(stdout)和标准错误(stderr)消息:执行分析报告:报告(getCoderExecutionProfile('ProfileSpeechCommandRecognitionRaspi'))

生成执行概要报告以评估执行时间。

executionProfile = getCoderExecutionProfile(“ProfileSpeechCommandRecognitionRaspi”);报告(executionProfile,“单位”“秒”“ScaleFactor”“1 e 03”“NumericFormat”' % 0.4 f '
ans = 'W:\Ex\ExampleManager\ sporwall . bdoc22 .j1844576\ deeplearning_share-ex00376115 \codegen\lib\ProfileSpeechCommandRecognitionRaspi\html\ orphailed \ExecutionProfiling_d82c7024f87064b9.html'

的最大执行时间ProfileSpeechCommandRecognitionRaspi函数的执行时间几乎是平均执行时间的两倍。您可以注意到,第一次调用PIL函数的执行时间最长,这是由于在第一次调用中进行了初始化。平均执行时间约为20毫秒,低于50毫秒的预算(音频捕获时间)。性能是在Raspberry Pi 4 Model B Rev 1.1上测量的。