Сгенерируйте код для сети LSTM и развернитесь на цели Cortex-M

Этот пример демонстрирует, как сгенерировать код С с плавающей точкой для сети долгой краткосрочной памяти (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

Чтобы включить основанное на 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

Настройте последовательный коммуникационный интерфейс 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 CRL Cortex-M

Чтобы сгенерировать оптимальный код, используйте ARM Cortex-M (CMSIS) заменяющая библиотека кода.

cfg.CodeReplacementLibrary = 'ARM Cortex-M (CMSIS)';

Приблизьтесь 1: сгенерируйте исполняемый файл PIL, который принимает одно наблюдение за переменной длиной последовательности

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]);

Сгенерируйте исполняемый файл PIL

Запустите codegen команда, чтобы сгенерировать код и исполняемый файл PIL.

codegen -config cfg lstmNetwork_predict -args {matrixInput} -report

Запустите сгенерированный исполняемый файл PIL

Загрузите 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)

Приблизьтесь 2: сгенерируйте исполняемый файл PIL, который принимает несколько наблюдений за различными длинами последовательности

Если вы хотите выполнить предсказание на многих наблюдениях целиком, можно собрать в группу наблюдения в массиве ячеек и передать массив ячеек для предсказания. Массив ячеек должен быть массивом ячейки столбца, и каждая ячейка должна содержать одно наблюдение.

Каждое наблюдение должно иметь ту же размерность признаков, но их длины последовательности могут варьироваться.

Задайте входной тип и размер

В этом примере, XValidateData содержит четыре наблюдения. Сгенерировать MEX, который может принять XValidateData как вход, задайте входной тип, чтобы быть 4 1 массивом ячеек.

Далее, укажите, что каждая ячейка имеет тот же тип как matrixInput, тип вы задали для одного наблюдения в предыдущем |codegen | команда.

matrixInput = coder.typeof(single(0),[3 Inf],[false true]);
cellInput = coder.typeof({matrixInput}, [4 1]);

Сгенерируйте исполняемый файл PIL

Запустите codegen команда, чтобы сгенерировать код и исполняемый файл PIL.

codegen -config cfg lstmNetwork_predict -args {cellInput} -report

Запустите исполняемый файл PIL

Загрузите 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)

Приблизьтесь 3: сгенерируйте исполняемый файл PIL для LSTM с сохранением информации

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]);

Сгенерируйте исполняемый файл PIL

Запустите codegen команда, чтобы сгенерировать код и исполняемый файл PIL.

codegen -config cfg lstmNetwork_predict_and_update -args {matrixInput} -report

Запустите сгенерированный исполняемый файл PIL

Загрузите 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)

Смотрите также

| | | | | (Deep Learning Toolbox)

Похожие темы