В этом примере показано, как развернуть редукцию данных и сверточную нейронную сеть (CNN) для распознавания речевых команд в Raspberry Pi™. Чтобы сгенерировать редукцию данных и сетевой код, вы используете MATLAB Coder, MATLAB Support Package for Raspberry Pi Hardware и ARM ® Compute Library. В этом примере сгенерированный код является исполняемым файлом на вашем Raspberry Pi, который вызывается скриптом MATLAB, который отображает предсказанную речевую команду вместе с сигналом и слуховой спектрограммой. Взаимодействие между скриптом MATLAB и исполняемым файлом на вашем Raspberry Pi обрабатывается с помощью протокола пользовательской дейтаграммы (UDP). Для получения дополнительной информации о предварительной обработке аудио и сетевом обучении смотрите Распознание речевых команд с использованием глубокого обучения (Audio Toolbox).
Процессор ARM, поддерживающий расширение NEON
ARM Compute Library версии 19.05 (на целевом оборудовании ARM)
Переменные окружения для компиляторов и библиотек
Для поддерживаемых версий библиотек и для получения информации о настройке переменных окружения смотрите Необходимые условия для глубокого обучения с MATLAB Coder (MATLAB Coder).
Используйте те же параметры для конвейера редукции данных и классификации, что и в Распознание речевых команд с использованием глубокого обучения (Audio Toolbox).
Определите ту же частоту дискретизации, на которой обучалась сеть (16 кГц). Задайте частоту классификации и количество аудио выборок входа в систему координат. Функцией, входом к сети, является спектрограмма Bark, которая соответствует 1 секунде аудио данных. Спектрограмма Коры рассчитана для окон 25 мс с хмелем 10 мс. Вычислите количество отдельных спектров в каждой спектрограмме.
fs = 16000; classificationRate = 20; samplesPerCapture = fs/classificationRate; segmentDuration = 1; segmentSamples = round(segmentDuration*fs); frameDuration = 0.025; frameSamples = round(frameDuration*fs); hopDuration = 0.010; hopSamples = round(hopDuration*fs); numSpectrumPerSpectrogram = floor((segmentSamples-frameSamples)/hopSamples) + 1;
Создайте audioFeatureExtractor
(Audio Toolbox) объект для извлечения 50-диапазонных спектрограмм коры без нормализации окна. Вычислим количество элементов в каждой спектрограмме.
afe = audioFeatureExtractor( ... 'SampleRate',fs, ... 'FFTLength',512, ... 'Window',hann(frameSamples,'periodic'), ... 'OverlapLength',frameSamples - hopSamples, ... 'barkSpectrum',true); numBands = 50; setExtractorParams(afe,'barkSpectrum','NumBands',numBands,'WindowNormalization',false); numElementsPerSpectrogram = numSpectrumPerSpectrogram*numBands;
Загрузите предварительно обученные CNN и метки.
load('commandNet.mat') labels = trainedNet.Layers(end).Classes; NumLabels = numel(labels); BackGroundIdx = find(labels == 'background');
Задайте буферы и пороги принятия решений для постпроцессных предсказаний сети.
probBuffer = single(zeros([NumLabels,classificationRate/2])); YBuffer = single(NumLabels * ones(1, classificationRate/2)); countThreshold = ceil(classificationRate*0.2); probThreshold = single(0.7);
Создайте audioDeviceReader
(Audio Toolbox), чтобы считать аудио с вашего устройства. Создайте dsp.AsyncBuffer
(DSP System Toolbox) для буферизации звука в фрагменты.
adr = audioDeviceReader('SampleRate',fs,'SamplesPerFrame',samplesPerCapture,'OutputDataType','single'); audioBuffer = dsp.AsyncBuffer(fs);
Создайте dsp.MatrixViewer
(DSP System Toolbox) объект и timescope
(DSP System Toolbox) для отображения результатов.
matrixViewer = dsp.MatrixViewer("ColorBarLabel","Power per band (dB/Band)",... "XLabel","Frames",... "YLabel","Bark Bands", ... "Position",[400 100 600 250], ... "ColorLimits",[-4 2.6445], ... "AxisOrigin","Lower left corner", ... "Name","Speech Command Recognition using Deep Learning"); timeScope = timescope("SampleRate",fs, ... "YLimits",[-1 1], ... "Position",[400 380 600 250], ... "Name","Speech Command Recognition Using Deep Learning", ... "TimeSpanSource","Property", ... "TimeSpan",1, ... "BufferLength",fs, ... "YLabel","Amplitude", ... "ShowGrid",true);
Показать возможности времени и средство просмотра матриц. Обнаруживайте команды, пока открыты программа средства просмотра возможностей и матрицы или пока не достигнут предел времени. Чтобы остановить обнаружение в реальном времени до достижения предела времени, закройте окно временных возможностей или окно средства просмотра матрицы.
show(timeScope) show(matrixViewer) timeLimit = 10; tic while isVisible(timeScope) && isVisible(matrixViewer) && toc < timeLimit % Capture audio x = adr(); write(audioBuffer,x); y = read(audioBuffer,fs,fs-samplesPerCapture); % Compute auditory features features = extract(afe,y); auditoryFeatures = log10(features + 1e-6); % Perform prediction probs = predict(trainedNet, auditoryFeatures); [~, YPredicted] = max(probs); % Perform statistical post processing YBuffer = [YBuffer(2:end),YPredicted]; probBuffer = [probBuffer(:,2:end),probs(:)]; [YModeIdx, count] = mode(YBuffer); maxProb = max(probBuffer(YModeIdx,:)); if YModeIdx == single(BackGroundIdx) || single(count) < countThreshold || maxProb < probThreshold speechCommandIdx = BackGroundIdx; else speechCommandIdx = YModeIdx; end % Update plots matrixViewer(auditoryFeatures'); timeScope(x); if (speechCommandIdx == BackGroundIdx) timeScope.Title = ' '; else timeScope.Title = char(labels(speechCommandIdx)); end drawnow limitrate end
Скрыть возможности.
hide(matrixViewer) hide(timeScope)
Чтобы создать функцию для выполнения редукции данных, совместимых с генерацией кода, вызовите generateMATLABFunction
(Audio Toolbox) на audioFeatureExtractor
объект. The generateMATLABFunction
объект создаёт автономную функцию, которая выполняет эквивалентную редукцию данных и совместима с генерацией кода.
generateMATLABFunction(afe,'extractSpeechFeatures')
Вспомогательная функция HelperSpeechCommandRecognitionRasPi инкапсулирует редукцию данных и процесс сетевого предсказания, продемонстрированный ранее. Чтобы редукция данных была совместима с генерацией кода, редукция данных обрабатывается сгенерированным extractSpeechFeatures
функция. Чтобы сеть была совместима с генерацией кода, вспомогательная функция использует coder.loadDeepLearningNetwork
(MATLAB Coder) для загрузки сети. Вспомогательная функция использует dsp.UDPReceiver
(DSP System Toolbox) системный объект, чтобы послать слуховую спектрограмму и индекс, соответствующий предсказанной речевой команде от Raspberry Pi в MATLAB. Вспомогательная функция использует dsp.UDPReceiver
(DSP System Toolbox) системный объект для приема звука, захваченного микрофоном в MATLAB.
Замените hostIPAddress
с адресом вашей машины. Ваш Raspberry Pi отправляет слуховые спектрограммы и предсказанную речевую команду на этот IP-адрес.
hostIPAddress = coder.Constant('172.18.230.30');
Создайте объект строения генерации кода, чтобы сгенерировать исполняемую программу. Задайте целевой язык как C++.
cfg = coder.config('exe'); cfg.TargetLang = 'C++';
Создайте объект строения для генерации кода глубокого обучения с помощью вычислительной библиотеки ARM, которая находится на вашем Raspberry Pi. Задайте архитектуру Raspberry Pi и присоедините объект строения глубокого обучения к объекту строения генерации кода.
dlcfg = coder.DeepLearningConfig('arm-compute'); dlcfg.ArmArchitecture = 'armv7'; dlcfg.ArmComputeVersion = '19.05'; cfg.DeepLearningConfig = dlcfg;
Используйте функцию Raspberry Pi Support Package, raspi
, чтобы создать связь с вашим Raspberry Pi. В следующем коде замените:
raspiname
с именем вашего Raspberry Pi
pi с вашим именем пользователя
password
с вашим паролем
r = raspi('raspiname','pi','password');
Создайте coder.hardware
(MATLAB Coder) для Raspberry Pi и присоединить его к объекту строения генерации кода.
hw = coder.hardware('Raspberry Pi');
cfg.Hardware = hw;
Укажите папку сборки на Raspberry Pi.
buildDir = '~/remoteBuildDir';
cfg.Hardware.BuildDir = buildDir;
Используйте автоматически сгенерированный основной файл C++ для генерации независимого исполняемого файла.
cfg.GenerateExampleMain = 'GenerateCodeAndCompile';
Функции codegen
(MATLAB Coder), чтобы сгенерировать код С++ и исполняемый файл на вашем Raspberry Pi. По умолчанию имя приложения Raspberry Pi совпадает с именем функции MATLAB.
codegen -config cfg HelperSpeechCommandRecognitionRasPi -args {hostIPAddress} -report -v
Deploying code. This may take a few minutes. Location of the generated elf : /home/pi/remoteBuildDir/MATLAB_ws/R2020b/C/Users/sporwal/OneDrive_-_MathWorks/Documents/MATLAB/Examples/deeplearning_shared-ex00376115 ### Using toolchain: GNU GCC Raspberry Pi ### 'C:\Users\sporwal\OneDrive - MathWorks\Documents\MATLAB\Examples\deeplearning_shared-ex00376115\codegen\exe\HelperSpeechCommandRecognitionRasPi\HelperSpeechCommandRecognitionRasPi_rtw.mk' is up to date ### Building 'HelperSpeechCommandRecognitionRasPi': make -f HelperSpeechCommandRecognitionRasPi_rtw.mk all Warning: Function 'HelperSpeechCommandRecognitionRasPi' does not terminate due to an infinite loop. Warning in ==> HelperSpeechCommandRecognitionRasPi Line: 86 Column: 1 Code generation successful (with warnings): View report
Создайте команду, чтобы открыть HelperSpeechCommandRasPi
application on Raspberry Pi
. Использование system
отправить команду на свой Raspberry Pi.
applicationName = 'HelperSpeechCommandRecognitionRasPi'; applicationDirPaths = raspi.utils.getRemoteBuildDirectory('applicationName',applicationName); targetDirPath = applicationDirPaths{1}.directory; exeName = strcat(applicationName,'.elf'); command = ['cd ' targetDirPath '; ./' exeName ' &> 1 &']; system(r,command);
Создайте dsp.UDPReceiver
(DSP System Toolbox) системный объект для отправки аудио, захваченное в MATLAB, на ваш Raspberry Pi. Обновление targetIPAddress
для вашего малинового Пи. Raspberry Pi получает захваченное аудио от того же порта, используя dsp.UDPReceiver
(DSP System Toolbox) системный объект.
targetIPAddress = '172.18.228.24'; UDPSend = dsp.UDPSender('RemoteIPPort',26000,'RemoteIPAddress',targetIPAddress);
Создайте dsp.UDPReceiver
(DSP System Toolbox) системный объект для получения слуховых функций и прогнозируемого индекса команды речи от вашего Raspberry Pi. Каждый пакет UDP, полученный от Raspberry Pi, состоит из слуховых функций в основном порядке столбца и последующего индекса предсказанной речевой команды. Максимальная длина сообщения для dsp.UDPReceiver
объект составляет 65507 байт. Вычислите buffer size, чтобы вместить максимальное количество пакетов UDP.
sizeOfFloatInBytes = 4; maxUDPMessageLength = floor(65507/sizeOfFloatInBytes); samplesPerPacket = 1 + numElementsPerSpectrogram; numPackets = floor(maxUDPMessageLength/samplesPerPacket); bufferSize = numPackets*samplesPerPacket*sizeOfFloatInBytes; UDPReceive = dsp.UDPReceiver("LocalIPPort",21000, ... "MessageDataType","single", ... "MaximumMessageLength",samplesPerPacket, ... "ReceiveBufferSize",bufferSize);
Уменьшите накладные расходы на инициализацию, отправив систему координат с нулями в исполняемый файл, работающий на вашем Raspberry Pi.
UDPSend(zeros(samplesPerCapture,1,"single"));
Обнаруживайте команды, пока открыты программа средства просмотра возможностей и матрицы или пока не достигнут предел времени. Чтобы остановить обнаружение в реальном времени до достижения предела времени, закройте окно time scope или matrix viewer.
show(timeScope) show(matrixViewer) timeLimit = 20; tic while isVisible(timeScope) && isVisible(matrixViewer) && toc < timeLimit % Capture audio and send that to RasPi x = adr(); UDPSend(x); % Receive data packet from RasPi udpRec = UDPReceive(); if ~isempty(udpRec) % Extract predicted index, the last sample of received UDP packet speechCommandIdx = udpRec(end); % Extract auditory spectrogram spec = reshape(udpRec(1:numElementsPerSpectrogram), [numBands, numSpectrumPerSpectrogram]); % Display time domain signal and auditory spectrogram timeScope(x) matrixViewer(spec) if speechCommandIdx == BackGroundIdx timeScope.Title = ' '; else timeScope.Title = char(labels(speechCommandIdx)); end drawnow limitrate end end hide(matrixViewer) hide(timeScope)
Чтобы остановить исполняемый файл на Raspberry Pi, используйте stopExecutable
. Деблокируйте объекты UDP.
stopExecutable(codertarget.raspi.raspberrypi,exeName) release(UDPSend) release(UDPReceive)
Можно измерить время выполнения, занятое на Raspberry Pi, используя рабочий процесс PIL (процессор в цикле). Вспомогательная функция ProfileSpeechCommandRecognitionRaspi является эквивалентной функции HelperSpeechCommandRecognitionRaspi, за исключением того, что первая возвращает индекс речевой команды и слуховую спектрограмму, в то время как последняя отправляет те же параметры с помощью UDDP. Время, затраченное вызовами UDP, составляет менее 1 мс, что относительно мало по сравнению с общим временем выполнения.
Создайте объект строения PIL.
cfg = coder.config('lib','ecoder',true); cfg.VerificationMode = 'PIL';
Установите вычислительную библиотеку и архитектуру ARM.
dlcfg = coder.DeepLearningConfig('arm-compute'); cfg.DeepLearningConfig = dlcfg ; cfg.DeepLearningConfig.ArmArchitecture = 'armv7'; cfg.DeepLearningConfig.ArmComputeVersion = '19.05';
Настройте подключение к целевому компьютеру.
if (~exist('r','var')) r = raspi('raspiname','pi','password'); end hw = coder.hardware('Raspberry Pi'); cfg.Hardware = hw;
Установите директорию сборки и целевой язык.
buildDir = '~/remoteBuildDir'; cfg.Hardware.BuildDir = buildDir; cfg.TargetLang = 'C++';
Включите профилирование, а затем сгенерируйте код PIL. Файл MEX с именем ProfileSpeechCommandRecognition_pil
сгенерирован в текущей папке.
cfg.CodeExecutionProfiling = true; codegen -config cfg ProfileSpeechCommandRecognitionRaspi -args {rand(samplesPerCapture, 1, 'single')} -report -v
### Target device has no native communication support. Checking connectivity configuration registrations... Deploying code. This may take a few minutes. ### Target device has no native communication support. Checking connectivity configuration registrations... ### Connectivity configuration for function 'ProfileSpeechCommandRecognitionRaspi': 'Raspberry Pi' ### Using toolchain: GNU GCC Raspberry Pi ### Creating 'C:\Users\sporwal\OneDrive - MathWorks\Documents\MATLAB\Examples\deeplearning_shared-ex00376115\codegen\lib\ProfileSpeechCommandRecognitionRaspi\coderassumptions\lib\ProfileSpeechCommandRecognitionRaspi_ca.mk' ... ### Building 'ProfileSpeechCommandRecognitionRaspi_ca': make -f ProfileSpeechCommandRecognitionRaspi_ca.mk all ### Using toolchain: GNU GCC Raspberry Pi ### Creating 'C:\Users\sporwal\OneDrive - MathWorks\Documents\MATLAB\Examples\deeplearning_shared-ex00376115\codegen\lib\ProfileSpeechCommandRecognitionRaspi\pil\ProfileSpeechCommandRecognitionRaspi_rtw.mk' ... ### Building 'ProfileSpeechCommandRecognitionRaspi': make -f ProfileSpeechCommandRecognitionRaspi_rtw.mk all Location of the generated elf : /home/pi/remoteBuildDir/MATLAB_ws/R2020b/C/Users/sporwal/OneDrive_-_MathWorks/Documents/MATLAB/Examples/deeplearning_shared-ex00376115/codegen/lib/ProfileSpeechCommandRecognitionRaspi/pil ### Using toolchain: GNU GCC Raspberry Pi ### 'C:\Users\sporwal\OneDrive - MathWorks\Documents\MATLAB\Examples\deeplearning_shared-ex00376115\codegen\lib\ProfileSpeechCommandRecognitionRaspi\ProfileSpeechCommandRecognitionRaspi_rtw.mk' is up to date ### Building 'ProfileSpeechCommandRecognitionRaspi': make -f ProfileSpeechCommandRecognitionRaspi_rtw.mk all Code generation successful: View report
Вызовите сгенерированную функцию PIL несколько раз, чтобы получить среднее время выполнения.
testDur = 50e-3; numCalls = 100; for k = 1:numCalls x = pinknoise(fs*testDur,'single'); [speechCommandIdx, auditoryFeatures] = ProfileSpeechCommandRecognitionRaspi_pil(x); end
### Starting application: 'codegen\lib\ProfileSpeechCommandRecognitionRaspi\pil\ProfileSpeechCommandRecognitionRaspi.elf' To terminate execution: clear ProfileSpeechCommandRecognitionRaspi_pil ### Launching application ProfileSpeechCommandRecognitionRaspi.elf... Execution profiling data is available for viewing. Open Simulation Data Inspector. Execution profiling report available after termination.
Завершает выполнение PIL.
clear ProfileSpeechCommandRecognitionRaspi_pil
### Host application produced the following standard output (stdout) and standard error (stderr) messages: Execution profiling report: report(getCoderExecutionProfile('ProfileSpeechCommandRecognitionRaspi'))
Сгенерируйте отчет профиля выполнения для оценки времени выполнения.
executionProfile = getCoderExecutionProfile('ProfileSpeechCommandRecognitionRaspi'); report(executionProfile, ... 'Units','Seconds', ... 'ScaleFactor','1e-03', ... 'NumericFormat','%0.4f')
ans = 'C:\Users\sporwal\OneDrive - MathWorks\Documents\MATLAB\Examples\deeplearning_shared-ex00376115\codegen\lib\ProfileSpeechCommandRecognitionRaspi\html\orphaned\ExecutionProfiling_0d0860c73650e0a4.html'
Максимальное время выполнения, затраченное ProfileSpeechCommandRecognitionRaspi
функция почти в два раза превышает среднее время выполнения. Можно заметить, что время выполнения является максимальным для первого вызова функции PIL, и это связано с инициализацией, происходящей в первом вызове. Среднее время выполнения составляет приблизительно 20 мс, что ниже 50 мс бюджета (время захвата аудио). Эффективность измеряется на Raspberry Pi 4 Model B Rev 1.1.