Генерация кода для сети LSTM на Raspberry Pi

В этом примере показано, как сгенерировать код для предварительно обученной сети долгой краткосрочной памяти (LSTM), которая использует ARM ® Compute Library и развертывает код на цели Raspberry Pi™. В этом примере сеть LSTM предсказывает оставшийся полезный срок службы (RUL) машины. Сеть принимает в качестве входных наборов данных временных рядов, которые представляют различные датчики в двигателе. Сеть возвращает Оставшийся Полезный Срок Работы двигателя, измеренный в циклах, в качестве своего выхода.

Этот пример использует набор данных моделирования деградации Engine Turbofan, как описано в [1]. Этот набор данных содержит 100 обучающих наблюдений и 100 тестовых наблюдений. Обучающие данные содержат моделируемые данные временных рядов для 100 двигателей. Каждая последовательность имеет 17 функции, изменяется в длине и соответствует полному запуску в отказ (RTF) образца. Эти тестовые данные содержат 100 частичных последовательности и соответствующие значения оставшегося полезного срока службы в конце каждой последовательности.

Этот пример использует предварительно обученную сеть LSTM. Для получения дополнительной информации о том, как обучить сеть LSTM, смотрите пример Классификация последовательности с использованием глубокого обучения.

Этот пример демонстрирует два различных подхода для выполнения предсказания с использованием сети LSTM:

  • Первый подход использует стандартную сеть LSTM и запускает вывод на наборе данных временных рядов.

  • Второй подход использует поведение той же LSTM-сети на основе состояний. В этом методе вы передаете один временной интервал данных за раз и получаете, чтобы сеть обновляла свое состояние на каждом временном шаге.

Этот пример использует рабочий процесс, основанный на PIL, чтобы сгенерировать MEX-функцию, которая, в свою очередь, вызывает исполняемый файл, сгенерированный на целевом компьютере из MATLAB.

Примечания:

  • Код, линии в этом примере, комментируется. Раскомментируйте их перед запуском примера.

  • Версия библиотеки ARM Compute, которую использует этот пример, может быть не последней версией, которая поддержки генерацию кода. Информацию о поддерживаемых версиях компиляторов и библиотек см. в разделе Оборудование и программное обеспечение сторонних производителей (MATLAB Coder).

  • Этот пример не поддерживается в MATLAB Online.

Необходимые условия

  • MATLAB ® Coder™

  • Embedded Coder ®

  • Deep Learning Toolbox™

  • Интерфейс MATLAB Coder для библиотек глубокого обучения. Для установки этого пакета поддержки используйте браузер Add-On Explorer.

  • Пакет поддержки MATLAB для оборудования Raspberry Pi. Для установки этого пакета поддержки используйте браузер Add-On Explorer.

  • Оборудование Raspberry Pi

  • ARM Compute Library (на целевом оборудовании ARM)

  • Переменные окружения для компиляторов и библиотек. Для настройки переменных окружений смотрите Окружение Переменные (MATLAB Coder).

Настройка объекта строения генерации кода для статической библиотеки

Чтобы сгенерировать функцию PIL MEX для указанной функции точки входа, создайте объект строения кода для статической библиотеки и установите режим верификации на 'PIL'. Установите целевой язык на C++.

% cfg = coder.config('lib', 'ecoder', true);
% cfg.VerificationMode = 'PIL';
% cfg.TargetLang = 'C++';

Настройте объект строения для генерации кода глубокого обучения

Создайте coder.ARMNEONConfig объект. Укажите версию вычислительной библиотеки. В данном примере предположим, что ARM Compute Library в оборудовании Raspberry Pi является версией 19.05.

% dlcfg = coder.DeepLearningConfig('arm-compute');
% dlcfg.ArmComputeVersion = '19.05';

Установите DeepLearningConfig свойство объекта строения генерации кода объекту строения глубокого обучения.

% cfg.DeepLearningConfig = dlcfg;

Создайте соединение с Raspberry Pi

Используйте функцию MATLAB Поддержки Package for Raspberry Pi Поддержки Package, raspi, для создания соединения с Raspberry Pi. В следующем коде замените:

  • raspiname с именем вашего Raspberry Pi

  • username с вашим именем пользователя

  • password с вашим паролем

% r = raspi('raspiname','username','password');

Сконфигурируйте аппаратные параметры генерации кода для Raspberry Pi

Создайте coder.Hardware объект для Raspberry Pi и присоедините его к объекту строения генерации кода.

% hw = coder.hardware('Raspberry Pi');
% cfg.Hardware = hw;

Первый подход: сгенерируйте MEX-функцию PIL для сети LSTM

В этом подходе вы генерируете код для функции точки входа rul_lstmnet_predict.

Функция точки входа rul_lstmnet_predict.m принимает весь набор данных временных рядов как вход и передает его в сеть для предсказания. В частности, функция использует сеть LSTM, которая обучена в примере Классификация последовательности с использованием глубокого обучения. Функция загружает сетевой объект из rul_lstmnet.mat файл в постоянную переменную и повторно использует этот постоянный объект в последующих вызовах предсказания. Сеть LSTM от последовательности к последовательности позволяет вам делать различные предсказания для каждого отдельного временного шага последовательности данных.

Чтобы отобразить интерактивную визуализацию сетевой архитектуры и информацию о слоях сети, используйте analyzeNetwork функция.

