Этот пример демонстрирует генерацию кода для определения ключевого слова с помощью сети Bidirectional Long Short-Term Memory (BiLSTM) и извлечения признаков частоты mel cepstral коэффициента (MFCC) на Raspberry Pi™. MATLAB® Coder™ с Поддержкой Глубокого обучения включает генерацию независимого исполняемого файла (.elf) файл на Raspberry Pi. Связь между MATLAB® (.mlx) файл и сгенерированным исполняемым файлом происходит по асинхронному Пользовательскому дейтаграммному протоколу (UDP). Входящий речевой сигнал отображен с помощью timescope
. Маска показывается синим прямоугольником, окружающим определенные экземпляры ключевого слова, YES. Для получения дополнительной информации об извлечении признаков MFCC и обучении нейронной сети для глубокого обучения, посетите Определение Ключевого слова в Шуме Используя MFCC и Сети LSTM.
MATLAB® Coder Interface для пакета поддержки глубокого обучения
Процессор ARM, который поддерживает расширение NEON
ARM Вычисляет версию 20.02.1 Библиотеки (на целевом оборудовании ARM)
Переменные окружения для компиляторов и библиотек
Для поддерживаемых версий библиотек и для получения информации о подготовке переменных окружения, смотрите Необходимые условия для Глубокого обучения для MATLAB Coder (MATLAB Coder).
Частотой дискретизации предварительно обученной сети является 16
kHz. Установите длину окна на 512
выборки, с длиной перекрытия 384
выборки и длина транзитного участка, заданная как различие между окном и длинами перекрытия. Задайте уровень, на котором оценивается маска. Маска сгенерирована однажды для каждого numHopsPerUpdate
аудио системы координат.
fs = 16e3; windowLength = 512; overlapLength = 384; hopLength = windowLength - overlapLength; numHopsPerUpdate = 16; maskLength = hopLength * numHopsPerUpdate;
Создайте audioFeatureExtractor
объект выполнить извлечение признаков MFCC.
afe = audioFeatureExtractor('SampleRate',fs, ... 'Window',hann(windowLength,'periodic'), ... 'OverlapLength',overlapLength, ... 'mfcc',true, ... 'mfccDelta',true, ... 'mfccDeltaDelta',true);
Загрузите и загрузите предварительно обученную сеть, а также среднее значение (M
) и стандартное отклонение (S
) векторы используются для стандартизации функции.
url = 'http://ssd.mathworks.com/supportfiles/audio/KeywordSpotting.zip'; downloadNetFolder = './'; netFolder = fullfile(downloadNetFolder,'KeywordSpotting'); if ~exist(netFolder,'dir') disp('Downloading pretrained network and audio files (4 files - 7 MB) ...') unzip(url,downloadNetFolder) end load(fullfile(netFolder,'KWSNet.mat'),"KWSNet","M","S");
Вызовите generateMATLABFunction
на audioFeatureExtractor
объект создать функцию извлечения признаков.
generateMATLABFunction(afe,'generateKeywordFeatures','IsStreaming',true);
Задайте Систему Читателя Аудио устройства object™, чтобы считать аудио из вашего микрофона. Установите длину системы координат, равную длине транзитного участка. Это включает расчет нового набора функций каждого нового аудио кадра, принятого от микрофона.
frameLength = hopLength; adr = audioDeviceReader('SampleRate',fs, ... 'SamplesPerFrame',frameLength,'OutputDataType','single');
Создайте Time Scope, чтобы визуализировать речевые сигналы и оцененную маску.
scope = timescope('SampleRate',fs, ... 'TimeSpanSource','property', ... 'TimeSpan',5, ... 'TimeSpanOverrunAction','Scroll', ... 'BufferLength',fs*5*2, ... 'ShowLegend',true, ... 'ChannelNames',{'Speech','Keyword Mask'}, ... 'YLimits',[-1.2 1.2], ... 'Title','Keyword Spotting');
Инициализируйте буфер для аудиоданных, буфер для вычисленных функций и буфер, чтобы построить входное аудио и выходную речевую маску.
dataBuff = dsp.AsyncBuffer(windowLength); featureBuff = dsp.AsyncBuffer(numHopsPerUpdate); plotBuff = dsp.AsyncBuffer(numHopsPerUpdate*windowLength);
Выполните определение ключевого слова о речи, полученной от вашего микрофона. Чтобы запустить цикл неопределенно, установите timeLimit
к Inf
. Чтобы остановить симуляцию, закройте scope
.
show(scope); timeLimit = 20; tic while toc < timeLimit && isVisible(scope) data = adr(); write(dataBuff,data); write(plotBuff,data); frame = read(dataBuff,windowLength,overlapLength); features = generateKeywordFeatures(frame,fs); write(featureBuff,features.'); if featureBuff.NumUnreadSamples == numHopsPerUpdate featureMatrix = read(featureBuff); featureMatrix(~isfinite(featureMatrix)) = 0; featureMatrix = (featureMatrix - M)./S; [keywordNet,v] = classifyAndUpdateState(KWSNet,featureMatrix.'); v = double(v) - 1; v = repmat(v,hopLength,1); v = v(:); v = mode(v); v = repmat(v,numHopsPerUpdate * hopLength,1); data = read(plotBuff); scope([data,v]); drawnow limitrate; end end hide(scope)
helperKeywordSpottingRaspi
поддерживание функции инкапсулирует извлечение признаков и сетевой процесс предсказания, продемонстрированный ранее. Чтобы сделать извлечение признаков совместимым с генерацией кода, извлечение признаков обработано сгенерированным generateKeywordFeatures
функция. Чтобы сделать сеть совместимой с генерацией кода, функция поддержки использует coder.loadDeepLearningNetwork
(MATLAB Coder) функция, чтобы загрузить сеть.
Функция поддержки использует dsp.UDPReceiver
Системный объект, чтобы получить записанное аудио от MATLAB® и использования dsp.UDPSender
Системный объект, чтобы отправить входную речь сигнализирует наряду с предполагаемой маской, предсказанной сетью к MATLAB®. Точно так же live скрипт MATLAB® использует dsp.UDPSender
Системный объект, чтобы отправить полученную речь сигнализирует к исполняемому файлу, работающему на Raspberry Pi и dsp.UDPReceiver
Системный объект, чтобы получить речь сигнализирует и оцененная маска от Raspberry Pi.
Замените 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 = '20.02.1'; cfg.DeepLearningConfig = dlcfg;
Используйте функцию Пакета поддержки Raspberry Pi, 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';
Сгенерируйте Код С++ для helperKeywordSpottingRaspi
на вашем Raspberry Pi.
codegen -config cfg helperKeywordSpottingRaspi -args {hostIPAddress} -report
Deploying code. This may take a few minutes. Warning: Function 'helperKeywordSpottingRaspi' does not terminate due to an infinite loop. Warning in ==> helperKeywordSpottingRaspi Line: 78 Column: 1 Code generation successful (with warnings): View report
Создайте команду, чтобы открыть helperKeywordSpottingRaspi
приложение на Raspberry Pi. Использование системы
отправить команду в ваш Raspberry Pi.
applicationName = 'helperKeywordSpottingRaspi'; applicationDirPaths = raspi.utils.getRemoteBuildDirectory('applicationName',applicationName); targetDirPath = applicationDirPaths{1}.directory; exeName = strcat(applicationName,'.elf'); command = ['cd ',targetDirPath,'; ./',exeName,' &> 1 &']; system(r,command);
Создайте dsp.UDPSender
Системный объект, чтобы отправить аудио, записанное в MATLAB® к вашему Raspberry Pi. Обновите targetIPAddress
для вашего Raspberry Pi. Raspberry Pi получает записанное аудио от того же порта с помощью dsp.UDPReceiver
Системный объект.
targetIPAddress = '172.18.240.234'; UDPSend = dsp.UDPSender('RemoteIPPort',26000,'RemoteIPAddress',targetIPAddress);
Создайте dsp.UDPReceiver
Системный объект, чтобы получить речевые данные и предсказанную речевую маску от вашего Raspberry Pi. Каждый пакет UDP, полученный от Raspberry Pi, состоит из maskLength
маска и речевые выборки. Максимальная длина сообщения для dsp.UDPReceiver
объектом является 65507
байты. Вычислите buffer size, чтобы вместить максимальное количество пакетов UDP.
sizeOfFloatInBytes = 4; speechDataLength = maskLength; numElementsPerUDPPacket = maskLength + speechDataLength; maxUDPMessageLength = floor(65507/sizeOfFloatInBytes); numPackets = floor(maxUDPMessageLength/numElementsPerUDPPacket); bufferSize = numPackets*numElementsPerUDPPacket*sizeOfFloatInBytes; UDPReceive = dsp.UDPReceiver("LocalIPPort",21000, ... "MessageDataType","single", ... "MaximumMessageLength",1+numElementsPerUDPPacket, ... "ReceiveBufferSize",bufferSize);
Определите ключевое слово, целый осциллограф времени открыт или пока ограничение по времени не достигнуто. Чтобы остановить живое обнаружение перед, ограничение по времени достигнуто, закройте осциллограф времени.
tic; show(scope); timelimit = 20; while toc < timelimit && isVisible(scope) x = adr(); UDPSend(x); data = UDPReceive(); if ~isempty(data) mask = data(1:maskLength); dataForPlot = data(maskLength + 1 : numElementsPerUDPPacket); scope([dataForPlot,mask]); end drawnow limitrate; end
Выпустите системные объекты и отключите независимый исполняемый файл.
hide(scope) release(UDPSend) release(UDPReceive) release(scope) release(adr) stopExecutable(codertarget.raspi.raspberrypi,exeName)
Чтобы оценить время выполнения, потраченное независимым исполняемым файлом на Raspberry Pi, используйте PIL (процессор в цикле) рабочий процесс. Чтобы выполнить профилирование PIL, сгенерируйте функцию PIL для функции поддержки profileKeywordSpotting
. profileKeywordSpotting
эквивалентно helperKeywordSpottingRaspi
, за исключением того, что первый возвращает речь и предсказанную речевую маску, в то время как последний отправляет те же параметры с помощью UDP. Время, потраченное вызовами 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 = '20.02.1';
Настройте связь со своим целевым компьютером.
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 под названием profileKeywordSpotting_pil
сгенерирован в вашей текущей папке.
cfg.CodeExecutionProfiling = true; codegen -config cfg profileKeywordSpotting -args {pinknoise(hopLength,1,'single')} -report
Deploying code. This may take a few minutes. ### Connectivity configuration for function 'profileKeywordSpotting': 'Raspberry Pi' Location of the generated elf : /home/pi/remoteBuildDir/MATLAB_ws/R2021a/E/sandbox/sporwal/Examples/ExampleManager/sporwal.Bdoc21a.j1572571/deeplearning_shared-ex18742368/codegen/lib/profileKeywordSpotting/pil Code generation successful: View report
Вызовите сгенерированную функцию PIL многократно, чтобы получить среднее время выполнения.
numPredictCalls = 10; totalCalls = numHopsPerUpdate * numPredictCalls; x = pinknoise(hopLength,1,'single'); for k = 1:totalCalls [maskReceived,inputSignal,plotFlag] = profileKeywordSpotting_pil(x); end
### Starting application: 'codegen\lib\profileKeywordSpotting\pil\profileKeywordSpotting.elf' To terminate execution: clear profileKeywordSpotting_pil ### Launching application profileKeywordSpotting.elf... Execution profiling data is available for viewing. Open Simulation Data Inspector. Execution profiling report available after termination.
Отключите выполнение PIL.
clear profileKeywordSpotting_pil
### Host application produced the following standard output (stdout) and standard error (stderr) messages: Execution profiling report: report(getCoderExecutionProfile('profileKeywordSpotting'))
Сгенерируйте профиль выполнения, сообщают, чтобы оценить время выполнения.
executionProfile = getCoderExecutionProfile('profileKeywordSpotting'); report(executionProfile, ... 'Units','Seconds', ... 'ScaleFactor','1e-03', ... 'NumericFormat','%0.4f')
ans = 'E:\sandbox\sporwal\Examples\ExampleManager\sporwal.Bdoc21a.j1572571\deeplearning_shared-ex18742368\codegen\lib\profileKeywordSpotting\html\orphaned\ExecutionProfiling_303d853869fa4b88.html'
Обработка первой системы координат взяла ~20 мс из-за накладных расходов инициализации. Скачки в графике времени в каждой 16-й системе координат (numHopsPerUpdate
) соответствуйте в вычислительном отношении интенсивный, предсказывают, что функция вызвала каждую 16-ю систему координат. Максимальное время выполнения составляет ~30 мс, который является ниже бюджета на 128 мс для потоковой передачи в реальном времени. Уровень измерен на версии Модели B Raspberry Pi 4 1.1.