Этот пример демонстрирует, как сгенерировать код С с плавающей точкой для сети долгой краткосрочной памяти (LSTM) от последовательности к последовательности. Вы генерируете приложение PIL, которое делает предсказания на каждом шаге входа timeseries.
Этот пример показывает три подхода для обработки переменных входных параметров длины последовательности к сети LSTM в сгенерированном коде. Для каждого подхода вы генерируете приложение PIL, которое выполняет одно из следующих действий:
Принимает одно наблюдение за переменной длиной последовательности
Принимает несколько наблюдений за переменными длинами последовательности
Усиливает поведение с сохранением информации сети LSTM, чтобы принять вход фиксированной длины последовательности
Этот пример использует данные о датчике акселерометра из смартфона, продолжил тело и делает предсказания на действии владельца.
Перемещения владельца классифицируются в одну из пяти категорий, а именно, танца, выполнения, нахождения, положения и обхода.
Для получения дополнительной информации об обучении сети смотрите, что Классификация Последовательностей Использует Глубокое обучение (Deep Learning Toolbox).
Когда вы генерируете и запускаете исполняемый файл PIL, сгенерированный код C работает на плате STMicroelectronics® STM32F746G-Discovery. Эта плата является базирующимся микроконтроллером ARM Cortex®-M7.
Можно также развернуть этот пример на других платах Открытия STMicroelectronics и платах STMicroelectronics Nucleo то использование процессоры ARM Cortex-M. Для развертывания на этих устройствах необходимо установить соответствующий пакет поддержки и связанные необходимые продукты, как описано в документации пакета поддержки.
Для развертывания на платах Открытия STMicroelectronics установите Пакет поддержки Embedded Coder для Советов Открытия STMicroelectronics.
Поддерживаемые платы Открытия STMicroelectronics:
STM32F746G-открытие
STM32F769I-открытие
STM32F4-открытие
Для развертывания на платах STMicroelectronics Nucleo установите Пакет поддержки Simulink Coder для Советов STMicroelectronics Nucleo.
Поддерживаемые платы STMicroelectronics Nucleo:
Nucleo-F401RE
Nucleo-F103RB
Nucleo-F302R8
Nucleo-F031K6
Nucleo-L476RG
Nucleo-L053R8
Nucleo-F746ZG
Nucleo-F411RE
Nucleo-F767ZI
Nucleo-H743ZI/Nucleo-H743ZI2
Плата STM32F746G-открытия
Тип A USB к кабелю Mini-B
Соедините аппаратную плату с хостом - компьютером при помощи типа A USB к кабелю Mini-B. Чтобы установить драйверы для платы, смотрите Драйверы Установки для Советов STMicroelectronics STM32 (Пакет поддержки Embedded Coder для Советов Открытия STMicroelectronics).
Создайте coder.EmbeddedCodeConfig
объект cfg
для генерации статической библиотеки.
cfg = coder.config('lib','ecoder',true);
Чтобы включить основанное на PIL выполнение, установите VerificationMode
к 'PIL'
.
cfg.VerificationMode = 'PIL';
Чтобы сгенерировать типовой код С, который не зависит от сторонних библиотек, устанавливает TargetLibrary
к 'none'
.
cfg.DeepLearningConfig = coder.DeepLearningConfig('TargetLibrary', 'none');
Чтобы задать целевой компьютер, создайте coder.Hardware
объект. Присвойте этот объект Hardware
свойство объекта cfg
.
cfg.Hardware = coder.hardware('STM32F746G-Discovery');
Настройте последовательный коммуникационный интерфейс PIL.
cfg.Hardware.PILInterface = 'Serial';
Чтобы определить COM-порт для последовательной передачи, следуйте за шагами 2 - 4 в Верификации кода и Валидации с PIL и Контроле и Настройке (Пакет поддержки Embedded Coder для Советов Открытия STMicroelectronics). Затем установите PILCOMPort
свойство.
cfg.Hardware.PILCOMPort = 'COM4';
Размер стека по умолчанию намного больше, чем память, доступная на оборудовании этот пример использование. Установите размер стека на меньшее значение, например, 512 байтов.
cfg.StackUsageMax = 512;
Чтобы просмотреть журнал сборки в командной строке, включите многословную сборку.
cfg.Verbose = 1;
Чтобы сгенерировать оптимальный код, используйте ARM Cortex-M (CMSIS) заменяющая библиотека кода.
cfg.CodeReplacementLibrary = 'ARM Cortex-M (CMSIS)';
lstmNetwork_predict
Функция точки входаЭта функция точки входа берет входную последовательность и передает ее обученной сети LSTM для предсказания. А именно, эта функция использует сеть LSTM, обученную в Последовательности в качестве примера к Классификации Последовательностей Используя пример Глубокого обучения.
Функция загружает сетевой объект от activityRecognitionNet.mat
файл в персистентную переменную. Функциональные повторные использования этот постоянный объект на последующих вызовах предсказания.
type('lstmNetwork_predict.m')
function out = lstmNetwork_predict(in) %#codegen % Copyright 2019-2021 The MathWorks, Inc. persistent mynet; if isempty(mynet) mynet = coder.loadDeepLearningNetwork('activityRecognitionNet.mat'); end % pass in input out = predict(mynet,in);
Задайте тип и размер входного параметра к codegen
команда при помощи coder.typeof
функция.
В данном примере вход имеет один тип данных со значением размерности признаков три и переменная длина последовательности.
При определении длины последовательности, когда переменный размер позволяет сгенерированному коду выполнить предсказание на входной последовательности любой длины.
matrixInput = coder.typeof(single(0),[3 Inf],[false true]);
Запустите codegen
команда, чтобы сгенерировать код и исполняемый файл PIL.
codegen -config cfg lstmNetwork_predict -args {matrixInput} -report
Загрузите MAT-файл XValidateData.mat
. Этот MAT-файл хранит переменную XValidateData
это содержит демонстрационный timeseries показаний датчика, на которых можно протестировать сгенерированный код. Кроме того, загрузите MAT-файл labelsActivity.mat
это содержит метки действия.
load XValidateData.mat load labelsActivity.mat
Вызовите lstmNetwork_predict_pil
на первом наблюдении, которое имеет длину последовательности шесть. Тот же исполняемый файл PIL может быть назван с помощью наблюдений за другими длинами последовательности также.
YPred1 = lstmNetwork_predict_pil(XValidateData{1});
Очистите исполняемый файл PIL.
clear lstmNetwork_predict_pil;
YPred1
5 6 числовая матрица, содержащая вероятности этих пяти классов для каждого из этих 6 временных шагов.
% For each time step, find the predicted class by calculating the index of the maximum probability value.
[~, maxIndex] = max(YPred1, [], 1);
Сопоставьте индекс максимального значения вероятности к соответствующей метке.
Отобразите связанные метки. От результатов вы видите, что сеть предсказала человеческое положение для первого наблюдения.
predictedLabels_1stObservation = labels(maxIndex); disp(predictedLabels_1stObservation)
Если вы хотите выполнить предсказание на многих наблюдениях целиком, можно собрать в группу наблюдения в массиве ячеек и передать массив ячеек для предсказания. Массив ячеек должен быть массивом ячейки столбца, и каждая ячейка должна содержать одно наблюдение.
Каждое наблюдение должно иметь ту же размерность признаков, но их длины последовательности могут варьироваться.
В этом примере, XValidateData
содержит четыре наблюдения. Сгенерировать MEX, который может принять XValidateData
как вход, задайте входной тип, чтобы быть 4 1 массивом ячеек.
Далее, укажите, что каждая ячейка имеет тот же тип как matrixInput
, тип вы задали для одного наблюдения в предыдущем |codegen | команда.
matrixInput = coder.typeof(single(0),[3 Inf],[false true]); cellInput = coder.typeof({matrixInput}, [4 1]);
Запустите codegen
команда, чтобы сгенерировать код и исполняемый файл PIL.
codegen -config cfg lstmNetwork_predict -args {cellInput} -report
Загрузите MAT-файл XValidateData.mat
. Этот MAT-файл хранит переменную XValidateData
это содержит демонстрационный timeseries показаний датчика, на которых можно протестировать сгенерированный код. Кроме того, загрузите MAT-файл labelsActivity.mat
это содержит метки действия.
load XValidateData.mat; load labelsActivity.mat;
Запустите исполняемый файл PIL для всех наблюдений.
YPred2 = lstmNetwork_predict_pil(XValidateData);
Очистите исполняемый файл PIL.
clear lstmNetwork_predict_pil;
Выход является 4 1 массивом ячеек предсказаний для этих четырех наблюдений, переданных lstmNetwork_predict_pil
.
disp(YPred2)
Отобразите связанные метки для первого наблюдения.
% For each time step, find the predicted class by calculating the index of the maximum probability.
[~, maxIndex] = max(YPred2{1}, [], 1);
predictedLabels_1stObservation = labels(maxIndex);
disp(predictedLabels_1stObservation)
lstmNetwork_predict_and_update
Функция точки входаВместо того, чтобы передать целый timeseries predict
за один шаг можно запустить предсказание на входе путем потоковой передачи в один такт за один раз при помощи predictAndUpdateState
(Deep Learning Toolbox) функция. Эта функция принимает вход, производит выходное предсказание и обновляет внутреннее состояние сети так, чтобы будущие предсказания приняли этот начальный вход во внимание. Используйте этот подход в ограниченном оборудовании ресурса, которое не имеет достаточной памяти, недостаточно, чтобы работать с целым timeseries.
Присоединенный lstmNetwork_predict_and_update
функция принимает вход одно такта и обрабатывает вход при помощи predictAndUpdateState
функция. Этот функциональные выходные параметры предсказание в течение входного такта и обновлений сеть так, чтобы последующие входные параметры были обработаны как последующие такты того же наблюдения. После передачи во все такты по одному, эквивалентен получившийся выход, если все такты были переданы в как один вход.
type('lstmNetwork_predict_and_update.m')
function out = lstmNetwork_predict_and_update(in) %#codegen % Copyright 2019-2021 The MathWorks, Inc. persistent mynet; if isempty(mynet) mynet = coder.loadDeepLearningNetwork('activityRecognitionNet.mat'); end % pass in input [mynet, out] = predictAndUpdateState(mynet,in);
Запускать codegen
команда на этом новом файле проекта, необходимо задать тип и размер входных параметров к функции точки входа. Поскольку каждый вызов lstmNetwork_predict_and_update
принимает один такт, задайте matrixInput
иметь фиксированную длину последовательности 1
вместо переменной длины последовательности.
matrixInput = coder.typeof(single(0),[3 1]);
Запустите codegen
команда, чтобы сгенерировать код и исполняемый файл PIL.
codegen -config cfg lstmNetwork_predict_and_update -args {matrixInput} -report
Загрузите MAT-файл XValidateData.mat
. Этот MAT-файл хранит переменную XValidateData
это содержит демонстрационный timeseries показаний датчика, на которых можно протестировать сгенерированный код. Кроме того, загрузите MAT-файл labelsActivity.mat
это содержит метки действия.
load XValidateData.mat; load labelsActivity.mat;
Получите продолжительность последовательности первого наблюдения.
sequenceLength = size(XValidateData{1} ,2);
Запустите сгенерированный исполняемый файл PIL на первом наблюдении выборки цикличным выполнением по каждому временному шагу.
for i = 1:sequenceLength % get each timestep data eachTimestepData = XValidateData{1}(:,i); YPredStateful(:,i) = lstmNetwork_predict_and_update_pil(eachTimestepData); end
Очистите сгенерированный исполняемый файл PIL после каждого наблюдения.
clear lstmNetwork_predict_and_update_pil; clear lstmNetwork_predict;
Сопоставьте индекс максимального значения вероятности к соответствующей метке.
[~, maxIndex] = max(YPredStateful, [], 1); predictedLabelsStateful = labels(maxIndex); disp(predictedLabelsStateful)
codegen
| coder.hardware
| coder.typeof
| coder.config
| coder.DeepLearningConfig
| predictAndUpdateState
(Deep Learning Toolbox)