type('rul_lstmnet_predict.m')
function out =  rul_lstmnet_predict(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('rul_lstmnet.mat');
end


out = mynet.predict(in); 

Чтобы сгенерировать код при помощи codegen (MATLAB Coder), используйте coder.typeof (MATLAB Coder), чтобы задать тип и размер входного параметра для функции точки входа. В этом примере вход имеет двойной тип данных со значением размерности признаков 17 и длину переменной последовательности. Задайте длину последовательности как переменный размер, чтобы выполнить предсказание для входа последовательности любой длины.

% matrixInput = coder.typeof(double(0),[17 Inf],[false true]);

Запустите команду codegen, чтобы сгенерировать основанную на PIL MEX-функцию rul_lstmnet_predict_pil на хост-платформе.

% codegen -config cfg rul_lstmnet_predict -args {matrixInput} -report

Запуск сгенерированных PIL- MEX-функции на тестовых данных

Загрузите MAT-файл RULTestData. Этот MAT-файл хранит переменные XTest и YTest которые содержат выборочный timeseries датчика, на которых можно протестировать сгенерированный код. Эти тестовые данные взяты из примера Классификация последовательности с использованием глубокого обучения после предварительной обработки данных.

load RULTestData;

The XTest переменная содержит 100 входных наблюдений. Каждое наблюдение имеет 17 функции с различной длиной последовательности.

XTest(1:5)
ans=5×1 cell array
    {17×31  double}
    {17×49  double}
    {17×126 double}
    {17×106 double}
    {17×98  double}

The YTest переменная содержит 100 выходных наблюдений, которые соответствуют XTest входная переменная. Каждое выходное наблюдение является значением остаточного полезного срока службы (RUI), измеренным в циклах, для каждого временного шага данных в целом последовательности.

YTest(1:5)
ans=5×1 cell array
    {[                                                                                                                                                                                                                                                                                                                                                             142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112]}
    {[                                                                                                                                                                                                                                                                                       146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98]}
    {[150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69]}
    {[                                                                   150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82]}
    {[                                                                                          150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 150 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91]}

Запустите сгенерированную MEX-функцию rul_lstmnet_predict_pil на наборе случайных тестовых данных.

% idx = randperm(numel(XTest), 1);
% inputData = XTest{idx};

% YPred1 = rul_lstmnet_predict_pil(inputData);

Сравнение предсказаний с тестовыми данными

Используйте график, чтобы сравнить выходные данные MEX с тестовыми данными.

% figure('Name', 'Standard LSTM', 'NumberTitle', 'off');
%     
% plot(YTest{idx},'--')
% hold on
% plot(YPred1,'.-')
% hold off
% 
% ylim([0 175])
% title("Test Observation " + idx)
% xlabel("Time Step")
% ylabel("RUL measured in cycles")

Очистить PIL

% clear rul_lstmnet_predict_pil;

Второй подход: сгенерируйте MEX-функцию PIL для сети LSTM с учетом состояния

Вместо передачи всех данных timeseries сразу в predict, можно запустить предсказание путем потоковой передачи входных данных сегментно при помощи predictAndUpdateState функция.

Функция точки входа rul_lstmnet_predict_and_update.m принимает однократный вход и обрабатывает его при помощи predictAndUpdateState функция. predictAndUpdateState возвращает предсказание для входного временного интервала и обновляет сеть так, чтобы последующие части входа рассматривались как последующие временные интервалы той же выборки.

type('rul_lstmnet_predict_and_update.m')
function out = rul_lstmnet_predict_and_update(in) %#codegen

% Copyright 2019 The MathWorks, Inc. 

persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork('rul_lstmnet.mat');
end

[mynet, out] = predictAndUpdateState(mynet, in);

end

Создайте тип входа для codegen команда. Потому что rul_lstmnet_predict_and_update принимает отдельные данные временного интервала в каждом вызове, задает тип входа matrixInput иметь фиксированную длину последовательности 1 вместо переменной длины последовательности.

% matrixInput = coder.typeof(double(0),[17 1]);

Запуск codegen команда для генерации основанной на PIL MEX-функции rul_lstmnet_predict_and_update_pil на хост-платформе.

% codegen -config cfg rul_lstmnet_predict_and_update -args {matrixInput} -report

Запуск сгенерированных PIL- MEX-функции на тестовых данных

% Run generated MEX function(|rul_lstmnet_predict_and_update_pil|) for each
% time step data in the inputData sequence.

% sequenceLength = size(inputData,2);
% YPred2 = zeros(1, sequenceLength);
% for i=1:sequenceLength
%     inTimeStep = inputData(:,i);
%     YPred2(:, i) = rul_lstmnet_predict_and_update_pil(inTimeStep);
% end

После того, как вы передаете все временные интервалы, по одному, в rul_lstmnet_predict_and_update функция, результат выхода такой же, как в первом подходе, в котором вы прошли все входы сразу.

Сравнение предсказаний с тестовыми данными

Используйте график, чтобы сравнить выходные данные MEX с тестовыми данными.

% figure('Name', 'Statefull LSTM', 'NumberTitle', 'off');
% 
% 
% plot(YTest{idx},'--')
% hold on
% plot(YPred2,'.-')
% hold off
% 
% ylim([0 175])
% title("Test Observation " + idx)
% xlabel("Time Step")
% ylabel("RUL measured in cycles")

Очистить PIL

% clear rul_lstmnet_predict_and_update_pil;

Ссылки

[1] Саксена, Абхинав, Кай Гебель, Дон Симон и Нил Эклунд. Моделирование распространения повреждений для симуляции пробега двигателя самолета до отказа. В прогнозах и управлении здоровьем, 2008. PHM 2008. Международная конференция, стр. 1-9. IEEE, 2008.

См. также

| (MATLAB Coder) | (MATLAB Coder) | (MATLAB Coder)

Похожие темы